数据结构【排序】—排序算法大集合

影响排序性能的要素
  时间性能;
  辅助空间
  算法的复杂度

简单排序【n^2】
  算法思想:
    第一趟:
      从第一个记录开始,通过n-1次关键字比较,从n个记录中选出最小的并和第一个记录交换;
     第二趟:
      从第二个记录开始,通过n-2次关键字比较,从n -1个记录中选出最小的并和第二个记录交换;

  

 1 /**************************简单排序****************************/
 2 //初级冒泡排序,就是一个一个与后面对比
 3 void  BubbleSort0(SqList* &l,int (&a)[2]) {
 4     for (int i = 1; i < l->len; ++i) {
 5         for (int j = i + 1; j <= l->len; ++j) {
 6             a[0]++;
 7             if (l->v[i] > l->v[j]){
 8                 swap(l->v[i], l->v[j]);
 9                 a[1]++;
10             }
11         }
12     }
13 }

 

冒泡排序【n^2】:
  冒泡排序(Bubble Sort)一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。
  从末尾两两比较将最小数浮上来!

 1 /**************************冒泡排序****************************/
 2 //冒泡排序,两两比较排序
 3 void BubbleSort(SqList* &l, int(&a)[2]) {
 4     for (int i = 1; i < l->len; ++i) {
 5         for (int j = l->len - 1; j >= i; --j) {
 6             a[0]++;
 7             if (l->v[j + 1] < l->v[j]) {
 8                 swap(l->v[j + 1], l->v[j]);
 9                 a[1]++;
10             }
11         }
12     }
13 }
 1 /**************************改进冒泡排序****************************/
 2 //改进冒泡排序,加入哨兵模式
 3 void BubbleSort2(SqList* &l, int(&a)[2]) {
 4     bool flag = true;//哨兵
 5     for (int i = 1; flag&&i < l->len; ++i) {
 6         flag = false;
 7         for (int j = l->len - 1; j >= i; --j) {
 8             a[0]++;
 9             if (l->v[j + 1] < l->v[j]) {
10                 a[1]++;
11                 swap(l->v[j + 1], l->v[j]);
12                 flag = true;//数据交换后才需要遍历
13             }
14         }
15     }
16 }

 

选择比较【n^2】:
  简单选择排序法(Simple Selection Sort)就是通过n-i次关键字间的比较,从n-i+1个记录中选出关键字最小的坐标记录,并和第i(1<i<n)个记录交换之。找到最小值,然后依次放到前到后的值;

 1 /**************************选择排序****************************/
 2 //选择排序,就是依次找出未排序中的最小值放入前面
 3 void SelectSort(SqList* &l, int(&a)[2]) {
 4     int i, j, min;
 5     for (i = 1; i < l->len; ++i) {
 6         min = i;
 7         for (j = i + 1; j < l->len; ++j) {
 8             a[0]++;
 9             if (l->v[min] > l->v[j])
10                 min = j;
11         }
12         if (i != min) {
13             swap(l->v[min], l->v[i]);
14             a[1]++;
15         }
16     }
17 }

 

直接插入排序【n^2】:
  直接插入排序(Straight Insertion Sort)的基本操作是将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增1的有序表。

  即:从前向后两两比较,若第二个数为小的数,然后将该数记住,从此位置从后向前比较该数,并将比他大的数向后挪,直到找到存放该数的位置
  此算法需要一个辅助的临时空间存放:

  算法思想:将第i个记录插入到前面已经排好序的i - 1个记录中去。

  算法要点:
    ·使用监视哨r[0]临时保存带插入记录
    ·从后往前查找应插入的位置
    ·查找与移动用同一循环完成
    ·算法时间复杂度:o(n^2)

 1 /**************************插值排序****************************/
 2 //插值排序,就是从前向后两两比较,若第二个数为小的数,然后将该数记住,
 3 //从此位置从后向前比较该数,并将比他大的数向后挪,直到找到存放该数的位置
 4 //此算法需要一个辅助的临时空间存放:
 5 
 6 void InsertSort(SqList* &l, int(&a)[2]) {
 7     int i, j;
 8     for (int i = 2; i < l->len; ++i) {
 9         a[0]++;
10         if (l->v[i] < l->v[i - 1]) {//找到了前比后大的数
11             l->v[0] = l->v[i];//设置哨兵
12             for (j = i - 1; l->v[0] < l->v[j]; --j) {//返回比较
13                 a[1]++;
14                 l->v[j + 1] = l->v[j];//大的数向后挪
15             }
16             l->v[j+1] = l->v[0];
17         }
18     }
19 }

