当前位置: 首页 > news >正文

希尔排序的增量和缩小增量问题

对于这个问题,我犹豫了很久。现在鼓起勇气来聊一聊。但是我仍然觉的自己会说不好。这里藏着一些令人惊讶的东西,一直沉睡在没有被注意的角落里。

现在不用y_tab解释器。直接用c 语言。

void shellsort(int a[], int n)
{int i,j,t, gap=n;for(gap/=2;gap>0;gap/=2) {printag(a, n, gap);for(i=gap; i<n; i++) {t =a[i];j=i-gap;while(j>=0) {if(a[j]>t) {a[j+gap]=a[j];}else {break;}j-=gap;}a[j+gap]=t;
if(i%gap==gap-1) printag(a, n, gap);}
if(i%gap!=0) printag(a, n, gap);printa(a,n);}
}

为了观察运行过程,插入了一些打印语句,printa()是打印数组。printag()是什么?

void printag(int a[], int n, int gap)
{int i=0;int g=0;if(gap<=1) return;printf("-:\n");while(i<n) {printf("%2d ", a[i++]);if(++g==gap) {printf("\n"); g=0;}}printf("-END\n");
}

每遇到一次gap输出一个换行符的printa()。

这样原来的数组,输出为n/gap行, gap列的矩阵。注意这个除法有余数。最后一行会有参差。

大家早已知晓,希尔排序最外层循环直接拿掉。里面出现gap的地方直接改为1,就变成了直接插入排序。执行的结果也得到一个正确排序的序列。那么,把流程故意弄复杂,的意图究竟是什么?

说复杂,是因为暂时还没有掌握正确读它的方法。等一会儿掌握了,就不再复杂,而是很清楚了。刚才说到printag(),把一个单行的数组输出为 gap列的矩阵。暂时忽略最后一行参差不齐的问题。

好了,矩阵有行向量,列向量两种分解的方法。现在按列向量来分。列向量是不是比原来的数组短?对含有gap个列向量的向量组逐个做排序会怎么样?这就是第2层循环
for(i=gap; i<n; i++) {…,这个循环所做的。想象一下,对每一个列向量都开一个直接插入排序“线程”,每个线程插入完一个数据,就轮换给下一个线程。这就是上面循环所做的事情。

然后增量"gap"要缩小一半。这是最外层的循环。也是说排序好的半gap相邻的列向量要镶嵌合并,变成长度增加一倍,数目减少一半的又一个矩阵。这个收缩是有限度的,"gap"缩到1就结束了。

而在这个镶嵌变化了的列向量上做排序是有特殊规律的。镶嵌排列的列向量有间隔的排序关系,再做一遍插入排序基本上都在就地重排意义上完成,而不能穿透。

这个最好直接看运行实例。下面给出16个数据的排序经过:
57 13 31 18 19 9 14 71 11 17 69 7 3 2 8 97 END
-:
57 13 31 18 19 9 14 71
11 17 69 7 3 2 8 97
-END
-:
11 13 31 7 3 2 8 71
57 17 69 18 19 9 14 97
-END
11 13 31 7 3 2 8 71 57 17 69 18 19 9 14 97 END
-:
11 13 31 7
3 2 8 71
57 17 69 18
19 9 14 97
-END
-:
3 2 8 7
11 13 31 71
57 17 69 18
19 9 14 97
-END
-:
3 2 8 7
11 13 31 18
57 17 69 71
19 9 14 97
-END
-:
3 2 8 7
11 9 14 18
19 13 31 71
57 17 69 97
-END
3 2 8 7 11 9 14 18 19 13 31 71 57 17 69 97 END
-:
3 2
8 7
11 9
14 18
19 13
31 71
57 17
69 97
-END
-:
3 2
8 7
11 9
14 18
19 13
31 71
57 17
69 97
-END
-:
3 2
8 7
11 9
14 18
19 13
31 71
57 17
69 97
-END
-:
3 2
8 7
11 9
14 18
19 13
31 71
57 17
69 97
-END
-:
3 2
8 7
11 9
14 13
19 18
31 71
57 17
69 97
-END
-:
3 2
8 7
11 9
14 13
19 18
31 71
57 17
69 97
-END
-:
3 2
8 7
11 9
14 13
19 17
31 18
57 71
69 97
-END
-:
3 2
8 7
11 9
14 13
19 17
31 18
57 71
69 97
-END
3 2 8 7 11 9 14 13 19 17 31 18 57 71 69 97 END
2 3 7 8 9 11 13 14 17 18 19 31 57 69 71 97 END

而列向量的观点,用c++来表达,就是:

void shellsort2(int a[], int n)
{class colvec {public:int *a;int n;int m;int col;public:colvec(int *arr, int len, int gap, int icol) {a=arr; n=len/gap +(len%gap>icol); m=gap; col=icol;}int & operator[](int i) { return a[m*i+col]; }int length() {return n;}};int i,j,t, gap=n;for(gap/=2;gap>0;gap/=2) {for(i=0; i<gap; i++) {colvec p(a, n, gap, i);int n = p.length();for(j=1; j<n; j++) {int k=j;t =p[k--];while(k>=0) {if(p[k]>t) {p[k+1]=p[k];}else {break;}k--;}p[k+1]=t;}}printa(a,n);}
}

class colvec代表列向量。这里清楚地看到,希尔排序内层一字不差的照搬了直接插入排序。


http://www.mrgr.cn/news/58739.html

相关文章:

  • C++ 中将 Lambda 作为参数传递给函数
  • 华为HCIE-OpenEuler认证详解
  • IMX6ULL裸机-ARM内部寄存器
  • 安装报错解决:No module named ‘quaternion‘
  • E. Sakurako, Kosuke, and the Permutation (置换环) Codeforces Round 981 (Div. 3)
  • 系统架构图设计(轻量级架构)
  • Vue 如何批量注册自定义指令
  • 欧拉函数(模板)
  • input子系统中读取流程解析
  • windows DLL技术-动态链接库搜索
  • LeetCode904.水果成篮
  • uniapp 发起post和get请求!uni.request(OBJECT)
  • Typora 、 Minio and PicGo 图床搭建
  • 【高级IO】IO多路转接之select
  • 代码随想录第九天|151.翻转字符串里的单词、卡码网:55.右旋转字符串、28. 实现 strStr() 、459.重复的子字符串
  • 《西安科技大学学报》
  • 我谈Canny算子
  • windows中git无法通过ssh连接github
  • 【Git】将本地代码提交到github仓库
  • electron 监听窗口高端变化
  • 基础知识总结-因果分析-dayone-辛普森悖论 因果关系
  • Spring Boot 中应用单元测试(UT):结合 Mock 和 H2 讲解和案例示范
  • Openlayers高级交互(8/20):选取feature,平移feature
  • Linux中安装配置SQLite3,并实现C语言与SQLite3的交互。
  • 活着就好20241026
  • Nature Communications|一种3D打印和激光诱导协同策略用于定制功能化器件(3D打印/激光直写/柔性电子/人机交互/柔性电路)