常用排序演算法

2021-07-05 15:38:05 字數 3810 閱讀 6667

排序在程式中非常常見,許多時候人們過於關注各種高階演算法,在長久的工作學習中甚至只會呼叫庫函式排序。閒來無事,整理了幾種自己認為最常見的排序演算法,僅為溫習和備忘。

插入排序的思想就是對每個待排序元素,找到其正確地插入位置。該元素左邊是有序陣列,右邊是無序的。在左邊找到該元素的插入位置,完成插入後,對下乙個元素位置繼續排序。

#include

using

namespace

std;

void insert_sort(vector

&nums)

nums[j+1] = temp;

}}

可見,插入排序是原地的,其最壞時間複雜度為o(n*n),空間複雜度o(1),插入排序是穩定的。當原陣列是有序的時候,每次一進入內層迴圈就退出,時間複雜度可以提公升到o(n),而當原陣列剛好是逆序的時候,時間複雜度為o(n*n),且每一次都要發生一次移動。由此可見,當資料已經基本有序的時候使用插入排序是乙個較好的選擇。

我們發現對每個待排元素總要去其左邊的有序序列尋找正確的插入位置,能不能對這一步提速呢,類似使用二分查詢?其實是不行的,因為從**可見,我們在尋找正確插入位置的時候還在移動元素,即使使用二分查詢快速找到了插入位置,但還是要花費o(n)的時間移位。

如果原來序列是逆序的,那麼插入排序的效能會變得很差,針對這一點d.l.shell提出了shell排序。

其思想為:首先將序列按照乙個增量值分成很多組,每一組內進行插入排序。然後縮短增量,繼續上述步驟,直到增量為1,這樣的排序方法可以有效減少序列中的逆序對,提高效能。

#include

using

namespace

std;

void shell_sort(vector

&nums)

}}void modinssort(int *p, n, delta)}}

}

上述**中modinssort()函式是插入排序的修改版。

shell排序是不穩定的,其最壞時間複雜度仍是o(n*n),空間複雜度為o(1),其具體表現與增量的選擇有很大關係,其基本思想就是先通過幾輪排序使得之後排序的序列基本有序,而在基本有序的情況下,插入排序是比較快的。關於其增量如何選擇,有很多學者做了相關研究,在此不贅述。

選擇排序可以理解為,每次選擇乙個位置i,然後選擇第i小的資料來占有這個位置即將兩個位置的資料互換。

#include

using

namespace

std;

void select_sort(vector

&nums)

}int temp = nums[i];

nums[i] = nums[mini];

nums[mini] = temp;

}}

選擇排序是不穩定的,最壞、最好和平均時間複雜度都為o(n*n),空間複雜度o(1)

堆排序基本步驟為,構造乙個最大堆,然後把最大元素和堆的最後乙個元素互換,然後調整堆和堆的大小

#include

using

namespace

std;

//移除堆頂元素,至堆的末尾,每次結束重新調整堆

void remove_max(vector

&nums, int currentsize)

//向下調整函式。若子節點存在比父節點大的,將父節點與子節點中較大的交換。直到不存在,就調整完畢。

void shiftdown(vector

&nums, int i, int currentsize)

if (nums[large] > temp)

else

break;

}nums[i] = temp;

}//建立最大堆,建堆的過程是針對每個非葉子節點進行shiftdown即向下調整

void build_heap(vector

&nums, maxsize)

}//堆排序的主要步驟。1、建立最大堆。2、每次移除堆頂元素,直到堆空

void heap_sort(vector

&nums)

}

堆排序最好,最壞和平均時間複雜度都是o(nlogn),空間複雜度o(1),是不穩定的。由於一次建堆就可以反覆使用,因此n越大效率越高。

快速排序演算法是二十世紀十大演算法之一,可以認為是「最快」的演算法。其基本的演算法思想是分治,歸併排序基本思想也是分支,但是不同的是,快速排序重點在分,而歸併重點在合。

快排的基本步驟為:1、選定乙個軸值。2、將比軸值小的數移到左邊,比軸值大的數移到右邊,則此刻軸值的位置就正確了。3、針對軸值兩邊的陣列繼續上述步驟,直到只剩乙個資料。

#include

using

namespace

std;

void quick_sort(vector

&nums, left, right)

if (l < r)

while (nums[r] >= temp)

if (l < r)

}nums[l] = temp;

quicksort(nums, left, l-1);

quicksort(nums, l+1, right);

}

快排平均、最小時間複雜度是o(nlogn),最壞時間複雜度是o(n*n),空間複雜度是o(1),是不穩定排序。快排是最常用的排序演算法,雖然說現在各種排序演算法都可以直接呼叫庫函式,但是能快速手寫這種經典演算法也是有必要的。

前面已經提到過了,歸併排序也是用的分治法的思想。但是「分,治,合」中,歸併在意的是合的過程,將兩個有序陣列合併為乙個陣列,只需要一遍掃瞄即可。歸併排序的步驟為1、選乙個中間值將陣列分為兩半。2、重複上述步驟知道兩邊只剩乙個數。3、此時兩邊都有序,將兩邊陣列合併

#include

using

namespace

std;

void merge(vector

&nums, vector

&temp, int left, int right, int mid)

int index1 = mid + 1;

int index2 = left;

int j = left;

while ((index1 <= right) && (index2 <= mid))

else

}while (index1 <= right)

while (index2 <= mid)

}void merge_sort(vector

&nums, vector

&temp, left, right)

}

歸併排序最好、最壞、平均時間複雜度都是o(nlogn),空間複雜度o(n),是穩定的。其中temp陣列是用來臨時存放用的,其實也可以不從外部傳入,在merge()函式內部建立,建立的時候只要n/2大小即可,但並沒有什麼數量級的提高。可以自己根據情況自由選擇

氣泡排序可以算是我接觸的最早的電腦程式了,那還是初中的時候。。氣泡排序非常好寫,基本思想就是依次把最大的數移到陣列的末尾,就像乙個氣泡冒出來一樣。

#include

using

namespace

std;

void bubble_sort(vector

&nums)}}

}

氣泡排序時間複雜度o(n*n),空間複雜度o(1)。平時不要使用。。

這是幾種最常用的內排序演算法,雖然很底層,但還是有必要了解。特別是快速排序,掌握它應該是基本素養。而且對於一般情況,各種實驗驗證,快速排序的確是最快的排序演算法。

常用排序演算法

筆者最近學習演算法,學了很久也只弄懂了幾個排序演算法,在這裡曬一下下,作為以後參考之用。一 為什麼要研究排序問題 許多計算機科學家認為,排序演算法是演算法學習中最基本的問題,原因有以下幾點 l有時候應用程式本身需要對資訊進行排序,如為了準備客戶賬目,銀行需要對支票賬號進行排序 l很多演算法將排序作為...

常用排序演算法

一 簡單排序演算法 由於程式比較簡單,所以沒有加什麼注釋。所有的程式都給出了完整的執行 並在我的vc環境 下執行通過。因為沒有涉及mfc和windows的內容,所以在borland c 的平台上應該也不會有什麼 問題的。在 的後面給出了執行過程示意,希望對理解有幫助。1.冒泡法 這是最原始,也是眾所...

常用排序演算法

排序演算法 最好時間 平均時間 最壞時間 輔助空間 穩定性 直接插入排序 o n o n 2 o n 2 o 1 穩定 希爾排序 o n 1.3 o 1 不穩定 直接選擇排序 o n 2 o n 2 o n 2 o 1 不穩定 堆排序 o n x lbn o n x lbn o n x lbn o ...