1. 程式人生 > >淺談排序算法

淺談排序算法

代碼 can 大小 print 指向 pau 用兩個 代碼實現 emp

桶排序(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;
}

參考書

《啊哈!算法》

淺談排序算法