经典的排序算法

这些天复习了排序这个模块,排序算法在程序员的日常工作中是必不可少的,有时候我们不知不觉就用到了排序,这是因为高级语言系统已经比较完美的封装和优化了排序算法,并且在笔试,面试等方面我们都能见到它的身影。下面结合那本大三的教材:严版的《数据结构》,来说一说这几个经典的排序算法,如果有不对的欢迎指正!

首先我们还是先说基础概念(按书上说的),万变离不开概念,没有概念没有规矩,那可不行。

1:内部排序和外部排序(我们重点说内部排序(因为我们最常用到))

内排序:在排序的时间数据对象全部存放在内存的排序。

外排序:在排序的时间对象个数太多,不能同时存放在内存,根据排序的要求,不断在内、外存之间移动。

2:排序的方法

按所排列(移动交换)的方式不同,可归纳为五类:插入排序、选择排序、交换排序、归并排序和分配排序(有的书上直接说基数)。

插入排序主要包括直接插入排序和希尔排序两种;

选择排序主要包括直接选择排序和堆排序;

交换排序主要包括冒泡排序和快速排序;

归并排序主要包括二路归并(常用的归并排序)。

分配排序主要包括箱排序和基数排序。

3:稳定性

稳定排序:假设在待排序的文件中,存在两个或两个以上的记录具有相同的关键字,在用某种排序法排序后,若这些相同关键字的元素的相对次序仍然不变,则这种排序方法是稳定的。

冒泡,插入,基数,归并属于稳定排序;

选择,快速,希尔,堆属于不稳定排序。

4:图表帮助大家记忆:

 各种排序算法
类别 排序方法 时间复杂度 稳定性
平均情况 最好情况 最坏情况
插入排序  直接插入  O(n2)  O(n)  O(n2)  稳定
 希尔排序  O(n1.3)  O(n)  O(n2)  不稳定
 选择排序  直接选择  O(n2)  O(n2)  O(n2)  不稳定
 堆排序  O(nlog2n)  O(nlog2n)  O(nlog2n)  不稳定
 交换排序  冒泡排序  O(n2)  O(n)  O(n2)  稳定
 快速排序  O(nlog2n)  O(nlog2n)  O(n2)  不稳定
  归并排序 O(nlog2n)  O(nlog2n)  O(nlog2n)  稳定
  基数排序 O(d(r+n)) O(d(n+rd))   O(d(r+n))   稳定

一、冒泡排序

冒泡排序也叫起泡排序,大家都知道,学C语言那会的循环结构就那这个做的例子,冒泡排序过程很简单,但是效率太低。

1:简要过程:

首先将一个记录的关键字和第二个记录的关键字比较若为逆序将两个记录交换,然后比较第二个记录和第三个记录的关键字....,直到n-1个记录呢第n个记录的关键字进行比较,上述过称作一趟冒泡排序,然后进行第二趟,对n-1个记录进行操作...(可以不安这种方法来,实际应用中可以逆序也可以正序,因为比较简单,所以不再多说)

2:排序效率:

如果开始的时候需要排序的元素是正序,则只要一趟,需要n-1次的关键字比较,如果为逆序要进行n(n-1)/2次的比较,所以时间复杂度是O(n2),所以效率超级的低,一般不建议使用

3:排序过程图:

4:具体算法实现(可以有多种形式):

 1 //冒泡排序
 2 void bubbling(int arr[], int n){
 3     int i,j,k;
 4     for(i = 0; i < n; i++){
 5         for(j = i+1;j < n;j++){
 6             if(arr[i] > arr[j]){
 7                 k = arr[i];
 8                 arr[i] = arr[j];
 9                 arr[j] = k;
10             }
11         }
12     }
13 }

二、直接选择排序

是一种选择排序,总的来说交换的少,比较的多,如果排序的数据是字符串的话比建议使用这种方法。

1:简要过程:

首先找出最大元素,与最后一个元素交换(arr[n-1]),然后再剩下的元素中找最大元素,与倒数第二个元素交换....直到排序完成。

