三種常用又簡單的排序算法

2021-11-09

關鍵字:桶排序


 

1、桶排序

 

桶排序一般用於對一組知道上下限的整數序列中。

 

因爲桶排序的核心原理就是全覆蓋式計數,爲整個區間每一個數創建一個計數器,遍歷待排序序列,爲每一個出現的數計數加1,最後根據需要從頭至尾或從尾至頭打印區間計數。

 

舉個例子,假設要爲一個班級的學生數學考試分數做個排序。

 

已知分數範圍爲 0 ~ 100,是一個知道上下限的區間。現有分數:52、70、41、99、64、64。創建一個101個長度的數組score,第0號表示成績爲0分的人數,第1號爲成績爲1分的人數,第101號爲成績爲100分的人數。遍歷待排序序列,第一個成績爲52,則將score數組第53號的值加1,第二個成績爲70,則將score數組第71號的值加1,依此類推直至結尾。當我們需要獲取排序結果時,例如想要將成績從高到低打印出來,則可以逆遍歷score數組,當其計數值大於0時則打印出來即可。

 

桶排序的優點就是速度快,缺點是對序列元素有要求,且其空間佔用會隨着序列規模的增大而增大。

 

以下是一個桶排序的C語言實例:

#include <stdio.h>
#include <string.h>

int main()
{
    //待排序序列
    const char scores[] = {71, 100, 7, 40, 88, 100, 91, 96, 71, 84, 60, 40, 71, 0, 1, 0};
    //序列上下限爲 0 ~ 100 的整數。
    char score_bucket[101];
    
    memset(&score_bucket, 0, 101);
    
    int count = sizeof(scores) / sizeof(char);
    int i;
    for(i = 0; i < count; i++)
    {
        score_bucket[scores[i]] += 1;
    }
    
    //打印結果(遞減順序)
    int j = 0;
    for(i = 100; i >= 0; i--)
    {
        if(score_bucket[i])
        {
            for(j = 0; j < score_bucket[i]; j++)
            {
                printf("%d,", i);
            }
        }
    }
    printf("\n");
    return 0;
}

 

 

2、冒泡排序

 

冒泡排序對空間的要求非常小,時間複雜度爲O(n(n+1))約等於O(n2)。

 

其核心原理是從頭到尾兩兩比較,將順序不正確的兩個數互換一下位置,如此一趟下來能將符合要求的最大或最小數挪到原數據的最末位,然後再重複一次操作,只不過這次因爲最末一位已經是正確的順序了,第二輪比較就只到第n-1位了。如此循環直至原數組中已排序序列數量漲至n-1個爲止即表示整個排序已完成。

 

以下是冒泡排序的C語言實例:

#include <stdio.h>

int main()
{
    //待排序序列
    char scores[] = {71, 100, 7, 40, 88, 100, 91, 96, 71, 84, 60, 40, 71, 0, 1, 0};
    
    int count = sizeof(scores) / sizeof(char); //序列長度
    int i;
    int j;
    int loop = count - 1; //最後一個元素不用參與到排序中。
    char tmp;
    for(i = 0; i < loop; i++)
    {
        for(j = 0; j < loop - i; j++)
        {
            if(scores[j] > scores[j + 1])
            {
                tmp = scores[j];
                scores[j] = scores[j+1];
                scores[j+1] = tmp;
            }
        }
    }
    
    //print
    for(i = 0; i < count; i++)
    {
        printf("%d,", scores[i]);
    }
    printf("\n");
    
    return 0;
}

 

 

3、快速排序

 

桶排序速度快,但是空間消耗大。冒泡排序空間消耗小,但是速度慢。快速排序則可以一定程度上兼顧空間和時間消耗,它在數值比較上採用與冒泡排序類似的兩兩交換法,在空間消耗上採用函數遞歸調用,雖然遞歸調用函數也會隨着序列規模上升而增長,但相對來講空間佔用還是比桶排序好很多。

 

快速排序的核心是選中一個基準數,在遞增排序的需求下將所有大於基準數的元素放在基準數右邊,將所有小於基準數的元素放在其左邊。然後對分別對左半子序列和右半子序列應用同樣的算法,直至子序列只剩一個元素爲止。通常爲了方便,基準數選第1個或最後一個。

 

快速排序的實現原理是將待排序序列第1個元素作爲基準數,分別從序列兩端收縮遍歷取值。如果基準數選的是第1個,則首先從右端收縮,若基準數選的是最後一個,則首先從左端收縮。當從右端開始收縮時,一直收縮直到遇到一個數小於基準數爲止,然後收縮左端,直到找到一個數大於基準數爲止。然後直接交換這兩個數,之後再重複兩端的收縮過程,直至兩端收縮碰撞爲止。收縮碰撞後將碰撞值直接與基準數對調,之後便可對生成的兩個子序列再分別應用此算法,直至子序列只有一個元素爲止。

 

以下是一個C語言版的實例:

#include <stdio.h>static void quick_sort(char nums[], int start, int end)
{
    char tmp;
    int i = start;
    int j = end;
    if(start >= end)
        return;

    while(1)
    {
        if(i == j)
        {
            //直接跟基數交換
            tmp = nums[start];
            nums[start] = nums[j];
            nums[j] = tmp;
            
            //迭代左邊的
            if(start < j)
            {
                quick_sort(nums, start, j - 1);
            }
            
            //迭代右邊的
            if(end > i)
            {
                quick_sort(nums, i + 1, end);
            }
            
            //排序完成
            break;
        }
        else
        {
            //j先動。
            if(nums[j] < nums[start])
            {
                //輪到i動
                if(nums[i] > nums[start])
                {
                    if(i != j)
                    {
                        //可以交換
                        tmp = nums[j];
                        nums[j] = nums[i];
                        nums[i] = tmp;
                    }
                }
                else
                {
                    i++;
                }
            }
            else
            {
                j--;
            }
        }
    }
}

int main()
{
    //待排序序列
    char nums[] = {6, 1, 2, 7, 9, 3, 4, 5, 10, 8};
    
    int i;
    quick_sort(nums, 0, 9);
    
    for(i = 0; i < 10; i++)
    {
        printf("%d, ", nums[i]);
    }
    printf("\n");
    
    return 0;
}

 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章