插入排序的改进算法-希尔排序
希尔排序(Shell's Sort)又称缩小增量排序,类属于插入排序。考虑到直接插入排序得一下特点:
(1)在待排序数基本有序情况下排序效率大大提高;
(2)在n很小时,其排序效率也很高。
基于以上考虑,对直接插入排序进行改进,并得出希尔排序。其基本思想为:先将整个待排序记录序列分割成若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序时”,再对全体记录进行一次插入排序。
这里的子序列是通过一个增量得到的,每一次赋予不同的增量,则得到不同的子序列组(分别对子序列进行直接插入排序就称作一次希尔插入排序,注意,实际代码中并不是依次排好一个自序列之后再排下一个这样效率低,而是依次扫描每一个子序列的元素即同时对各子序列排序)。这样将该增量逐渐递减为1便最终得到的子序列组就是其本身。
此时,问题的关键就在于增量序列delta[t]了,其个数和值都将影响排序效果。已有的结论为:当delta[k]=2t-k+1-1,1≤k≤t≤log2(n+1)时其时间复杂度为O(n3/2).另外增量序列还有其他各种取法。
另外,从排序过程可知,希尔排序是一种不稳定的排序算法。
对此,源码如下:
#include <iostream> #include <time.h> #include <math.h> #include <cstdlib> #include <fstream> #include <stdio.h> using namespace std; template <typename T> void shellInsert(T &L,int dk, int length) //对顺序表做一趟希尔排序,dk是增量值,length是待排序数组的元素个数 { int i=0,j=0; for (i = 1+dk; i <= length; ++i) if (L[i] < L[i-dk]) { L[0] = L[i]; //L[0]用来临时暂存 for (j = i-dk; j>0 && L[j]>L[0]; j -= dk) L[j+dk] = L[j]; L[j+dk] = L[0]; } } template <typename T> void shellSort(T &L, int dlta[], int t,int length) { for (int k = 0; k<t; ++k) { shellInsert(L,dlta[k],length); /*for (int i = 1; i<=length; ++i) cout << L[i] << ' '; cout << endl;*/ } } int main() { srand(time(NULL)); int n,n1,i=0; cout << "输入待排序数组的个数:"; cin >> n; int* a = new int[n]; //int* a = (int *) malloc(n*sizeof(int)); n1 = log(double(n))/log(2.0);//增量序列的大小 int* dlta = new int[n1]; //const size_t int_a_size = sizeof(a)/sizeof(a[0]); for (i = 0; i<n1; ++i) //生成增量序列 { dlta[i] = pow(2.0,n1-i)-1; cout << dlta[i] << ' '; } cout << endl; for (i = 1; i<n; ++i) //生成待排序数组 { a[i] = double(rand())/(RAND_MAX+1)*n; cout << a[i] << ' '; } cout << endl << endl; shellSort(a,dlta,n1,n-1); ofstream outs; outs.open("shellSort.txt"); for (i = 1; i<n; ++i) { outs << a[i] << ' '; if (0 == i%11) outs << endl; //cout << a[i] << ' '; } cout << endl; return 0; }