2:排序效率:

一趟排序通过n-1次的关键字比较,从n-i-1个记录中选择最大或者最小的元素并和第i个元素交换,所以平均为n(n-1)/2,时间复杂度为O(n2),也不是个省油的灯,效率还是比较低。

3:排序过程图:(选择小元素)

4:具体算法实现:

 1 //直接选择排序
 2 void directDialing(int arr[], int n){
 3     int i,j,k,num;
 4     for(i = 0; i < n; i++){
 5         num = 0;
 6         for(j = 0; j < n-i; j++){
 7             if(arr[j] > arr[num]){
 8                 num = j;
 9             }
10         }
11         k = arr[n-i-1];
12         arr[n-i-1] = arr[num];
13         arr[num] = k;
14     }
15 }

三、直接插入排序

是一种简单的排序方法,算法简洁,容易实现

1:简要过程:

每步将一个待排序元素,插入到前面已经排序好的元素中,从而得到一个新的有序序列,直到最后一个元素加入进去即可。

2:排序效率:

空间上直接插入排序只需要一个辅助空间,时间上:花在比较两个关键字的大小和移动记录,逆序时比较次数最大:(n+2)(n-1)/2,平均:n2/4,所以直接插入排序时间复杂度也是O(n2)

3:排序过程图:

4:具体算法实现:

 1 //直接插入排序
 2 void  insert(int arr[], int n){
 3     int m,i,k;
 4     for(i = 1; i < n; i++){
 5         m = arr[i];
 6         for(k = i-1; k >= 0; k--){
 7             if(arr[k] > m){
 8                 arr[k+1] = arr[k];
 9             }else{
10                 break;
11             }
12         }
13         arr[k+1] = m;
14     }
15 }

四、希尔排序

希尔排序,也叫缩小增量排序,是一种插入排序,和前三种不一样它在时间效率上有很大的改进,所以这种排序方法才是我们需要重点学习和掌握的,但是凡事都有利弊,容易的排序算法算法简单,但是效率低下,反过来复杂的排序算法算法复杂,但是效率及其的出色。

 1:简要过程:

选择一个增量序列a1,a2,…,ak,其中ai>aj,ak=1;按增量序列个数k,对序列进行k 趟排序;每趟排序,根据对应的增量ai,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

说白了其实就是:先取一个正整数d1<n,把所有序号相隔d1的数组元素放一组,组内进行直接插入排序;然后取d2<d1,重复上述分组和排序操作;直至di=1,即所有记录放进一个组中排序为止。

2:排序效率:

希尔排序的效率的确不低,大量的研究说时间复杂度为O(n3/2)(书上说的在大量的试验基础上推出的)感觉有点玄乎,但是希尔排序效率确实很高,在后面我写的有一个效率比拼大家可以看看。

3:排序过程图:

 4:具体算法实现:

 1 //希尔排序
 2 void Heer(int arr[], int n){
 3     int i,j,k,num;
 4     k = n/2;
 5     while(k > 0){
 6         for(i = k; i < n; i++){
 7             num = arr[i];
 8             for(j = i - k;j >= 0; j -= k){
 9                 if(arr[j] > num){
10                     arr[j+k] = arr[j];
11                 }else{
12                     break;
13                 }
14             }
15             arr[j+k] = num;
16         }
17         k = k/2;
18     }
19 } 

 五、堆排序

先说说堆的定义:n个元素的序列{k1,k2,. . . kn}当且仅当满足以下条件时称之为堆:

ki <= k2i              ki >= k2i

ki <= k2i+1          ki >= k2i+1

若将这样的序列对用的一维数组看成一个完全二叉树则堆的定义看出:完全二叉树非终节点的值均不大于(不小于)其左右两个孩子的节点值。

大顶堆和小顶堆:堆顶元素取最小值的是小顶堆,取最大值的是大顶堆。

1:简要过程:

(1) 建堆:对初始序列建堆的过程,就是一个反复进行筛选的过程。n 个结点的完全二叉树,则最后一个结点是第(既是程序中的n * 2 +1)个结点的子树。筛选从第个结点为根的子树开始,该子树成为堆。之后向前依次对各结点为根的子树进行筛选,使之成为堆,直到根结点。

(2) 调整堆:k个元素的堆,输出堆顶元素后,剩下k-1 个元素。将堆底元素送入堆顶(最后一个元素与堆顶进行交换),堆被破坏,其原因仅是根结点不满足堆的性质。将根结点与左、右子树中较小元素的进行交换。若与左子树交换:如果左子树堆被破坏,即左子树的根结点不满足堆的性质,则重复调整堆,.若与右子树交换,如果右子树堆被破坏,即右子树的根结点不满足堆的性质。则重复调整堆。对不满足堆性质的子树进行上述交换操作,直到叶子结点,堆被建成。

2:排序效率:

堆排序的方法对记录较少的文件并不值得提倡,但对于数据较大的文件还是很有效的,时间主要花在初始建堆和交换元素后调整堆上。对深度为k的堆比较算法最多为2(k-1)次,含有n个元素深度为h的堆时总共进行的关键字比较不超过4n,由此可见最坏的情况下,时间复杂度为O(nlogn)并且仅需要一个辅助控间,速度已经是相当快了。

3:排序过程图(图片来源百度,帮助理解):

4:具体算法实现:

 1 //堆调整
 2 void adjust(int arr[], int n, int length){
 3     int max,b;
 4     while(n * 2 +1 <= length){//说明存在左节点
 5         max = n * 2 + 1;
 6         if(n * 2 + 2 <= length){//说明存在右节点
 7             if(arr[max] < arr[n * 2 + 2]){
 8                 max = n * 2 + 2; //跟新最小的值
 9             }
10         }
11         if(arr[n] > arr[max]){
12             break;//顺序正确,不需要再调整
13         }else{
14             b = arr[n];
15             arr[n] = arr[max];
16             arr[max] = b;
17             n = max;
18         }
19     }
20 }
21
22 //堆排序
23 void stack(int arr[], int length){
24     int i,k,m = 0;
25     for(i = length/2-1; i >=0; i--){
26         adjust(arr,i,length-1);
27     }
28     //调整堆
29     for(i = length-1 ;i >= 0; i--){
30         //调整后把最后一个和第一个交换,每次调整少一个元素,依次向前
31         k = arr[i];
32         arr[i] = arr[0];
33         arr[0] = k;
34         adjust(arr,0,i-1);
35     }
36 }

六、归并排序

将两个和两个以上的排序表合成一个新的有序表,归并排序是分治法思想运用的一个典范。

1:简要过程:

将有 n个对象的原始序 列看作 n个有序子列,每个序列的长度为1,从第一个子序列开始,把相邻的子序列两两合并得到[n/2]个长度为2或者是1的归并项,(如果n为奇数,则最后一个有序子序列的长度为1),称这一个过程为一趟归并排序。

然后重复上述过程指导得到一个长度为n的序列为止。

2:排序效率:

一趟归并排序的操作是:调用[n/2b]次算法,整个过程需要[log2n]趟,课件归并排序时间复杂度是O(logn)

3:排序过程图:

4:具体算法实现:

 1 //归并排序合并函数
 2 void mergeSoft(int a[], int first, int mid, int last, int temp[]){
 3     int i = first, j = mid + 1;
 4     int m = mid,   n = last;
 5     int k = 0;
 6     while (i <= m && j <= n){
 7         if (a[i] <= a[j]){
 8             temp[k++] = a[i++];
 9         }else{
10             temp[k++] = a[j++];
11         }
12     }
13     while (i <= m){
14         temp[k++] = a[i++];
15     }
16     while (j <= n){
17         temp[k++] = a[j++];
18     }
19
20     for (i = 0; i < k; i++){
21         a[first + i] = temp[i];
22     }
23 }
24
25 //归并排序递归拆分函数
26 void mergerSelf(int arr[], int left, int right, int arrTmp[]){
27     if(left < right){
28         int center = (left + right)/2;
29         mergerSelf(arr, left, center, arrTmp);
30         mergerSelf(arr, center+1, right, arrTmp);
31         mergeSoft(arr, left, center, right, arrTmp);
32     }
33 }
34 //归并排序
35 void merger(int arr[], int n){
36     int *arrTmp = new int[n];
37     mergerSelf(arr, 0, n - 1, arrTmp);
38     delete[] arrTmp;
39 } 

