排序(冒泡排序、快速排序)


基本排序分類圖:

關於排序的穩定性

在待排序的記錄序列中,存在多個具有相同的關鍵字的記錄,若經過排序,這些記錄的相對次序保持不變,即在原序列中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),這個一個非常高的時間復雜度

冒泡排序的優化:
當第i次冒泡排序一次都沒有交換,說明該序列已經變成有序的了,這樣就減少了比較次數(注意是比較次數,不是交換次數),代碼如下:
 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)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM