簡單的排序算法

常見的排序算法有以下7種:

  • 冒泡排序
  • 選擇排序
  • 插入排序
  • 堆排序
  • 希爾排序
  • 歸併排序
  • 快速排序

我們通常說的排序算法往往指的是內部排序算法,即數據記錄在內存中進行排序

  • 排序算法大體可分爲兩種:
    1.一種是比較排序,時間複雜度爲O(nlogn)~O(n^2),主要有冒泡排序,選擇排序,插入排序,歸併排序,堆排序,快速排序等
    2.另一種是非比較排序,時間複雜度可以達到O(n)
    除了排序算法的時間複雜度是我們比較關心的,還有一個就是排序算法的穩定性。
    排序算法穩定性的簡單形式化定義爲:如果Ai = Aj,排序前Ai在Aj之前,排序後Ai還在Aj之前,則稱這種排序算法是穩定的。

接下來先介紹4種排序算法:

1.冒泡排序(這裏可以從前向後冒泡,也可以從後向前冒泡)

(1)比較兩個相鄰元素,如果前一個比後一個大,就將兩個元素進行交換
(2)依次向後進行比較操作,一趟冒泡下來,最後一個元素爲當前這組數中的最大值
(3)繼續再進行如上操作,進行第二次冒泡,但是最後一個元素不用進行比較,因爲已經有序,以此類推第三次冒泡時,最後兩個元素不需要比較
(4)重複上述操作,進行 元素個數-1 次冒泡,排序完成
如圖是對一組數進行一趟冒泡排序的結果,按照此方法繼續進行冒泡,就可以得到排序結果
這裏寫圖片描述
下面是代碼實現:

void BubbleSort(int array[],size_t size)
{
    if(size <= 1)
    {
        return;
    }
    //[0,i)表示有序區間
    //[i,size)表示待排序區間
    size_t i = 0;
    for(;i < size ;++i)
    {
        //這裏採取的是從後向前冒泡
        size_t j = size -1;
        for(;j > i;--j)
        {
            if(array[j] < array[j-1] )
            {
                Swap(&array[j],&array[j-1]);
            }
        }
    }
    return;
}
2.選擇排序

(1)第一次排序,第一個元素和後面的元素依次比較大小,如果第一個元素大的話就交換兩個元素的位置,保證一次排序後第一個元素爲這組數的最小值
(2)第二次排序,第二個元素和後面的元素依次比較大小,如果第二個元素大的話就交換兩個元素的位置,保證第二次排序後第二個元素爲剩下數中的最小值
(3)重複上述操作,就可以將該組數進行排序
如圖是進行一次選擇排序的結果,按照此方法繼續進行選擇排序就可以得到排序結果
這裏寫圖片描述
下面是代碼實現:

void SelectSort(int array[],size_t size)
{
    if(size <= 1)
    {
        return;
    }
    //[0,i)表示有序區間
    //[i,size)表示待排序區間
    size_t i = 0;
    for(; i < size ;++i)
    {
        size_t j = i + 1;
        for(; j < size;++j)
        {
            if(array[i] > array[j])
            {
                Swap(&array[i],&array[j]);
            }
        }
    }
    return;
}
3.插入排序

(1)從第一個元素,該元素可以被認爲已經有序
(2)取出下一個元素,先保存起來,在已經排序的元素序列中從後向前比較
(3)如果當前元素大於要插入的元素,就把當前元素向後移
(4)重複步驟3,直到找到已排序的元素小於或等於新元素的位置
(5)將新元素插入到該位置
(6)重複上述操作,即可完成排序
如圖是進行插入排序的過程
這裏寫圖片描述
下面是代碼實現:

void InsertSort(int array[],size_t size)
{
    if(size <= 1)
    {
        return;
    }
    //[0,i)表示有序區間
    //[i,size)表示待排序區間
    //插入排序是把前面的有序區間當做一個線性表
    //然後把 i_value 的值插入到線性表中合適的位置上
    size_t i = 1;
    for(; i < size;++i)
    {
        //此時存起來的意義是爲了後面的搬運
        //一旦array[i]元素被單獨保存起來了
        //array[i]數值就可以被修改了
        int i_value = array[i];
        //此時cur是輔助我們進行搬運的下標
        //從後向前遍歷,找到合適的位置放 i_value 的位置
        size_t cur = i;
        for(;cur > 0;--cur)
        {
            //此處我們的初始情況就是拿線性表的最後一個元素和 i_value 比較
            //因此 array[cur-1]這裏的 cur 取決於 cur 的初始位置
            if(array[cur-1] > i_value)
            {
                //進行搬運
                array[cur] = array[cur-1];
            }
            else
            {
                //說明已經找到了合適的位置
                break;
            }
        }
        //然後把i位置的元素插入到線性表的合適的位置上
        array[cur] = i_value;
    }
    return;
}
4.堆排序

(1)基於數組建立一個堆(如果是升序就建立大堆)
(2)循環的刪除堆頂元素,將所有的元素都刪除完畢,排序完成
(3)每次刪除堆頂元素後,都對堆進行調整,這裏有兩種方法

方法一:把新元素放到數組的末尾,進行上浮式調整(從前往後遍歷)
方法二:採用下沉式的調整(從後往前遍歷)
起始位置就是堆的從後往前遍歷的第一個非葉子節點
這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

如上給定一個數組建立一個堆已經完成,剩下的就是對堆進行刪除堆頂元素,然後下沉式調整
下面是代碼實現:

void AdjustDown(int array[],size_t size,size_t index)
{
    size_t parent = index;
    size_t child = 2 * index + 1 ;
    while(child < size)
    {
        if(child + 1 < size && array[child] < array[child+1])
        {
            child = child + 1;
        }
        if(array[parent] < array[child])
        {
            Swap(&array[parent],&array[child]);
        }
        parent = child;
        child = 2 * parent + 1;
    }
    return;
}
void HeapCreate(int array[],size_t size)
{
    if(size <= 1)
    {
        return;
    }
    size_t i = (size -1 -1) / 2;
    for(;i > 0;--i)
    {
        AdjustDown(array,size,i);
    }
    AdjustDown(array,size,0);
    return;
}
void HeapPop(int array[],size_t heap_size)
{
    if(heap_size <= 1)
    {
        return;
    }
    Swap(&array[0],&array[heap_size-1]);
    AdjustDown(array,heap_size - 1,0);
}
void HeapSort(int array[],size_t size)
{
    if(size <= 1)
    {
        return;
    }
    //1.基於數組建立一個堆(如果是升序,就建立大堆)
    HeapCreate(array,size);
    //2.循環的刪除堆頂元素,將所有的元素都刪除完畢,排序完成
    size_t i = 0;
    for(;i < size;++i)
    {
        //第二個參數表示數組中哪部分區間是符合堆的規則
        //第一個刪除之前,[0,size)都是堆
        //第二次刪除之前,[0,size-1)都是堆
        //第三次刪除之前,[0,size-2)都是堆
        HeapPop(array,size-i);
    }
    return;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章