七、快速排序

快速排序是一种交换排序,说白了就是一种对起泡排序的改进,不过改进了不少,快速排序被认为是最好的一种排序算法(同量级别)。

1:简要过程:

选择一个基准元素,我们称之为中枢,通常选择第一个元素或者最后一个元素,中枢的选择很重要,直接影响排序的性能,这是因为如果代排序列有序,快速排序就退化为冒泡排序。将序列分割成左右两个序列。其中一部分记录的元素值均比基准元素值小。另一部分记录的 元素值比基准值大。一趟排序的具体做法将两个附设指针left和right,然后分别对这两部分记录用同样的方法继续进行排序,直到整个序列有序。

2:排序效率:

在所有同级别的排序算法中其平均性能最好O(nlogn)。如果代排序列有序,快速排序就退化为冒泡排序,效率及其低下,这个可以在下面的效率比拼图中体现出来逆序的时候快速排序非常慢,效率很低下。所以可以在中枢的选择上优化可以选着最左边和最右边中间的元素取其平均值即可。

3:排序过程图:

4:具体算法实现:

 1 //快速排序的元素移动
 2 int fastSort(int arr[], int left, int right){
 3     int center = (left+right)/2;
 4     int num = arr[center]; //记录中枢点的位置,这里选择最左边点当做中枢点
 5     while(left < right){
 6         //比枢纽小的移动到左边
 7         while(left < right && arr[right] >= num){
 8             right--; //一直到有一个元素小于所选关键中枢为止
 9         }
10         arr[left] = arr[right];
11
12         while(left < right && arr[left] <= num){
13             left++; //一直到有一个元素大于所选关键中枢为止
14         }
15         arr[right] = arr[left]; //关键字入列
16     }
17     arr[left] = num;
18     return left;
19 }
20
21 //快速排序递归划分
22 int fastSortSelf(int arr[], int left, int right){
23     if(left < right){
24         int lowLocation = fastSort(arr,left,right); //第一个指针的位置
25         fastSortSelf(arr,left,lowLocation - 1);
26         fastSortSelf(arr,lowLocation + 1,right);
27     }
28 }
29
30 //快速排序
31 void fast(int arr[], int n){
32     fastSortSelf(arr,0,n-1);
33     //记录时间
34 } 

八、各种算法效率比拼

下面是我自己写的一个算法比拼,测试数据有100-50000都有,分为最坏情况(逆序->正序)和随机情况(随机->正序),测试数据会因为机器的不同而不同,我的是win8,64, 4G,cpu2.5,欢迎大家测试

说明两点:要注意时间的得到方法,需要引入的头文件包括

1 #include <iostream>
2 #include <iomanip>
3 #include <stdlib.h>
4 #include <time.h>
1 end_time = clock();
2 程序。。。。
3 times = static_cast<double>(end_timestart_time)/CLOCKS_PER_SEC*1000;cout <<right ; cout <<setw(7) <<times<<"ms";

