希尔排序(shell排序)的详细解说,对插入排序算法的改进
来源:互联网 发布:苏州淘宝拍摄 编辑:程序博客网 时间:2024/06/06 19:23
希尔排序是D.L.Shell于1959年提出来的一种排序算法,在这之前排序算法的时间复杂度基本都是O(n2)的,希尔排序算法是突破这个时间复杂度的第一批算法之一。插入排序的效率在某些时候是很高的,比如,记录本身就是基本有序的,只需要少量的插入操作,就可以完成整个记录集的排序工作,此时直接插入很高效。还有就是记录数比较少时,直接插入的优势也比较明显。可问题在于,两个条件本身就过于苛刻,现实中记录少或者基本有序都属于特殊情况。不过别急,有条件当然是好,条件不存在,我们创造条件,也是可以去做的。于是科学家希尔研究出了一种排序,对直接插入排序改进后可以增加效率的方法。如何让待排序的记录个数较少呢?很容易想到的就是将原本有大量记录数的记录进行分组。分割成若干个子序列,此时每个子序列待排序的记录个数就比较少了。然后在这些子序列内分别进行直接插入排序,当整个序列都基本有序时,注意只是基本有序时,再对全体记录进行一次直接插入排序。
算法描述
1)选定步长gap1(小于数据长度),按步长gap1将数据分成gap1组(按列分的)
2)所有距离为gap1倍数的数据放在同一组中
3)在各组中进行直接插入排序
4)重新取步长gap2(<gap1)重复上述的分组和排序,直到所取步长gapn=1,即所有数据
算法描述
1)选定步长gap1(小于数据长度),按步长gap1将数据分成gap1组(按列分的)
2)所有距离为gap1倍数的数据放在同一组中
3)在各组中进行直接插入排序
4)重新取步长gap2(<gap1)重复上述的分组和排序,直到所取步长gapn=1,即所有数据
放在同一组中进行直接插入排序为止。
在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按增量作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。由于Shell排序算法是按增量分组进行的排序,所以Shell排序算法是一种不稳定的排序算法。
关于插入排序的另一篇文章:
直接插入排序的C++实现及随机数组的产生方法
点击打开链接/******************************************************************希尔排序是D.L.Shell于1959年提出来的一种排序算法,在这之前排序算法的时间复杂度基本都是O(n2)的,希尔排序算法是突破这个时间复杂度的第一批算法之一。插入排序的效率在某些时候是很高的,比如,记录本身就是基本有序的,只需要少量的插入操作,就可以完成整个记录集的排序工作,此时直接插入很高效。还有就是记录数比较少时,直接插入的优势也比较明显。可问题在于,两个条件本身就过于苛刻,现实中记录少或者基本有序都属于特殊情况。不过别急,有条件当然是好,条件不存在,我们创造条件,也是可以去做的。于是科学家希尔研究出了一种排序,对直接插入排序改进后可以增加效率的方法。如何让待排序的记录个数较少呢?很容易想到的就是将原本有大量记录数的记录进行分组。分割成若干个子序列,此时每个子序列待排序的记录个数就比较少了。然后在这些子序列内分别进行直接插入排序,当整个序列都基本有序时,注意只是基本有序时,再对全体记录进行一次直接插入排序。 算法描述 1)选定步长gap1(小于数据长度),按步长gap1将数据分成gap1组(按列分的) 2)所有距离为gap1倍数的数据放在同一组中 3)在各组中进行直接插入排序 4)重新取步长gap2(<gap1)重复上述的分组和排序,直到所取步长gapn=1,即所有数据 放在同一组中进行直接插入排序为止。********************************************************************/#include <cmath>#include<cstdlib>#include<time.h>#include<cstdio>#include<iostream>#include <unistd.h> // Sleep函数using namespace std;//产生随机数组void Random(int a[],int n){ int i=0; srand( (unsigned)time( NULL ) ); while(i<n) { a[i++]=rand()/9999999; }}//print the arrayvoid print(int a[], int len){ int i; for (i = 0; i < len; i++) cout<<a[i]<<" "; cout<<endl;}void ShellSort_v1(int a[],int n){ int i,j; int increment=n; int temp; do { increment=increment/3+1; /* 增量序列 */ for(i=increment; i<n; i++) { if (a[i]<a[i-increment]) /* 需将a[i]插入有序增量子表 */ { temp=a[i]; /* 暂存在temp */ for(j=i-increment; j>=0 && temp<a[j]; j-=increment) //注意是j>=0 如果没有=则第一个数据不对 a[j+increment]=a[j]; /* 记录后移,查找插入位置 */ a[j+increment]=temp; /* 插入 */ } } } while(increment>1);}/**************************************************************************//和插入排序相比较void InsertSort(int a[], int n){ int i, j, temp; for (i = 1; i < n; i++) { temp = a[i];//这个是未排序数据的第一个,要把它插入到合适的位置 for (j = i-1; j >= 0 && temp < a[j]; j--)//a[j]是排序区的最后一个数据 a[j+1] = a[j];//a[j]是排序区的最后一个数据 //第一次循环式,a[j+1] 即a[i]的位置因为后移而被占据,但是他有备份 if(j!=(i-1)) 第i个数字比前面的都大,不需要重新插入 { a[j+1]=temp; } 当跳出循环时,说明temp >= a[j],循环体未执行,上一个循环的执行 结果是a[j+2] = a[j+1],a[j+1]位置已经空出,且a[j]<=temp<a[j+1] 为保持有序,a[j+1] = temp }}**************************************************************************//*和插入排序相比,只是步长不是1而是gap*/void ShellSort_v2(int *data, size_t size){ int temp,j=0; for (int gap = (size>>1); gap > 0; gap>>=1) /*最后一个循环的执行,gap==1*/ for (int i = gap; i < size; ++i) { temp = data[i]; // 参考插入排序 temp保存的是无序区的第一个数据 //初始化 /* 0=<j<=i-gap 表示有序区 j = i -gap j随着上层循环i的增加而增加*/ for( j = i -gap; j >= 0 && data[j] > temp; j -=gap)//从有序区里边找到找到待插入位置 //data[j] 是排序区的最后一个数据 { data[j+gap] = data[j];//数据依次后移,找到待插入位置 } if(j!=i -gap) //第i个数字比前面的都大,不需要重新插入,没有下边v3的效率不高 //应该是先判断,再移动 { data[j+gap] = temp; } }}void ShellSort_v3(int *data, size_t size){ int temp,j=0; for (int gap = (size>>1); gap > 0; gap>>=1) /*最后一个循环的执行,gap==1*/ for (int i = gap; i < size; ++i) { if(data[i]<data[i-gap]) //先判断是否需要插入,然后再寻找插入位置 { temp = data[i]; // 参考插入排序 temp保存的是无序区的第一个数据 /* 0=<j<=i-gap 表示有序区 j = i -gap j随着上层循环i的增加而增加*/ for( j = i -gap; j >= 0 && data[j] > temp; j -=gap)//从有序区里边找到找到待插入位置 //data[j] 是排序区的最后一个数据 { data[j+gap] = data[j];//数据依次后移,找到待插入位置 } data[j+gap] = temp; } }}void test1(){ int a[30] = {0}; Random(a,30); cout<<"-----------berore -----sort-------ShellSort_v1-------------"<<endl<<endl; print(a,30); //shellsort(a,30); ShellSort_v1(a,30); cout<<endl<<"------------after-------sort---------ShellSort_v1--------"<<endl; print(a,30);}void test2(){ int a[30] = {0}; Random(a,30); cout<<"-----------berore -----sort------ShellSort_v2--------------"<<endl<<endl; print(a,30); //shellsort(a,30); ShellSort_v2(a,30); cout<<endl<<"------------after-------sort---ShellSort_v2--------------"<<endl; print(a,30);}void test3(){ int a[30] = {0}; Random(a,30); cout<<"-----------berore -----sort------ShellSort_v3--------------"<<endl<<endl; print(a,30); //shellsort(a,30); ShellSort_v2(a,30); cout<<endl<<"------------after-------sort---ShellSort_v3--------------"<<endl; print(a,30);}int main(){ cout<<endl<<"=====================================test1============================"<<endl<<endl; test1(); sleep(1); //防止两次测试数据相同,时间种子的问题 cout<<endl<<"=====================================test2============================"<<endl<<endl; test2(); sleep(1); //防止两次测试数据相同,时间种子的问题 cout<<endl<<"=====================================test3============================"<<endl<<endl; test3();}/*************************************************=====================================test1============================-----------berore -----sort-------ShellSort_v1-------------206 157 192 37 29 167 44 200 107 49 140 21 167 1 94 70 195 51179 105 81 39 10 114 9 203 11 95 180 93------------after-------sort---------ShellSort_v1--------1 9 10 11 21 29 37 39 44 49 51 70 81 93 94 95 105 107 114 140 157 167 167 179 180 192 195 200 203 206=====================================test2============================-----------berore -----sort------ShellSort_v2--------------176 32 151 106 123 2 123 50 175 68 144 58 147 14 95 171 22 3115 35 100 107 57 199 169 96 62 35 97 60------------after-------sort---ShellSort_v2--------------2 3 14 22 32 35 35 50 57 58 60 62 68 95 96 97 100 106 107 115123 123 144 147 151 169 171 175 176 199=====================================test3============================-----------berore -----sort------ShellSort_v3--------------38 13 108 175 109 49 93 113 25 86 146 200 18 25 200 162 60 167 49 177 116 65 208 171 110 90 213 183 116 19------------after-------sort---ShellSort_v3--------------13 18 19 25 25 38 49 49 60 65 86 90 93 108 109 110 113 116 116 146 162 167 171 175 177 183 200 200 208 213Process returned 0 (0x0) execution time : 2.006 sPress ENTER to continue.***************************************************/
- 希尔排序(shell排序)的详细解说,对插入排序算法的改进
- 改进排序算法:希尔排序(对直接插入排序的改进)
- 插入排序的改进2:希尔排序
- 希尔排序(插入排序的改进)C++实现
- 算法<改进的冒泡排序、直接插入排序、折半插入排序、希尔排序、快速排序、归并排序>
- 希尔(Shell)排序——改良的插入排序算法
- 希尔(Shell)排序——改良的插入排序算法
- 希尔(shell)排序-插入排序的扩展
- 几种常见的排序算法(插入排序,希尔排序,归并排序和快速排序),算法分析以及改进
- 【排序算法 】希尔排序 shell sort(插入类排序)
- 改进的希尔排序
- shell(希尔)排序(改良的插入排序)
- 改进的插入排序算法
- 直接插入排序到希尔排序做的那些改进
- 常用的排序算法:插入排序,希尔排序,冒泡排序,选择排序,快速排序,归并排序
- 排序算法之希尔排序-优化后的插入排序
- 希尔排序(插入排序的改良)
- 常见比较排序算法的实现(归并排序、快速排序、堆排序、选择排序、插入排序、希尔排序)
- MySQL 运行状态及调优(二)
- 【Learning】适妞来学SA
- ADR的结构
- 金字塔 下面代码的目标是输出一个大写字母组成的金字塔。 其中space表示金字塔底距离左边的空白长度,x表示金字塔底的中心字母。
- Java和JSP几个常见问题
- 希尔排序(shell排序)的详细解说,对插入排序算法的改进
- hdu 2601 An easy problem
- Windows系统Vim编辑器乱码解决分析
- 《Expert MySQL》翻译——chapter2.解剖数据库系统(3)
- hdu1017
- 关于数字拼图
- 使用shell命令sed将指定目录下的所有文件中指定的字符串替换成指定的字符串
- hdu3046 最小割
- 花生壳域名转向设置