基本排序分類圖:
關於排序的穩定性
在待排序的記錄序列中,存在多個具有相同的關鍵字的記錄,若經過排序,這些記錄的相對次序保持不變,即在原序列中r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,則稱這種排序算法是穩定的;否則稱為不穩定的。
一、 冒泡排序
冒泡排序的基本思想:每次比較兩個相鄰的元素,如果它們的順序錯誤就把他們交換過來
冒泡排序的原理:每一趟只能確定將一個數歸位,如果有n個數進行排序,只需將n-1個數歸位,也就是說要進行n-1趟操作,而每一趟都需要從第1位開始進行相鄰兩個數的比較
1 #include <stdio.h>
2 #define MAX 7
3
4 int main(void) 5 { 6 int i, j, t; 7 int a[MAX] = {1, 5, 3, 7, 6, 4, 2}; 8
9 //冒泡排序核心部分
10 for (i = 0; i < MAX - 1; i++) //n個數排序只需要n-1趟
11 { 12 for (j = 0;j < MAX - i; j++) //每一趟比較到n-i結束
13 { 14 if (a[j] < a[j + 1])//降序排列
15 { 16 t = a[j]; 17 a[j] = a[j + 1]; 18 a[j + 1] = t; 19
20 } 21 } 22 } 23 for (i = 0; i < MAX; i++) 24 { 25 printf("%d ", a[i]); 26 } 27
28 return 0; 29 }
冒泡排序的核心部分是雙重嵌套循環,冒泡排序的時間復雜度是O(N2),這個一個非常高的時間復雜度
1 #include <stdio.h>
2 #define MAX 7
3
4 int main(void) 5 { 6 int i, j, t; 7 int flag = 0; 8 int n = 0; 9 int a[MAX] = {1, 5, 3, 7, 6, 4, 2}; 10
11 //冒泡排序核心部分
12 for (i = 0; i < MAX - 1; i++) //n個數排序只需要n-1趟
13 { 14 flag = 0; 15 for (j = 0;j < MAX - i; j++) //每一趟比較到n-i結束
16 { 17 n++; 18 if (a[j] < a[j + 1]) 19 { 20 t = a[j]; 21 a[j] = a[j + 1]; 22 a[j + 1] = t; 23 flag = 1; 24 } 25 } 26 if (flag == 0) /* 一次交換都沒有,說明已經是有序序列*/
27 { 28 break; /* 跳出整個循環 */
29 } 30 } 31 for (i = 0; i < MAX; i++) 32 { 33 printf("%d ", a[i]); 34 } 35 printf("\n比較次數%d\n", n); 36
37 return 0; 38 }
優化前:
優化后:
二、快速排序
快速排序是基於二分的思想,對冒泡排序的一種改進
快速排序基本思想:
通過一趟排序將要排序的數據分割成獨立的兩部分:分割點左邊都是比它小的數,右邊都是比它大的數。然后再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。
快速排序原理:第一步:設置兩個指針left和right分別指向數組的頭部和尾部,並且以頭部的元素(6)為基准數
第二步:right指針先往左移動,找到小於基准數的元素就停下,然后移動left指針(想一下為什么是right先移動,不能是left先移動)
第三步:left指針往左移動,找到大於基准數的元素就停下,然后交換right和left指針所值元素的值
重復第二、三步,直到兩個指針left和right重合
第四步:兩個指針重合后將基准數(6)與兩個指針指向的元素值(3)交換
到這時,第一輪排序結束,此時以基准數(6)為分界點,(6)左邊的數都小於等於6,(6)右邊的數都大於等於6,現在我們已經將原來的序列以(6)為分界點拆成了兩個序列
左邊的序列是3 1 2 5 4,右邊的序列是9 7 10 8,接下來分別處理這兩個序列,因為處理方法與上圖相同,下面就不上圖了(摸個魚)
先處理3 1 2 5 4,以(3)為基准數,處理后結果為2 1 3 5 4
再處理(3)左邊的數2 1,以(2)為基准數,處理后為1 2
再處理(3)右邊的數5 4,以(5)為基准數,處理后為4 5
現在的序列為1 2 3 4 5 6 9 7 10 8,現在對9 7 10 8進行處理
因為處理方式與上面相同這里不再贅述,處理結果為7 8 9 10
最終序列為1 2 3 4 5 6 7 8 9 10,到此排序完全結束(快速排序的每一輪處理其實就是將這一輪的基准數歸位,直到所有的數都歸位為止)
1 #include <stdio.h>
2 void quicksort(int left, int right, int *a); 3
4 #define N 7
5 int main(void) 6 { 7 int i; 8 int a[N] = {5, 1, 7, 2, 4, 3, 6}; 9
10 quicksort(0, N-1, a); 11
12 for(i = 0; i < N; i++) 13 { 14 printf("%d ", a[i]); 15 } 16
17 return 0; 18 } 19 void quicksort(int left, int right, int *a) 20 { 21 int i, j, t, temp; 22 if (left > right) //基線情況
23 { 24 return; 25 } 26
27 temp = a[left]; //存入基准數
28 i = left; 29 j = right; 30 while (i != j) 31 { 32 //先從右往左找
33 while (a[j] >= temp && j>i) 34 { 35 j--; 36 } 37 //從左往右找
38 while (a[i] <= temp && j>i) 39 { 40 i++; 41 } 42
43 if (i < j) 44 { 45 t = a[i]; 46 a[i] = a[j]; 47 a[j] = t; 48 } 49 } 50 a[left] = a[i]; //基准數歸位
51 a[i] = temp; 52
53 quicksort(left, i - 1, a); 54 quicksort(i + 1, right, a); 55
56 return; 57 }
快速排序在最壞的情況下,仍可能是相鄰的兩個數進行交換,因此快速排序最差時間復雜度和冒泡排序是一樣的,都是O(N2),它的平均時間復雜度為O(NlogN)