下面是程序代码:

  1 #include <iostream>
  2 #include <iomanip>
  3 #include <stdlib.h>
  4 #include <time.h>
  5 using namespace std;
  6
  7 clock_t start_time, end_time;
  8 int times;
  9
 10 void printfArr(int arr[], int n){
 11     for(int i = 0; i < n; i++){
 12         cout<<arr[i]<<" ";
 13     }
 14 }
 15
 16 //冒泡排序
 17 void bubbling(int arr[], int n){
 18     start_time = clock();
 19     int i,j,k;
 20     for(i = 0; i < n; i++){
 21         for(j = i+1;j < n;j++){
 22             if(arr[i] > arr[j]){
 23                 k = arr[i];
 24                 arr[i] = arr[j];
 25                 arr[j] = k;
 26             }
 27         }
 28     }
 29     end_time = clock();
 30     times = static_cast<double>(end_time-start_time)/CLOCKS_PER_SEC*1000;
 31     cout <<right ; cout <<setw(7) <<times<<"ms";
 32 }
 33
 34 //直接选择排序
 35 void directDialing(int arr[], int n){
 36     start_time = clock();
 37     int i,j,k,num;
 38     for(i = 0; i < n; i++){
 39         num = 0;
 40         for(j = 0; j < n-i; j++){
 41             if(arr[j] > arr[num]){
 42                 num = j;
 43             }
 44         }
 45         k = arr[n-i-1];
 46         arr[n-i-1] = arr[num];
 47         arr[num] = k;
 48     }
 49     end_time = clock();
 50     times = static_cast<double>(end_time-start_time)/CLOCKS_PER_SEC*1000;
 51     cout <<right ; cout <<setw(7) <<times<<"ms";
 52 }
 53
 54 //直接插入排序 (On2)
 55 void  insert(int arr[], int n){
 56     start_time = clock();
 57     int m,i,k;
 58     for(i = 1; i < n; i++){
 59         m = arr[i];
 60         for(k = i-1; k >= 0; k--){
 61             if(arr[k] > m){
 62                 arr[k+1] = arr[k];
 63             }else{
 64                 break;
 65             }
 66         }
 67         arr[k+1] = m;
 68     }
 69     end_time = clock();
 70     times = static_cast<double>(end_time-start_time)/CLOCKS_PER_SEC*1000;
 71     cout <<right ; cout <<setw(7) <<times<<"ms";
 72 }
 73
 74 //希尔排序
 75 void Heer(int arr[], int n){
 76     start_time = clock();
 77     int i,j,k,num;
 78     k = n/2;
 79     while(k > 0){
 80         for(i = k; i < n; i++){
 81             num = arr[i];
 82             for(j = i - k;j >= 0; j -= k){
 83                 if(arr[j] > num){
 84                     arr[j+k] = arr[j];
 85                 }else{
 86                     break;
 87                 }
 88             }
 89             arr[j+k] = num;
 90         }
 91         k = k/2;
 92     }
 93     end_time = clock();
 94     times = static_cast<double>(end_time-start_time)/CLOCKS_PER_SEC*1000;
 95     cout <<right ; cout <<setw(7) <<times<<"ms";
 96 }
 97
 98 //堆调整
 99 void adjust(int arr[], int n, int length){
100     int max,b;
101     while(n * 2 +1 <= length){//说明存在左节点
102         max = n * 2 + 1;
103         if(n * 2 + 2 <= length){//说明存在右节点
104             if(arr[max] < arr[n * 2 + 2]){
105                 max = n * 2 + 2; //跟新最小的值
106             }
107         }
108         if(arr[n] > arr[max]){
109             break;//顺序正确,不需要再调整
110         }else{
111             b = arr[n];
112             arr[n] = arr[max];
113             arr[max] = b;
114             n = max;
115         }
116     }
117 }
118
119 //堆排序
120 void stack(int arr[], int length){
121     start_time = clock();
122     int i,k,m = 0;
123     for(i = length/2-1; i >=0; i--){
124         adjust(arr,i,length-1);
125     }
126     //调整堆
127     for(i = length-1 ;i >= 0; i--){
128         //调整后把最后一个和第一个交换,每次调整少一个元素,依次向前
129         k = arr[i];
130         arr[i] = arr[0];
131         arr[0] = k;
132         adjust(arr,0,i-1);
133     }
134     end_time = clock();
135     times = static_cast<double>(end_time-start_time)/CLOCKS_PER_SEC*1000;
136     cout <<right ; cout <<setw(7) <<times<<"ms";
137 }
138
139 //归并排序合并函数
140 void mergeSoft(int a[], int first, int mid, int last, int temp[]){
141     int i = first, j = mid + 1;
142     int m = mid,   n = last;
143     int k = 0;
144     while (i <= m && j <= n){
145         if (a[i] <= a[j]){
146             temp[k++] = a[i++];
147         }else{
148             temp[k++] = a[j++];
149         }
150     }
151     while (i <= m){
152         temp[k++] = a[i++];
153     }
154     while (j <= n){
155         temp[k++] = a[j++];
156     }
157
158     for (i = 0; i < k; i++){
159         a[first + i] = temp[i];
160     }
161 }
162
163 //归并排序递归拆分函数
164 void mergerSelf(int arr[], int left, int right, int arrTmp[]){
165     if(left < right){
166         int center = (left + right)/2;
167         mergerSelf(arr, left, center, arrTmp);
168         mergerSelf(arr, center+1, right, arrTmp);
169         mergeSoft(arr, left, center, right, arrTmp);
170     }
171 }
172 //归并排序
173 void merger(int arr[], int n){
174     start_time = clock();
175     int *arrTmp = new int[n];
176     mergerSelf(arr, 0, n - 1, arrTmp);
177     delete[] arrTmp;
178     //记录时间
179     end_time = clock();
180     times = static_cast<double>(end_time-start_time)/CLOCKS_PER_SEC*1000;
181     cout <<right ; cout <<setw(7) <<times<<"ms";
182 }
183
184 //快速排序的元素移动
185 int fastSort(int arr[], int left, int right){
186     int center = (left+right)/2;
187     int num = arr[center]; //记录中枢点的位置,这里选择最左边点当做中枢点
188     while(left < right){
189         //比枢纽小的移动到左边
190         while(left < right && arr[right] >= num){
191             right--; //一直到有一个元素小于所选关键中枢为止
192         }
193         arr[left] = arr[right];
194
195         while(left < right && arr[left] <= num){
196             left++; //一直到有一个元素大于所选关键中枢为止
197         }
198         arr[right] = arr[left]; //关键字入列
199     }
200     arr[left] = num;
201     return left;
202 }
203
204 //快速排序递归划分
205 int fastSortSelf(int arr[], int left, int right){
206     if(left < right){
207         int lowLocation = fastSort(arr,left,right); //第一个指针的位置
208         fastSortSelf(arr,left,lowLocation - 1);
209         fastSortSelf(arr,lowLocation + 1,right);
210     }
211 }
212
213 //快速排序
214 void fast(int arr[], int n){
215     start_time = clock();
216     fastSortSelf(arr,0,n-1);
217     //记录时间
218     end_time = clock();
219     times = static_cast<double>(end_time-start_time)/CLOCKS_PER_SEC*1000;
220     cout <<right ; cout <<setw(7) <<times<<"ms";
221 }
222
223 int main(){
224     cout<<"\n****************************整数最坏(逆序)测试***********************\n\n";
225     cout<<"数据量       冒泡      选择     插入      希尔     堆     归并     快速\n";
226     int size;   //记录每个测试数量
227     int tmpNum; //记录临时数
228     int arr1[8] = {49,38,65,97,76,13,27,49};
229     //测试数据的各个范围
230     int nums[6] = {100,1000,5000,10000,30000,50000};
231     /*
232     printfArr(arr1,8);
233     printf("\n");
234     fast(arr1,8);
235     printfArr(arr1,8);*/
236
237     for(int p = 0; p < 6; p++){
238         size = nums[p];
239         int arrs1[size],arrs2[size],arrs3[size],arrs4[size],arrs5[size],arrs6[size],arrs7[size];
240         cout<<left; cout <<"n="<<setw(6)<<size;
241         //产生有序数
242         for(int m = 0; m < size; m++){
243             int tmpNum = size - m;
244             arrs1[m] = tmpNum;
245             arrs2[m] = tmpNum;
246             arrs3[m] = tmpNum;
247             arrs4[m] = tmpNum;
248             arrs5[m] = tmpNum;
249             arrs6[m] = tmpNum;
250             arrs7[m] = tmpNum;
251         }
252         bubbling(arrs1,size);     //冒泡排序法
253         directDialing(arrs2,size);//直接选择排序
254         insert(arrs3,size);       //直接插入排序
255         Heer(arrs4,size);         //希尔排序
256         stack(arrs5,size);        //堆排序
257         merger(arrs6,size);       //归并排序
258         fast(arrs7,size);         //快速排序
259         cout<<"\n";
260     }
261
262     //*****************随机数测试法******************
263     int number;
264     int nlong; //数据量
265     cout<<"\n******************************随机数测试*******************************\n\n";
266     cout<<"数据量       冒泡      选择     插入      希尔     堆     归并     快速\n";
267     for(int r = 0; r < 6; r++){
268         size = nums[r];
269         int rands1[size],rands2[size],rands3[size],rands4[size],rands5[size],rands6[size],rands7[size];
270         //产生测试随机数
271         srand((unsigned) time(NULL));
272         for (int rd = 0; rd < size; rd++){
273             tmpNum = rand() % size;
274             rands1[rd] = tmpNum;
275             rands2[rd] = tmpNum;
276             rands3[rd] = tmpNum;
277             rands4[rd] = tmpNum;
278             rands5[rd] = tmpNum;
279             rands6[rd] = tmpNum;
280             rands7[rd] = tmpNum;
281         }
282         //输出测试数据量
283         cout<<left; cout <<"n="<<setw(6)<<size;
284         //依次调用各个排序函数
285         bubbling(rands1,size);     //冒泡排序法
286         directDialing(rands2,size);//直接选择排序
287         insert(rands3,size);       //直接插入排序
288         Heer(rands4,size);         //希尔排序
289         stack(rands5,size);        //堆排序
290         merger(rands6,size);       //归并排序
291         fast(rands7,size);         //快速排序
292         cout<<"\n";
293     }
294 }

