1.插入排序(insertion sort)
如圖所示,將需要排序的序列,分成已排序的部分,和未排序的部分。
循環中,每一次就將當前迭代到的,未排序的第一個元素,插入到在已排序部分中的適當位置。
2.選擇排序(selection sort)
如圖所示,首先便利所有未排序的元素,找出最大的一個,然后與數組中的最后一個交換。
下一次迭代就從未排序的元素中,找出最大的一個,與數組中倒數第二個交換,以此類推。
3. 希爾排序(shell sort)
希爾排序,主要是將各元素按一個遞減的增量,來對元素分組排序,如圖所示,一開始increment為5,則將元素分為5組,每組3個,元素在組內先按大小排序好。
然后increment按(increment = increment / 3 + 1)的形式進行遞減,則第二次迭代increment為3,則將元素分為3組,再在組內進行排序。直到increment小於等於1。
具體算法:
void shell_sort() {
int increment, start; increment = array.count; do { increment = increment / 3 + 1; for (start = 0; start < increment; start++) { sort_interval(start, increment); } } while(increment > 1); }
4. 歸並排序(merge sort)
歸並排序是采用分治法的一種。通過直接將數組對半分,然后分成2部分數組,進行遞歸,直到數組中元素為一個,則函數直接返回,而父函數就將兩個數組中的元素進行比較,合並成為一個已經排好序的數組。
具體算法:
void recursive_merge_sort(Node*& sub_list) {
if (sub_list != NULL && sub_list -> next != NULL) { Node *second_half = divide_from(sub_list); recursive_merge_sort(sub_list); recursive_merge_sort(second_half); sub_list = merge(sub_list, second_half); } }
5. 快排(quick sort)
快排的核心,其實也是分治法。
通過選定一個pivot。
然后將數組分成大於這個pivot的和小於這個pivot的兩組。
再遞歸,分別給這兩組再找pivot及分組,直到組內元素為1。則快排結束。
6. 堆排序
堆定義:堆分為最大堆和最小堆,其實就是完全二叉樹。最大堆要求節點的元素都要不小於其孩子,最小堆要求節點元素都不大於其左右孩子,兩者對左右孩子的大小關系不做任何要求。
在一個二叉堆中,位置k的結點的父結點的位置為k/2 向下取整,而他的兩個子結點的位置分別為2k和2k+1。
一個例子:
上圖是一個最大堆。
堆主要有兩個操作:
(1)插入:
a. 往堆中的某個空節點插入一個元素,則要用該元素與該節點的兩個子節點的較大一個進行比較。
b. 如果元素大於該較大節點,則元素能夠放在這個位置。
否則,將這個較大節點,上浮到元素原來想存放的位置。然后元素的位置移到這個較大節點,再重復a
參考代碼思路:
void insert_heap(int current, int low, int high) {
int large = 2 * low + 1; // large是low的左子節點
while (large <= high) { if (large < high && entry[large] < entry[large + 1]) large++; // 確保large是兩個子節點中的較大一個 if (current >= entry[large]) break; // 可以放在low這個位置 else { entry[low] = entry[large]; // 交換較大節點到low low = large; // low指向較大節點的位置 large = 2 * low + 1; // large變為low的左子節點 } } entry[low] = current; // 放在low的位置 }
推排序最主要的幾個步驟:
(1)初始化一個最大堆
將一個無序的數組,變化成一個最大堆。
方法:從最后一個子元素的父元素開始,按順序,把非葉子節點的元素插入,判斷其是否適合該位置。
參考代碼:
void init_heap() {
int low; for (low = count / 2 - 1; low >=0; low--) { int current = entry[low]; insert_heap(current, low, count - 1); } }
(2)進行堆排序
把最大堆的堆頂元素出堆,放在最后一個元素(數組尾部)的位置,然后插入這個最后的元素進堆里。這樣,每次出堆的都是當前堆的最大值,所以就能完成排序。
參考代碼:
void heap_sort() {
int current, last_unsorted; init_heap(); for (last_unsorted = entry.count - 1; last_unsorted > 0; last_unsorted--) { current = entry[last_unsorted]; // 記錄最后的元素 entry[last_unsorted] = entry[0]; // 把堆頂的元素放到sorted中 insert_heap(current, 0, last_unsorted - 1); // 把最后的元素放進堆中,重新構建堆。 } }
7. 基數排序
基數排序(Radix Sort)是桶排序的擴展,它的基本思想是:將整數按位數切割成不同的數字,然后按每個位數分別比較。
具體做法是:將所有待比較數值統一為同樣的數位長度,數位較短的數前面補零。然后,從最低位開始,依次進行一次排序。這樣從最低位排序一直到最高位排序完成以后, 數列就變成一個有序序列。
8. 各種排序的空間、時間復雜度以及穩定性