排序的之插入排序
2011-11-19 19:40 java线程例子 阅读(188) 评论(0) 编辑 收藏 举报一、插入排序的主要分类:
1、直接插入排序;
2、折半插入排序;
3、2-路插入排序;
4、希尔排序(缩小增量排序)。
二、直接插入排序(简便,容易实现):
1、排序过程:整个排序过程为n-1趟插入,即先将序列中第1个元素看成是一个有序子序列,然后从第2个元素开始,逐个进行插入,直至整个序列有序。
2、算法实现:
void InsertSort(int a[], int len) { for (int i = 1; i < len; ++i) { int temp = a[i]; //先把将要插入的元素保存 int j = i; while (j > 0 && temp < a[j - 1])//通过while循环找出应该插入的位置 { a[j] = a[j - 1]; //后移 --j; } a[j] = temp; } }
3、算法评价:
(1) 时间复杂度
——若待排序元素按关键字从小到大排列(正序)
关键字比较次数:n-1元素移动次数:0
——若待排序元素按关键字从大到小排列(逆序)
关键字比较次数:n*(n-1)/2 注意:上面算法并没设置哨兵,若有设置,则比较次数应为(n+2)(n-1)/2
元素移动次数:n*(n-1)/2 注意:上面算法并没设置哨兵,若有设置,则移动次数应为(n+4)(n-1)/2
——若待排序元素是随机的,取平均值
关键字比较次数:(n+2)(n-1)/4
元素移动次数:n*(n-1)/4
故时间复杂度为:T(n)=O(n²)
(2)空间复杂度:S(n)=O(1)
4、适应范围:当序列中元素的个数n很少时。
三、折半插入排序(减少了元素的比较次数):
1、排序过程:用折半查找方法确定插入位置。
2、算法实现:
void binsort(int a[], int len) { for (int i = 1; i < len; ++i) { int temp = a[i]; int low = 0; int high = i - 1; //a[0]至a[i-1]的已经排序好了。 //执行while循环(折半查找)找出a[i]应该插入的位置 while (low <= high) { int middle = (low + high) / 2; if (temp < a[middle]) high = middle - 1; else low = middle + 1; } //a[low]至a[i-1]的元素移动到a[low+1]至a[i]; for (int j = i; j > low; --j) { a[j] = a[j - 1]; } a[low] = temp;//a[low]放置插入的元素 } }
3、算法评价:
本文若有错误或者不足之处,请您不吝指正。谢谢。
(1) 时间复杂度:
折半插入排序减少了关键字比较的次数,而元素的移动次数不变,故时间复杂度仍然为:T(n)=O(n²)
(2)空间复杂度:S(n)=O(1)
4、适应范围:当序列中元素的个数n很大时。
四、2-路插入排序(减少了元素的移动次数,但是增加了空间复杂度):
1、排序过程:引进一个空序列b。把原序列中的第一个元素a[0]看成是处于排好后的序列的中间。大于a[0]的元素放于a[0]值前的有序序列中,反之,放于其后。
如下图例子:
![](http://hi.csdn.net/attachment/201111/19/0_1321702565sEi2.gif)
2、算法实现:
void TowRsort(int a[], int len) { int *b = new int[len]; int current = len; //数组b后面序列中下标最小的一个 b[0] = a[0];//在b数组中放置第一个元素 int k = 0; for (int i = 1; i < len; ++i){ if (a[i] >= b[0]){ int k1 = k; //找出应该插入的位置 while (a[i] < b[k1]){ b[k1 + 1] = b[k1]; --k1; } b[k1 + 1] = a[i]; ++k; } else{ if (current == len)//放置第一个在数组最后 b[--current] = a[i]; else{ int tempCurrent = current; //找出应该插入的位置 while (b[tempCurrent] < a[i] && tempCurrent < len){ b[tempCurrent - 1] = b[tempCurrent]; ++tempCurrent; } b[tempCurrent - 1] = a[i]; --current; } } } int j = 0; for (int i = current; i < len; ++i, ++j){ a[j] = b[i]; } for (int i = 0; i < current; ++i, ++j){ a[j] = b[i]; } }
3、算法评价:
(1) 时间复杂度:时间复杂度仍然为:T(n)=O(n²)。(然而元素的移动次数约n*n/8)
(2)空间复杂度:S(n)=O(n)。
五、希尔插入排序(缩小增量法)(减少了元素的比较次数):
1、排序过程:分割成若干个较小的子文件,对各个子文件分别进行直接插入排序,当文件达到基本有序时,再对整个文件进行一次直接插入排序。
如下图例子:
![](http://hi.csdn.net/attachment/201111/19/0_13217012397eiV.gif)
2、算法实现:
void shellSort(int a[],const int& len){//希尔排序 int b[] = {5,3,1};//增量序列 int count = sizeof(b)/sizeof(int); for(int i = 0; i < count; ++i){ for(int j = 0; j < len - b[i]; ++j){ if(a[j] > a[j+b[i]]){ swap(a[j],a[j+b[i]]);//交换a[j]和a[j+b[i]]的值 int temp = j; while(temp >= b[i]){//向前想间隔b[i]的比较 if(a[temp] < a[temp-b[i]]){ swap(a[temp],a[temp-b[i]]);//交换 } else//只要有一个不满足,就跳出 break; temp -= b[i];//向前退 } } } } }
3、算法评价:
(1) 时间复杂度:在时间效率上较上述几种排序方法有较大的提高。时间复杂度效率介于O(n)与O(n*n)之间。
(2)空间复杂度:S(n)=O(1)。
4、补充说明:希尔排序的分析一个复杂的问题,因为它的时间复杂度与所取的增量序列有关,涉及到了数学上一些尚未解决的问题。因此到目前都没有人求出最好的增量序列。但是,应该使增量序列中没有除1外的公因子,并且最后一个增量值必须为1。
本文若有错误或者不足之处,请您不吝指正。谢谢。