运行结果如图:没有优化快速排序(逆序中枢选择第一个)前的效果,n=30000的时候递归太深出错,只能把n=10000。

运行结果如图:优化后快速排序(逆序中枢选择第一个最后一个的中间值)的效果,n=50000的时候,只用了4ms

  因为时间关系,写的不全,比如:算法具体的时间复杂度计算方法没有详细写出(有时间会补充完整),还有就是快速排序的改进程序,归并排序的合并细节没有说。反正是写每个程序都遇到很多问题,所有程序都可以编译运行,希望大家提出宝贵意见。

  转载请注明出处!

时间: 2024-10-11 06:54:04

经典的排序算法的相关文章

算法基础——经典八大排序算法的Java及Python实现

概述 八大排序算法不用多说了,程序员算法基础必须要掌握的,现在总结一下加深记忆.下图是这八大排序算法的分类.名称.时间空间复杂度,以及稳定性. 代码 以下是经典八大排序算法的Java及Python代码,都是基于经典算法书籍<算法导论>里的伪代码实现的,我在关键语句部分附上了注释. 按照上图中的顺序分别介绍八大排序算法的实现(升序),前面是Java,后面是Python.Java的排序函数写在了一个类里,Python的排序函数则直接写出来了. 直接插入排序 public class InsertS

