淺談排序算法
桶排序(BucketSort)
排序過程:
假如我們現在要排序的一組數為:5,3,5,2,8. 這組數都在0-10的範圍之內。這個時候,我們可以拿11個桶,標號為0,1,2,3......10。也就是定義長度為11的數組。現在我們來遍歷這些數字,第一個數字為5,那麽給第五號桶中插一個小紅旗,第二個數字為3,給第三號桶插一個小紅旗,以此類推。其中,插入一個小紅旗代表的是數組元素+1(開始初始化數組元素都為0),遍歷完成之後,可以查看所有桶中小紅旗的數量,也就是數組中存儲元素的個數。發現a[5] = 2,表示5這個數字出現了兩次。從0號桶開始,a[0] = 0,表示沒有0這個數字,依次遍歷到 10就結束了,也就把這些數字從小到大排好了。
當然,如果需要對0-100之間的數進行排序,就需要101個桶,桶的作用就是一個標誌。
把標誌數組起個名字為book。
寫代碼思路:
1.把book數組初始化,也就是把裏面都寫成0
2.把需要排序的一組數放在一個數組裏面。
3.循環放入的過程中,對book[i]++。
4.依次判斷編號為0~10之間的桶中小紅旗的個數,即book[i]的值
5.有n個小紅旗(book[i] = n)就打印n次這個數。
代碼如下:
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> //桶排序:對於0~100之間的數排序的時候,這時候需要有101個桶(數組長度為101的數組),插個小旗(加一)用來標記每個數出現的次數。 //然後,看這些桶中(遍歷這個數組)小旗的數目(多少個1),有多少只旗(多少個1)就(打印多少次這個數)表示這個桶的標號(數)出現了幾次; int main(){ int book[11];//先拿11個桶,0~10之間的數進行排序。 int t = 0; for (int i = 0; i < 11; i++) { book[i] = 0; //初始化數組(把桶清空) } int n = 0;//要對n個數排序 printf("請輸入需要對幾個數進行排序:"); scanf("%d", &n);//輸入n個需要排序的數 for (int i = 0; i < n; i++) { scanf("%d", &t);//把數輸入到t中 book[t]++; //進行計數,第t個桶插加一個旗 } for (int i = 0; i < 11; i++) //依此判斷編號為0~10的桶,(從小到大)。 { for (int j = 0; j < book[i]; j++) //出現幾個就打印幾次 { printf("%d ", i); } } system("pause"); return 0; }
桶排序這種方法存在明顯的問題就是占用了太多的空間。假如需要排列的數中有一個10000,那麽最少得定義數組長度為10000的數組。
冒泡排序(BubbleSort)
冒泡排序的思想:
每次比較兩個相鄰的兩個數,如果它們的順序是錯誤的(要求是從小到大,此時的序列是前面的比後面的大)就把它們進行交換。如果有n個數進行排序,要進行n-1趟操作,而每一趟比較都要從第一個數開始,兩兩進行比較,將較大的數,放在後面。重復此步驟直到最後一個尚未歸位的數,已經歸位的數則無需比較。
排序過程:
假設我們現在對12,35,99,18,76這幾個數由大到小進行排序。也就是前面的數比後面的大。
把1個位歸位成為跑一趟
第一趟:
首先,比較12和35,發現12小於35,那麽要交換這兩個數。得到35,12,99,18,76.
然後,繼續比較第二位和第三位,發現12比99小,交換得到,35,99,12,18,76.
接著,比較第三位和第四位,發現12小於18,交換得到,35,99,18,12,76.
最後,比較第四位和第五位,發現12小於76,交換得到,35,99,18,76,12.
四次比較後,發現最小的數12已經歸位。然而這還只是把1個數歸位了。接下來歸位剩余的四個數。
第二趟:
現在歸位第次小的數,跟第一趟過程差不多。
首先,比較35和99,發現小,那麽交換之,得到99,35,18,76,12.
···
因為12已經歸位了,所以沒有必要比較第四位和第五位的大小。
...
這趟完成後,次小的數也已經歸位了
第三趟:
···
第四趟:
···
直到得到最後的序列
排序的原理:
如果有n 個數進行排序,只需將n-1 個數歸位,也就是說要進行n-1 趟操作。而“每一趟”都需要從第1 位開始進行相鄰兩個數的比較,將較小的一個數放在後面,比較完畢後向後挪一位繼續比較下面兩個相鄰數的大小,重復此步驟,直到最後一個尚未歸位的數,已經歸位的數則無需再進行比較.
代碼描述:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
int arr[100];
int n = 0;//需要對n個數進行排序(從小到大)
int temp = 0;
printf("請輸入需要對幾個數進行排序:");
scanf("%d", &n);
for (int i = 0; i < n; i++){
scanf("%d", &arr[i]);
}
//冒泡排序:
//先分開寫:
////第一趟:
//for (int i = 0; i < n -1; i++)
//{
// if (arr[i]>arr[i + 1]){
// temp = arr[i];
// arr[i] = arr[i + 1];
// arr[i + 1] = temp;
// }
//}
////第二趟:
//for (int i = 0; i < n - 2; i++)
//{
// if (arr[i]>arr[i + 1]){
// temp = arr[i];
// arr[i] = arr[i + 1];
// arr[i + 1] = temp;
// }
//}
////需要 n-1 趟
////...
//合並起來:
for (int times = 1; times <= n - 1; times++){
for (int i = 0; i < n - times; i++){
if (arr[i]>arr[i + 1]){
temp = arr[i]; //交換的過程
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
}
//打印排好序的數組
for (int i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
system("pause");
return 0;
}
快速排序(QuickSort)
快速排序的過程:
我們對需要排序的序列6 1 2 7 9 3 4 5 10 8 ,首先在這組數中找一個基準數,我們就把第一個數6作為基準數,接下來,需要將這個序列中所有比基準數大的數放在6 的右邊,比基準數小的數放在6 的左邊。
分別從初始序列“6 1 2 7 9 3 4 5 10 8”兩端開始“探測”。先從右往左找一個小於6 的數,再從左往右找一個大於6 的數,然後交換它們。這裏可以用兩個 變量i 和j,分別指向序列最左邊和最右邊。
其實哨兵j 的使命就是要找小於基準數的數,而哨兵i 的使命就是要找大於基準數的數,直到i 和j 碰頭為止。
此時,基準數6已經歸位,左邊的序列是3 1 2 5 4 右邊的是 9 7 10 8 ,接下來分別處理這兩個序列。處理方法跟上述類似。
其實快速排序的每一輪處理都是將這一輪的基準數歸位,直到所有的數歸位為止。
代碼流程:
1.將需要排序的序列放在一個數組中調用排序算法
2.設置哨兵i和j和基準數。
3.哨兵j先走,哨兵j找出小於基準數的值,哨兵i找出大於基準數的數。
4.若i和j沒要到則交換這兩個數。反之,將基準數歸位,即交換arr[i]和基準數。
5.一輪完成後,剩下的就是將左邊後右邊的序列進行遞歸調用快速排序方法,直到將所有子序列排列完成為止。
6.輸出排好序的數組
代碼實現:
#include <stdio.h>
#include <stdlib.h>
//分別從初始序列“6 1 2 7 9 3 4 5 10 8”兩端開始“探測”。先從右往左找一個小於6 的數,再從左往右找一個大於6 的數,然後交換它們。這裏可以用兩個
//變量i 和j,分別指向序列最左邊和最右邊。
//其實哨兵j 的使命就是要找小於基準數的數,而哨兵i 的使命就是要找大於基準數的數,直到i 和j 碰頭為止。
/*快速排序的每一輪處理其實就是將這
一輪的基準數歸位,直到所有的數都歸位為止,排序就結束了。
*/
void qSort(int left, int right,int arr[])
{
int i, j, temp, basic;
if (left > right)
return;
i = left; //哨兵i和j分別指向left和right
j = right;
basic = arr[left];//基準數
while (i != j){
//哨兵j先走,要有順序,因為此處設置的基準數是最左邊的數
while (arr[j] >= basic && i < j){//哨兵j的使命就是找出小於基準數的數
j--;
}
while (arr[i] <= basic && i < j){//哨兵i的使命就是找出大於基準數的數
i++;
}
//i和j沒遇到,交換著兩個值
if (i < j){
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
//i和j相遇,將基準值歸位.
//上面有了代碼 basic = arr[left] ,basic這時候就是一個臨時變量
arr[left] = arr[i];
arr[i] = basic;
//把基準值歸位後就進行 基準值左邊和基準值右邊部分 的 遞歸排序
qSort(left, i - 1, arr);
qSort(i + 1, right, arr);
}
int main(){
int arr[] = {6,1,2,7,9,3,4,5,10,8};
qSort(0,9,arr);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
system("pause");
return 0;
}
參考書
《啊哈!算法》
淺談排序算法