折半插入排序:

  算法思想:
    利用折半查找的思想找到需要插入的位置
  算法时间复杂度:
    o(n^2),虽然减少了查找插入位置的次数,但是移动元素的时间仍未改变

希尔排序【nlogn】:
  将相距某个“增量”的记录组成一个子序列,这样才能保证在子序列内分别进行直接插入排序后得到的结果是基本有序而不是局部有序。

  与直接插入排序很相似,但需要一个变动的跨度n进行比较,然后第二次跨度为n-1进行比较

  算法思想:
    将待排序的关键字序列分成若干个较小的子序列,对子序列进行直接插入排序,使整个待排序序列排好序。

 1 /**************************希尔排序****************************/
 2 //希尔排序
 3 //与插值排序很像,不过是间隔比较
 4 void ShellSort(SqList* &l, int(&a)[2]) {
 5     int gap = l->len;
 6     int i, j;
 7     do {
 8         gap = gap / 3 + 1;//间隔大小
 9         for (i = gap + 1; i < l->len; ++i) {
10             a[0]++;
11             if (l->v[i] < l->v[i - gap]) {
12                 l->v[0] = l->v[i];
13                 for (j = i - gap; j > 0 && l->v[0] < l->v[j]; j -= gap) {//向前去排序
14                     l->v[j + gap] = l->v[j];//大数向后移;
15                     a[1]++;
16                 }
17                 l->v[j + gap] = l->v[0];//插入
18             }
19         }
20     } while (gap > 1);
21 }

堆排序【nlogn】:
  堆是具有下列性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。

  

 1 /**************************************堆排序*****************************/
 2 //调整为大根堆
 3 void HeapAdjust(SqList* &l, int n, int len) {
 4     int temp = l->v[n];
 5     for (int i = 2 * n; i <= len; i *= 2) {//沿着关键字中较大的孩子结构向在筛选
 6         if (i < len&&l->v[i] < l->v[i + 1])++i;//i为关键字中较大的记录的下标
 7         if (temp >= l->v[i])break;//找到插入的位置了
 8         l->v[n] = l->v[i];//
 9         n = i;
10     }
11     l->v[n] = temp;//进行插入
12 }
13 
14 //堆排序
15 void HeapSort(SqList* &l, int(&a)[2]) {
16     for (int i = l->len / 2; i > 0; --i) {//把数组中的数据变为一个大堆
17         a[0]++;
18         HeapAdjust(l, i, l->len);
19     }
20     for (int i = l->len; i > 1; --i) {
21         a[1]++;
22         swap(l->v[1], l->v[i]);/* 将堆顶记录和当前未经排序子序列的最后一个记录交换 */
23         HeapAdjust(l, 1, i - 1);/*  将L->r[1..i-1]重新调整为大根堆 */
24     }
25 }

  算法思想:

  将向量中存储的数据看成一棵完全二叉树,利用完全二叉树中双亲节点和孩子节点之间的内在关系选择关键字最小的记录。
    ·将待排序的序列构造成一个大顶堆。
    ·此时,整个序列的最大值就是堆顶的根结点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),
    ·然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次大值。
    ·如此反复执行,便能得到一个有序序列了。

  大根堆:
    根节点最大;
    各节点关键字满足:a[i] >= a[2i]并且a[i] >= a[2i + 1]
  小根堆:
    根节点最小;
    各节点关键字满足:a[i] <= a[2i]并且a[i] <= a[2i+1]

归并排序:
    归并排序(Merging Sort)就是利用归并的思想实现的排序方法。它的原理是假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[n/21([x1表示不小于x的最小整数)个长度为2或1的有序子序列;再两两归并,……,如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序。

  算法思想:
  设初始序列长度为n,将这n个序列看成n个有序的子序列,然后辆辆合并,得到一个ceil(n/2)长度为2的有序子序列。
  在此基础上再对长度为2 的有序子序列进行归并排序,得到若干长度为4的子序列,如此重复直到得到一个长度为n的有序子序列为止

  

 1 /**************************递归法归并+排序****************************/
 2 /* 将有序的SR[i..m]和SR[m+1..n]归并为有序的TR[i..n] */
 3 //归并
 4 void Merge(int *SR, int *TR, int pot, int m, int len) {
 5     int i,j,k;
 6     for (i = m + 1, k = pot; pot <= m && i <= len; ++k) {/*将SR中记录由小到大地并入TR * /*/
 7         if (SR[pot] < SR[i])TR[k] = SR[pot++];
 8         else TR[k] = SR[i++];
 9     }
10     if (pot <= m)
11         for (j = 0; j <= m; ++j)
12             TR[k + j] = SR[pot + j];    /* 将剩余的SR[i..m]复制到TR */
13     if (i <= len)
14         for (j = 0; j <= len - i; ++j)
15             TR[k + j] = SR[i + j];/* 将剩余的SR[j..n]复制到TR */
16 }
17 //进行递归
18 void MSort(int *SR,int*TR1,int pot, int len, int(&a)[2]) {
19     int TR2[MAXSIZE + 1];
20     if (len == pot)
21         TR1[pot] = SR[pot];
22     else {
23         int m = (len + pot) / 2;    //将原数组平分两个数组
24         a[0]++;
25         MSort(SR, TR2, pot, m, a);    /* 递归地将SR[pot..m]归并为有序的TR2[pot..m] */
26         MSort(SR, TR2, m + 1, len, a);    /* 递归地将SR[m+1..len]归并为有序的TR2[m+1..len] */
27         Merge(TR2, TR1, pot, m, len);    /* 将TR2[pot..m]和TR2[m+1..t]归并到TR1[pot..len] */
28         a[1]++;
29     }
30 
31 }
32 
33 //递归法归并排序
34 void MergeSort(SqList* &l, int(&a)[2]) {
35     MSort(l->v,l->v,1, l->len,a);
36 }
37 
38 /**************************非递归法归并排序****************************/
39 /*将SR[]中相邻长度为s的子序列两两归并到TR[] * /*/
40 void MergePass(int *SR, int *TR, int k, int len, int(&a)[2]) {
41     int i = 1, j;
42     a[1]++;
43     while (i <= len - 2 * k + 1) {
44         //两两归并
45         Merge(SR, TR, i, i + k - 1, len);
46         i = i + 2 * k;
47     }
48     if (i < len - k + 1)//归并最后两个序列
49         Merge(SR, TR, i, i + k - 1, len);
50     else//最后只剩下单个序列
51         for (j = i; j <= len; ++j)
52             TR[j] = SR[j];
53 } 
54 //归并排序
55 void MergeSort2(SqList* &l, int(&a)[2]) {
56     int *TR = new int[l->len];
57     int k = 1;
58     while (k < l->len) {
59         a[0]++;
60         MergePass(l->v, TR, k, l->len, a);
61         k = k * 2;//加长子序列
62         MergePass(TR, l->v, k, l->len, a);
63         k = 2 * k;//子序列加长
64     }
65 }

    

快速排序:
  快速排序(Quick Sort)的基本思想是:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。

  算法思想:
    从待排序记录中选择一个记录为枢纽,设为K,将其余大于K的记录移动至K的后面,小于K的移动至前面,此过程称为一趟快速排序。当然就是对接下来的两个字表进行相同的操作,直到子表的长度不超过1
  算法时间复杂度:
    O(Knlog2n),K为常数因子,且在所有O(nlogn)复杂度中,快排的K值最小

  

 1 /**************************快速排序****************************/
 2 /* 交换顺序表L中子表的记录,使枢轴记录到位,并返回其所在位置 */
 3 /* 此时在它之前(后)的记录均不大(小)于它。 */
 4 //即处于枢轴的数的左边比其小,右边比其大
 5 int Partiton(SqList* &l, int pot, int len, int(&a)[2]) {
 6     int pkey;
 7     pkey = l->v[pot];//假设第一个位置的数就是枢轴的位置
 8     while (pot < len) {
 9         a[0]++;
10         while (pot < len&&l->v[len] >= pkey)//确保右边大于关键数
11             len--;
12         a[1]++;
13         swap(l->v[pot], l->v[len]);//将比关键数小的数放置到关键数的左边
14         a[0]++;
15         while (pot < len&&l->v[pot] <= pkey)//确保左边的 数小于关键数
16             pot++;
17         a[1]++;
18         swap(l->v[pot], l->v[len]);//将比关键数大的数放置到关键数的右边
19     }
20     return pot;//返回关键数的位置
21 }
22 
23 /* 对顺序表L中的子序列L->r[low..high]作快速排序 */
24 void QSort(SqList* &l, int pot, int len, int(&a)[2]) {
25     int pivot;
26     if (pot < len) {
27         pivot = Partiton(l, pot, len, a);/*  将L->r[low..high]一分为二,算出枢轴值pivot */
28         QSort(l, pot, pivot - 1, a);/*  对低子表递归排序 */
29         QSort(l, pivot + 1, len, a);/*  对高子表递归排序 */
30     }
31 }
32 void QuickSort(SqList* &l, int(&a)[2]) {
33     QSort(l, 1, l->len, a);
34 }
35 
36 /**************************改进快速排序****************************/
37 //快速排序的优化
38 int Partiton1(SqList* &l, int pot, int len, int(&a)[2]) {
39     int pkey;
40 
41     /////改进之处,之间选中间作为关键数的位置
42     int m = pot + (len - pot) / 2;
43     a[0]++;
44     if (l->v[pot] > l->v[len]) {
45         swap(l->v[pot], l->v[len]);/* 交换左端与右端数据,保证左端较小 */
46         a[1]++;
47     }
48     a[0]++;
49     if (l->v[m] > l->v[len]) {
50         swap(l->v[m], l->v[len]);/* 交换中间与右端数据,保证中间较小 */
51         a[1]++;
52     }
53     a[0]++;
54     if (l->v[m] < l->v[pot]) {
55         swap(l->v[m], l->v[pot]);/* 交换中间与左端数据,保证左端较小 */
56         a[1]++;
57     }
58     /////
59     pkey = l->v[pot];//假设第一个位置的数就是枢轴的位置
60     l->v[0] = pkey;//保留
61     while (pot < len) {/*从表的两端交替地向中间扫描 */
62         a[0]++;
63         while (pot < len&&l->v[len] >= pkey)//确保右边大于关键数
64             --len;
65         l->v[pot] = l->v[len];
66         a[0]++;
67         while (pot < len&&l->v[pot] <= pkey)//确保左边的 数小于关键数
68             ++pot;
69         l->v[len] = l->v[pot];
70     }
71     l->v[pot] = l->v[0];
72     return pot;//返回关键数的位置
73 }
74 
75 void QSort1(SqList* &l, int pot, int len, int(&a)[2]) {
76     int pivot;
77     if ((len - pot) > MAX_LENGTH_INSERT_SORT) {
78         while (pot < len) {
79             pivot = Partiton1(l, pot, len, a);/*  将L->r[low..high]一分为二,算出枢轴值pivot */
80             QSort1(l, pot, pivot - 1, a);/*  对低子表递归排序 */
81             pot = pivot + 1;//尾递归
82         }
83     }
84     else
85         InsertSort(l,a);
86 }
87 
88 void QuickSort1(SqList* &l, int(&a)[2]) {
89     QSort1(l, 1, l->len, a);
90 }

 

总结:
  

  

  从算法的简单性来看,我们将7种算法分为两类:

  ·简单算法:冒泡、简单选择、直接插入。
  ·改进算法:希尔、堆、归并、快速。

 

完整代码:

  

  1 #include "000库函数.h"
  2 
  3 #define MAX_LENGTH_INSERT_SORT 7 /* 用于快速排序时判断是否选用插入排序阙值 */
  4 #define MAXSIZE 100  /* 用于要排序数组个数最大值,可根据需要修改 */
  5 #define N 9
  6 struct SqList
  7 {
  8     int v[MAXSIZE+1];//用于存储要排序的数组,r[0]作为哨兵或临时存放变量
  9     int len;//记录顺序表的长度
 10 };
 11 
 12 //数据交换
 13 void swap(int &i, int &j) {
 14     int temp;
 15     temp = i;
 16     i = j;
 17     j = temp;
 18 }
 19 
 20 /**************************简单排序****************************/
 21 //初级冒泡排序,就是一个一个与后面对比
 22 void  BubbleSort0(SqList* &l,int (&a)[2]) {
 23     for (int i = 1; i < l->len; ++i) {
 24         for (int j = i + 1; j <= l->len; ++j) {
 25             a[0]++;
 26             if (l->v[i] > l->v[j]){
 27                 swap(l->v[i], l->v[j]);
 28                 a[1]++;
 29             }
 30         }
 31     }
 32 }
 33 
 34 /**************************冒泡排序****************************/
 35 //冒泡排序,两两比较排序
 36 void BubbleSort(SqList* &l, int(&a)[2]) {
 37     for (int i = 1; i < l->len; ++i) {
 38         for (int j = l->len - 1; j >= i; --j) {
 39             a[0]++;
 40             if (l->v[j + 1] < l->v[j]) {
 41                 swap(l->v[j + 1], l->v[j]);
 42                 a[1]++;
 43             }
 44         }
 45     }
 46 }
 47 
 48 /**************************改进冒泡排序****************************/
 49 //改进冒泡排序,加入哨兵模式
 50 void BubbleSort2(SqList* &l, int(&a)[2]) {
 51     bool flag = true;//哨兵
 52     for (int i = 1; flag&&i < l->len; ++i) {
 53         flag = false;
 54         for (int j = l->len - 1; j >= i; --j) {
 55             a[0]++;
 56             if (l->v[j + 1] < l->v[j]) {
 57                 a[1]++;
 58                 swap(l->v[j + 1], l->v[j]);
 59                 flag = true;//数据交换后才需要遍历
 60             }
 61         }
 62     }
 63 }
 64 
 65 /**************************选择排序****************************/
 66 //选择排序,就是依次找出未排序中的最小值放入前面
 67 void SelectSort(SqList* &l, int(&a)[2]) {
 68     int i, j, min;
 69     for (i = 1; i < l->len; ++i) {
 70         min = i;
 71         for (j = i + 1; j < l->len; ++j) {
 72             a[0]++;
 73             if (l->v[min] > l->v[j])
 74                 min = j;
 75         }
 76         if (i != min) {
 77             swap(l->v[min], l->v[i]);
 78             a[1]++;
 79         }
 80     }
 81 }
 82 
 83 /**************************插值排序****************************/
 84 //插值排序,就是从前向后两两比较,若第二个数为小的数,然后将该数记住,
 85 //从此位置从后向前比较该数,并将比他大的数向后挪,直到找到存放该数的位置
 86 //此算法需要一个辅助的临时空间存放:
 87 
 88 void InsertSort(SqList* &l, int(&a)[2]) {
 89     int i, j;
 90     for (int i = 2; i < l->len; ++i) {
 91         a[0]++;
 92         if (l->v[i] < l->v[i - 1]) {//找到了前比后大的数
 93             l->v[0] = l->v[i];//设置哨兵
 94             for (j = i - 1; l->v[0] < l->v[j]; --j) {//返回比较
 95                 a[1]++;
 96                 l->v[j + 1] = l->v[j];//大的数向后挪
 97             }
 98             l->v[j+1] = l->v[0];
 99         }
100     }
101 }
102 
103 /**************************希尔排序****************************/
104 //希尔排序
105 //与插值排序很像,不过是间隔比较
106 void ShellSort(SqList* &l, int(&a)[2]) {
107     int gap = l->len;
108     int i, j;
109     do {
110         gap = gap / 3 + 1;//间隔大小
111         for (i = gap + 1; i < l->len; ++i) {
112             a[0]++;
113             if (l->v[i] < l->v[i - gap]) {
114                 l->v[0] = l->v[i];
115                 for (j = i - gap; j > 0 && l->v[0] < l->v[j]; j -= gap) {//向前去排序
116                     l->v[j + gap] = l->v[j];//大数向后移;
117                     a[1]++;
118                 }
119                 l->v[j + gap] = l->v[0];//插入
120             }
121         }
122     } while (gap > 1);
123 }
124 
125 /**************************************堆排序*****************************/
126 //调整为大根堆
127 void HeapAdjust(SqList* &l, int n, int len) {
128     int temp = l->v[n];
129     for (int i = 2 * n; i <= len; i *= 2) {//沿着关键字中较大的孩子结构向在筛选
130         if (i < len&&l->v[i] < l->v[i + 1])++i;//i为关键字中较大的记录的下标
131         if (temp >= l->v[i])break;//找到插入的位置了
132         l->v[n] = l->v[i];//
133         n = i;
134     }
135     l->v[n] = temp;//进行插入
136 }
137 
138 //堆排序
139 void HeapSort(SqList* &l, int(&a)[2]) {
140     for (int i = l->len / 2; i > 0; --i) {//把数组中的数据变为一个大堆
141         a[0]++;
142         HeapAdjust(l, i, l->len);
143     }
144     for (int i = l->len; i > 1; --i) {
145         a[1]++;
146         swap(l->v[1], l->v[i]);/* 将堆顶记录和当前未经排序子序列的最后一个记录交换 */
147         HeapAdjust(l, 1, i - 1);/*  将L->r[1..i-1]重新调整为大根堆 */
148     }
149 }
150 
151 /**************************递归法归并+排序****************************/
152 /* 将有序的SR[i..m]和SR[m+1..n]归并为有序的TR[i..n] */
153 //归并
154 void Merge(int *SR, int *TR, int pot, int m, int len) {
155     int i,j,k;
156     for (i = m + 1, k = pot; pot <= m && i <= len; ++k) {/*将SR中记录由小到大地并入TR * /*/
157         if (SR[pot] < SR[i])TR[k] = SR[pot++];
158         else TR[k] = SR[i++];
159     }
160     if (pot <= m)
161         for (j = 0; j <= m; ++j)
162             TR[k + j] = SR[pot + j];    /* 将剩余的SR[i..m]复制到TR */
163     if (i <= len)
164         for (j = 0; j <= len - i; ++j)
165             TR[k + j] = SR[i + j];/* 将剩余的SR[j..n]复制到TR */
166 }
167 //进行递归
168 void MSort(int *SR,int*TR1,int pot, int len, int(&a)[2]) {
169     int TR2[MAXSIZE + 1];
170     if (len == pot)
171         TR1[pot] = SR[pot];
172     else {
173         int m = (len + pot) / 2;    //将原数组平分两个数组
174         a[0]++;
175         MSort(SR, TR2, pot, m, a);    /* 递归地将SR[pot..m]归并为有序的TR2[pot..m] */
176         MSort(SR, TR2, m + 1, len, a);    /* 递归地将SR[m+1..len]归并为有序的TR2[m+1..len] */
177         Merge(TR2, TR1, pot, m, len);    /* 将TR2[pot..m]和TR2[m+1..t]归并到TR1[pot..len] */
178         a[1]++;
179     }
180 
181 }
182 
183 //递归法归并排序
184 void MergeSort(SqList* &l, int(&a)[2]) {
185     MSort(l->v,l->v,1, l->len,a);
186 }
187 
188 /**************************非递归法归并排序****************************/
189 /*将SR[]中相邻长度为s的子序列两两归并到TR[] * /*/
190 void MergePass(int *SR, int *TR, int k, int len, int(&a)[2]) {
191     int i = 1, j;
192     a[1]++;
193     while (i <= len - 2 * k + 1) {
194         //两两归并
195         Merge(SR, TR, i, i + k - 1, len);
196         i = i + 2 * k;
197     }
198     if (i < len - k + 1)//归并最后两个序列
199         Merge(SR, TR, i, i + k - 1, len);
200     else//最后只剩下单个序列
201         for (j = i; j <= len; ++j)
202             TR[j] = SR[j];
203 } 
204 //归并排序
205 void MergeSort2(SqList* &l, int(&a)[2]) {
206     int *TR = new int[l->len];
207     int k = 1;
208     while (k < l->len) {
209         a[0]++;
210         MergePass(l->v, TR, k, l->len, a);
211         k = k * 2;//加长子序列
212         MergePass(TR, l->v, k, l->len, a);
213         k = 2 * k;//子序列加长
214     }
215 }
216 
217 /**************************快速排序****************************/
218 /* 交换顺序表L中子表的记录,使枢轴记录到位,并返回其所在位置 */
219 /* 此时在它之前(后)的记录均不大(小)于它。 */
220 //即处于枢轴的数的左边比其小,右边比其大
221 int Partiton(SqList* &l, int pot, int len, int(&a)[2]) {
222     int pkey;
223     pkey = l->v[pot];//假设第一个位置的数就是枢轴的位置
224     while (pot < len) {
225         a[0]++;
226         while (pot < len&&l->v[len] >= pkey)//确保右边大于关键数
227             len--;
228         a[1]++;
229         swap(l->v[pot], l->v[len]);//将比关键数小的数放置到关键数的左边
230         a[0]++;
231         while (pot < len&&l->v[pot] <= pkey)//确保左边的 数小于关键数
232             pot++;
233         a[1]++;
234         swap(l->v[pot], l->v[len]);//将比关键数大的数放置到关键数的右边
235     }
236     return pot;//返回关键数的位置
237 }
238 
239 /* 对顺序表L中的子序列L->r[low..high]作快速排序 */
240 void QSort(SqList* &l, int pot, int len, int(&a)[2]) {
241     int pivot;
242     if (pot < len) {
243         pivot = Partiton(l, pot, len, a);/*  将L->r[low..high]一分为二,算出枢轴值pivot */
244         QSort(l, pot, pivot - 1, a);/*  对低子表递归排序 */
245         QSort(l, pivot + 1, len, a);/*  对高子表递归排序 */
246     }
247 }
248 void QuickSort(SqList* &l, int(&a)[2]) {
249     QSort(l, 1, l->len, a);
250 }
251 
252 /**************************改进快速排序****************************/
253 //快速排序的优化
254 int Partiton1(SqList* &l, int pot, int len, int(&a)[2]) {
255     int pkey;
256 
257     /////改进之处,之间选中间作为关键数的位置
258     int m = pot + (len - pot) / 2;
259     a[0]++;
260     if (l->v[pot] > l->v[len]) {
261         swap(l->v[pot], l->v[len]);/* 交换左端与右端数据,保证左端较小 */
262         a[1]++;
263     }
264     a[0]++;
265     if (l->v[m] > l->v[len]) {
266         swap(l->v[m], l->v[len]);/* 交换中间与右端数据,保证中间较小 */
267         a[1]++;
268     }
269     a[0]++;
270     if (l->v[m] < l->v[pot]) {
271         swap(l->v[m], l->v[pot]);/* 交换中间与左端数据,保证左端较小 */
272         a[1]++;
273     }
274     /////
275     pkey = l->v[pot];//假设第一个位置的数就是枢轴的位置
276     l->v[0] = pkey;//保留
277     while (pot < len) {/*从表的两端交替地向中间扫描 */
278         a[0]++;
279         while (pot < len&&l->v[len] >= pkey)//确保右边大于关键数
280             --len;
281         l->v[pot] = l->v[len];
282         a[0]++;
283         while (pot < len&&l->v[pot] <= pkey)//确保左边的 数小于关键数
284             ++pot;
285         l->v[len] = l->v[pot];
286     }
287     l->v[pot] = l->v[0];
288     return pot;//返回关键数的位置
289 }
290 
291 void QSort1(SqList* &l, int pot, int len, int(&a)[2]) {
292     int pivot;
293     if ((len - pot) > MAX_LENGTH_INSERT_SORT) {
294         while (pot < len) {
295             pivot = Partiton1(l, pot, len, a);/*  将L->r[low..high]一分为二,算出枢轴值pivot */
296             QSort1(l, pot, pivot - 1, a);/*  对低子表递归排序 */
297             pot = pivot + 1;//尾递归
298         }
299     }
300     else
301         InsertSort(l,a);
302 }
303 
304 void QuickSort1(SqList* &l, int(&a)[2]) {
305     QSort1(l, 1, l->len, a);
306 }
307 
308 
309 /*************************************************************/
310 int T036(){
311     /* int d[N]={9,1,5,8,3,7,4,6,2}; */
312     int d[N] = { 50,10,90,30,70,40,80,60,20 };
313     /* int d[N]={9,8,7,6,5,4,3,2,1}; */
314     int count[2] = { 0,0 };//记录比较次数和交换次数
315     SqList *l0, *l1, *l2, *l3, *l4, *l5, *l6, *l7, *l8, *l9, *l10;
316 
317     l0 = new SqList;
318     for (int i = 0; i < N; i++)
319         l0->v[i + 1] = d[i];
320     l0->len = N;
321 
322     l1 = l2 = l3 = l4 = l5 = l6 = l7 = l8 = l9 = l10 = l0;
323     printf("排序前:\n");
324     for(int i=1;i<=N;++i)
325         cout << l0->v[i] << "  ";
326     cout << endl;
327 
328     printf("初级冒泡排序:\n");
329     BubbleSort0(l0,count);
330     for (int i = 1; i <= N; ++i)
331         cout << l0->v[i] << "  ";
332     cout << endl;
333     cout << "比较次数: " << count[0] << " ; 交换次数: " << count[1] << endl;
334     count[0] = count[1] = 0;//归0
335 
336     printf("冒泡排序:\n");
337     BubbleSort(l1,count);
338     for (int i = 1; i <= N; ++i)
339         cout << l1->v[i] << "  ";
340     cout << endl;
341     cout << "比较次数: " << count[0] << " ; 交换次数: " << count[1] << endl;
342     count[0] = count[1] = 0;//归0
343 
344     printf("改进冒泡排序:\n");
345     BubbleSort2(l2,count);
346     for (int i = 1; i <= N; ++i)
347         cout << l2->v[i] << "  ";
348     cout << endl;
349     cout << "比较次数: " << count[0] << " ; 交换次数: " << count[1] << endl;
350     count[0] = count[1] = 0;//归0
351 
352     printf("选择排序:\n");
353     SelectSort(l3,count);
354     for (int i = 1; i <= N; ++i)
355         cout << l3->v[i] << "  ";
356     cout << endl;
357     cout << "比较次数: " << count[0] << " ; 交换次数: " << count[1] << endl;
358     count[0] = count[1] = 0;//归0
359 
360     printf("直接插入排序:\n");
361     InsertSort(l4, count);
362     for (int i = 1; i <= N; ++i)
363         cout << l4->v[i] << "  ";
364     cout << endl;
365     cout << "比较次数: " << count[0] << " ; 交换次数: " << count[1] << endl;
366     count[0] = count[1] = 0;//归0
367 
368     printf("希尔排序:\n");
369     ShellSort(l5, count);
370     for (int i = 1; i <= N; ++i)
371         cout << l5->v[i] << "  ";
372     cout << endl;
373     cout << "比较次数: " << count[0] << " ; 交换次数: " << count[1] << endl;
374     count[0] = count[1] = 0;//归0
375 
376     printf("堆排序:\n");
377     HeapSort(l6, count);
378     for (int i = 1; i <= N; ++i)
379         cout << l6->v[i] << "  ";
380     cout << endl;
381     cout << "比较次数: " << count[0] << " ; 交换次数: " << count[1] << endl;
382     count[0] = count[1] = 0;//归0
383 
384     printf("归并排序(递归):\n");
385     MergeSort(l7, count);
386     for (int i = 1; i <= N; ++i)
387         cout << l7->v[i] << "  ";
388     cout << endl;
389     cout << "比较次数: " << count[0] << " ; 交换次数: " << count[1] << endl;
390     count[0] = count[1] = 0;//归0
391 
392     printf("归并排序(非递归):\n");
393     MergeSort2(l8, count);
394     for (int i = 1; i <= N; ++i)
395         cout << l8->v[i] << "  ";
396     cout << endl;
397     cout << "比较次数: " << count[0] << " ; 交换次数: " << count[1] << endl;
398     count[0] = count[1] = 0;//归0
399 
400     printf("快速排序:\n");
401     QuickSort(l9, count);
402     for (int i = 1; i <= N; ++i)
403         cout << l9->v[i] << "  ";
404     cout << endl;
405     cout << "比较次数: " << count[0] << " ; 交换次数: " << count[1] << endl;
406     count[0] = count[1] = 0;//归0
407 
408     printf("改进快速排序:\n");
409     QuickSort1(l10, count);
410     for (int i = 1; i <= N; ++i)
411         cout << l10->v[i] << "  ";
412     cout << endl;
413     cout << "比较次数: " << count[0] << " ; 交换次数: " << count[1] << endl;
414     count[0] = count[1] = 0;//归0
415 
416 
417     /*大数据排序*/
418     /*
419     srand(time(0));
420     int Max=10000;
421     int d[10000];
422     int i;
423     SqList l0;
424     for(i=0;i<Max;i++)
425         d[i]=rand()%Max+1;
426     for(i=0;i<Max;i++)
427         l0.r[i+1]=d[i];
428     l0.length=Max;
429     MergeSort(l0);
430     print(l0);
431     */
432     return 0;
433 }

 

posted @ 2019-03-26 08:48  自由之翼Az  阅读(226)  评论(0编辑  收藏  举报