C语言——几种经典的排序算法

经典排序之冒泡排序 #define SIZE 5 int main() { int a[SIZE] = {0}; //循环输入 for(int i=0;i<SIZE;i++) { scanf("%d",&a[i]); } //冒泡排序核心 for(int i=0;i<SIZE-1;i++) { for(int j=0;j<SIZE-1-i;j++) { if(a[j]>a[j+1]) { int temp = a[j]; a[j] = a[j+1]; a

经典的排序算法java实现版

1 /** 2 * 3 * @author yuzhiping 4 * @version 1.0 5 * 功能说明:计算机领域经典的算法 6 * 7 */ 8 public class sortAlgorithm<T extends Comparable<T>> { 9 10 //交换索引i和索引j的值 11 private void swap(T [] data ,int i,int j){ 12 T tmp; 13 tmp=data[i]; 14 data[i]=data[j]

经典的排序算法学习(java实现)

1.算法思想 通过一躺排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小, 然后再按次方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列. 2.算法图解 3.实现代码 static void quikSort(int n[], int left, int right){ int temp; //定义一个临时的变量 if(left < right){ temp = partition(n, left, right);//

JS实现常用排序算法—经典的轮子值得再造

关于排序算法的博客何止千千万了,也不多一个轮子,那我就斗胆粗制滥造个轮子吧!下面的排序算法未作说明默认是从小到大排序. 1.快速排序2.归并排序3.冒泡排序4.选择排序(简单选择排序)5.插入排序(直接插入排序)6.希尔排序二分查找 1.快速排序 为什么把快排放在最前面呢,因为传说Chrome中数组的sort方法默认采用的就是快排. 算法思想: (1)在数据集之中,选择一个元素作为"基准"(pivot). (2)所有小于"基准"的元素,都移到"基准&quo

C/C++中的经典排序算法总结

C/C++中的经典排序算法总结 在C/C++中,有一些经典的排序算法,例如:冒泡排序.鸡尾酒排序或双向冒泡排序(改进的冒泡排序).选择排序.直接插入排序.归并排序.快速排序.希尔排序和堆排序等等.下面对这些排序算法进行一一解析并给出示例代码以共享之. 1.冒泡排序 冒泡排序是最基本的排序算法,之所以称之为冒泡排序是因为在冒泡排序的过程中总是大数往前放,小数往后放,相当于气泡上升. 冒泡排序的基本原理是:依次比较相邻的两个数,将大数放在前面,小数放在后面. 影响冒泡排序算法性能的主要部分就是循环和

九种经典排序算法详解(冒泡排序,插入排序,选择排序,快速排序,归并排序,堆排序,计数排序,桶排序,基数排序)

综述 最近复习了各种排序算法,记录了一下学习总结和心得,希望对大家能有所帮助.本文介绍了冒泡排序.插入排序.选择排序.快速排序.归并排序.堆排序.计数排序.桶排序.基数排序9种经典的排序算法.针对每种排序算法分析了算法的主要思路,每个算法都附上了伪代码和C++实现. 算法分类 原地排序(in-place):没有使用辅助数据结构来存储中间结果的排序**算法. 非原地排序(not-in-place / out-of-place):使用了辅助数据结构来存储中间结果的排序算法 稳定排序:数列值(key)

经典排序算法 — C# 版(上)

提起排序,与我们的息息相关,平时开发的代码少不了排序. 经典的排序算法又非常多,我们怎么评价一个排序算法的好坏呢? 其实可以这样想,要细致的比较排序算法好坏,那我们就从多方面尽可能详细的对比 一.效率方面 1.排序算法的执行效率:最好.最坏.平均 2. 我们之前舍弃的时间复杂度的系数.常量.低阶,在这里需要拿回来 3.排序,免不了比较和移动 二.内存消耗方面 没错就是 算法的空间复杂度,不过对于排序的空间复杂度来说,又赋予了新的名词 — 原地排序. 顾名思义是 原地排序的肯定是消耗内存少,反之需

Python实现各种排序算法的代码示例总结

Python实现各种排序算法的代码示例总结 作者:Donald Knuth 字体:[增加 减小] 类型:转载 时间:2015-12-11我要评论 这篇文章主要介绍了Python实现各种排序算法的代码示例总结,其实Python是非常好的算法入门学习时的配套高级语言,需要的朋友可以参考下 在Python实践中,我们往往遇到排序问题,比如在对搜索结果打分的排序(没有排序就没有Google等搜索引擎的存在),当然,这样的例子数不胜数.<数据结构>也会花大量篇幅讲解排序.之前一段时间,由于需要,我复习了