插入排序之2路插入排序及变种算法思考

  2-路插入排序算法是在折半插入排序的基础之上进行的改进,主要贡献是减少了排序过程中移动记录的次数,不足的地方是需要n个记录的辅助空间。

  具体算法思路如下:

    另设一个与含有n个数据的待排数据序列同类型的数组d,把待排序列的第一个元素(根据自己的数据结构来确定)赋值给d[0],并将d[0]看做是在排好序的序列的中间位置,然后将剩下的n-1个序列一次插入到d[0]之前或之后的有序数据序列(将数组d看做循环向量)中。

  相关变量定义如下:

View Code
1 #define MAXSIZE 20
2 typedef int KeyType;
3 typedef struct {
4     KeyType key;
5 }RedType;
6 typedef struct{
7     RedType r[MAXSIZE+1];
8     int length;
9 }Sqlist;

  2-路插入排序算法代码:

 1 /* 2 Path Insert Sort */ 
 2 void twoPathInsertSort(Sqlist &L){
 3     if(!L.length)
 4         return;
 5     KeyType d[MAXSIZE]={0};
 6     // 设置第一个记录和最后一个记录的指针 
 7     int first=0;
 8     int final=0;
 9     // 设置d[0]为哨兵元素 
10     d[0]=L.r[1].key;
11     int i;
12     for(i=2; i<= L.length; ++i){
13         if(LT(L.r[i].key,d[first])){  // 不需移动元素 
14             first = (first-1+L.length)%L.length;
15             d[first] = L.r[i].key ;
16         }else if(LT(d[final],L.r[i].key)){ // 不需要移动元素 
17             final = final+1 ;
18             d[final] = L.r[i].key;
19         }else {    // 中间插入,需要移动元素 
20             int j=final-1;
21             final += 1;
22             d[final] = d[final-1];
23             while(LT(L.r[i].key,d[j])){
24                 d[j+1] = d[j];
25                 --j;
26             }
27             d[j+1] = L.r[i].key;
28         }
29     }
30     // 将辅助数组的数据按序复制到表L 
31     for(i=1; i<= L.length; ++i){
32         L.r[i].key = d[first%L.length];
33         ++first;
34     }
35 }

  此算法相对折半插入算法来说,能减少移动记录的次数,但是不能绝对避免移动记录(除非是已排好序的数据序列),移动记录的次数约为N^2/8。根据由折半插入排序改进而来的2路插入排序,我不由自主的就想到了能不能来个2-路快速插入排序,即结合折半插入排序、快速排序优点的排序。

 1 void twoPQInsertSort(Sqlist &L){
 2     int i=1;
 3     int j=L.length;
 4     L.r[0].key = L.r[i].key;
 5     // Quick insert sort from two path 
 6     while(i<j){
 7         while(LE(L.r[0].key,L.r[j].key) && i<j){
 8             // Binary insert 
 9             int left=j+1;
10             int right=L.length;
11             while( left <= right ){
12                 int m = (left+right)/2 ;
13                 if(LT(L.r[j].key,L.r[m].key))
14                     right = m - 1;
15                 else
16                     left = m + 1;
17             }
18             KeyType tmp = L.r[j].key;
19             int tmpj;
20             for(tmpj=j; tmpj <= right-1; ++tmpj){
21                 L.r[tmpj].key = L.r[tmpj+1].key;
22             }
23             L.r[right].key = tmp;
24             --j;
25         }
26         L.r[i].key = L.r[j].key;
27         
28         while(LE(L.r[i].key,L.r[0].key) && i<j){
29             // Binary insert 
30             int left = 1;
31             int right = i-1;
32             while(left<=right){
33                 int m = (left+right)/2;
34                 if(LT(L.r[i].key,L.r[m].key))
35                     right = m - 1;
36                 else
37                     left = m + 1;
38             }
39             int tmpi;
40             int tmp = L.r[i].key;
41             for(tmpi=i-1; tmpi>= right+1; --tmpi){
42                 L.r[tmpi+1].key = L.r[tmpi].key;
43             }
44             L.r[right+1].key = tmp;
45             ++i;
46         }
47         L.r[j].key = L.r[i].key;
48         
49     }
50     L.r[j].key = L.r[0].key;
51 }

  在2-路快速插入排序中,相比算法一,2-路插入排序,来说,节约了n-2个辅助存储空间,但是增加了最大n-1个记录的移动,相对0(N^2)的复杂度来说,可以忽略,然后时间复杂度并没有明显下降。在最坏的情况下(当选取的哨兵元素为数据序列中最大或最小的元素时),2-路快速插入排序退化为折半插入排序。

可运行程序源码:

