<排序算法> 希尔排序ShellSort
1.核心思想:
希尔排序是插入排序的一种,是直接插入排序的一种改进版本,他们同属于插入排序类。
这是一个不稳定的排序算法。
采取跳跃分割的策略:将相距某个“增量”的记录组成一个子序列,这样才能保证在子序列内分别进行直接插入排序后得到的结果是基本有序而不是局部有序。
2.代码实现:
1 #include<iostream> 2 using namespace std; 3 4 void PrintArr(int arr[],int len); 5 void ShellSort(int arr[],int len) 6 { 7 if(arr == NULL || len <= 0) return ; 8 9 int gap = len/2; 10 int i = 0; //分组 11 int j; //每个组中的各个元素 12 13 while(gap >= 1) 14 { 15 //分组 16 for(i=0;i<gap;i++) 17 { 18 //每个组中进行插入排序 19 for(j=i+gap;j<len;j+=gap) 20 { 21 int yes = j-gap; //有序的就是这个组里面的第一个 22 int flag = arr[j]; //无序的第一个 23 while(flag < arr[yes] && yes >= i) 24 { 25 arr[yes+gap] = arr[yes]; 26 yes = yes-gap; 27 } 28 arr[yes+gap] = flag; 29 } 30 //PrintArr(arr,len); 31 } 32 gap = gap/2; 33 } 34 return ; 35 } 36 37 void PrintArr(int arr[],int len) 38 { 39 for(int i=0;i<len;i++) 40 cout << arr[i] << " "; 41 cout << endl; 42 43 return ; 44 } 45 46 int main() 47 { 48 //int arr[10] = {1,0,2,3,4,5,6,7,8,9}; 49 int arr[10] = {4,8,6,3,7,2,9,5,0,1}; 50 ShellSort(arr,sizeof(arr)/sizeof(arr[0])); 51 PrintArr(arr,sizeof(arr)/sizeof(arr[0])); 52 53 system("pause"); 54 return 0; 55 }
3.稳定性分析:
一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以希尔排序是不稳定的。
4.复杂度分析:
首先增量的选取是和时间复杂度有关系的。一般取为O(n^1.2~n^1.5),最差情况为O(n)。因此中等大小规模表现良好,对规模非常大的数据排序不是最优选择。但是比O(n)复杂度的算法快得多。
5.拓展:
此外,希尔算法在最坏的情况下和平均情况下执行效率相差不是很多,与此同时快速排序在最坏的情况下执行的效率会非常差。专家们提倡,几乎任何排序工作在开始时都可以用希尔排序,若在实际使用中证明它不够快,再改成快速排序这样更高级的排序算法。本质上讲,希尔排序算法是直接插入排序算法的一种改进,减少了其复制的次数,速度要快很多。 原因是,当n值很大时数据项每一趟排序需要移动的个数很少,但数据项的距离很长。当n值减小时每一趟需要移动的数据增多,此时已经接近于它们排序后的最终位置。 正是这两种情况的结合才使希尔排序效率比插入排序高很多。Shell算法的性能与所选取的分组长度序列有很大关系。只对特定的待排序记录序列,可以准确地估算关键词的比较次数和对象移动次数。