View Code
  1 /*
  2 *    2-road Insert sort algorithm
  3 *    Post at 2012.10.8
  4 */
  5 #include <stdio.h>
  6 #include <stdlib.h>
  7 #include <string.h>
  8 
  9 #define MAXSIZE 20
 10 typedef int KeyType;
 11 typedef struct {
 12     KeyType key;
 13 }RedType;
 14 typedef struct{
 15     RedType r[MAXSIZE+1];
 16     int length;
 17 }Sqlist;
 18 
 19 
 20 void initSqlist(Sqlist &L){
 21     printf("input the sort record length:");
 22     if(!scanf("%d",&L.length) && L.length <= MAXSIZE ){
 23         printf("input error!\n");
 24         exit(-1);
 25     }
 26     int i;
 27     for(i=1; i<= L.length; ++i){
 28         //printf("input the record:");
 29         scanf("%d",&L.r[i].key);
 30     }
 31 } 
 32 
 33 bool LT(KeyType r1, KeyType r2){
 34     if(r1<r2){
 35         return true;
 36     }else{
 37         return false;
 38     }
 39 }
 40 
 41 bool LE(KeyType r1, KeyType r2){
 42     if(r1<=r2){
 43         return true;
 44     }else{
 45         return false;
 46     }
 47 }
 48 
 49 /* 2 Path Insert Sort */ 
 50 void twoPathInsertSort(Sqlist &L){
 51     if(!L.length)
 52         return;
 53     KeyType d[MAXSIZE]={0};
 54     // 设置第一个记录和最后一个记录的指针 
 55     int first=0;
 56     int final=0;
 57     // 设置d[0]为哨兵元素 
 58     d[0]=L.r[1].key;
 59     int i;
 60     for(i=2; i<= L.length; ++i){
 61         if(LT(L.r[i].key,d[first])){  // 不需移动元素 
 62             first = (first-1+L.length)%L.length;
 63             d[first] = L.r[i].key ;
 64         }else if(LT(d[final],L.r[i].key)){ // 不需要移动元素 
 65             final = final+1 ;
 66             d[final] = L.r[i].key;
 67         }else {    // 中间插入,需要移动元素 
 68             int j=final-1;
 69             final += 1;
 70             d[final] = d[final-1];
 71             while(LT(L.r[i].key,d[j])){
 72                 d[j+1] = d[j];
 73                 --j;
 74             }
 75             d[j+1] = L.r[i].key;
 76         }
 77     }
 78     // 将辅助数组的数据按序复制到表L 
 79     for(i=1; i<= L.length; ++i){
 80         L.r[i].key = d[first%L.length];
 81         ++first;
 82     }
 83 }
 84 
 85 /* 2 path quick insert sort ,has some problem not deal with*/
 86 void twoPQInsertSort(Sqlist &L){
 87     int i=1;
 88     int j=L.length;
 89     L.r[0].key = L.r[i].key;
 90     // Quick insert sort from two path 
 91     while(i<j){
 92         while(LE(L.r[0].key,L.r[j].key) && i<j){
 93             // 下面是折半插入代码 
 94             int left=j+1;
 95             int right=L.length;
 96             while( left <= right ){
 97                 int m = (left+right)/2 ;
 98                 if(LT(L.r[j].key,L.r[m].key))
 99                     right = m - 1;
100                 else
101                     left = m + 1;
102             }
103             KeyType tmp = L.r[j].key;
104             int tmpj;
105             for(tmpj=j; tmpj <= right-1; ++tmpj){
106                 L.r[tmpj].key = L.r[tmpj+1].key;
107             }
108             L.r[right].key = tmp;
109             --j;
110         }
111         L.r[i].key = L.r[j].key;
112         
113         while(LE(L.r[i].key,L.r[0].key) && i<j){
114             // 下面是折半插入代码 
115             int left = 1;
116             int right = i-1;
117             while(left<=right){
118                 int m = (left+right)/2;
119                 if(LT(L.r[i].key,L.r[m].key))
120                     right = m - 1;
121                 else
122                     left = m + 1;
123             }
124             int tmpi;
125             int tmp = L.r[i].key;
126             for(tmpi=i-1; tmpi>= right+1; --tmpi){
127                 L.r[tmpi+1].key = L.r[tmpi].key;
128             }
129             L.r[right+1].key = tmp;
130             ++i;
131         }
132         L.r[j].key = L.r[i].key;
133         
134     }
135     L.r[j].key = L.r[0].key;
136 }
137 
138 void printSqlist(Sqlist &L){
139     printf("Sorted Sqlist as follow:");
140     int i;
141     for(i=1; i <= L.length; ++i){
142         printf(" %d ",L.r[i].key);
143     }
144     printf("\n");
145 }
146 
147 
148 int main(int argc, char **argv){
149     Sqlist L;
150     L.length = 0;
151     initSqlist(L);
152     //twoPathInsertSort(L);    
153     twoPQInsertSort(L);
154     printSqlist(L);
155     return 0;
156 }

 

原文地址:https://www.cnblogs.com/HackingProgramer/p/2719227.html