排序(三)堆排序 歸併排序 快速排序

2021-08-04 22:39:53 字數 2809 閱讀 6520

7、堆排序

堆排序是指利用堆這種資料結構所設計的一種排序演算法。堆是乙個近似完全二叉樹的結構(通常堆是通過一維陣列來實現的),並同時滿足堆的性質:即子結點的鍵值總是小於(或者大於)它的父節點。

我們可以很容易的定義堆排序的過程:

1、建立乙個堆

2、把堆頂元素(最大值)和堆尾元素互換

3、把堆的尺寸縮小1,並呼叫heapify(a, 0)從新的堆頂元素開始進行堆調整

4、重複步驟2,直到堆的尺寸為1

堆排序的**如下:

#include // 交換函式

void swap (int a, int i, int j)

// 列印陣列

void printa (int *a, int

len)

printf ("\n");

}// a 代表乙個陣列

// i 代表要調整的結點的下標

// len 陣列的長度

void heapify(int *a, int i, int

len)

}void heapsort (int *a, int

len)

// 排序

for (i = len

-1; i >0; i--)

}int main()

; int

len = sizeof(a) / sizeof(a[0]);

heapsort(a, len);

printa (a, len);

return

0;}

8、歸併排序

歸併排序是建立在歸併操作上的一種有效的排序演算法,效率為o(nlogn),2023年由馮·諾伊曼首次提出。

歸併排序的實現分為遞迴實現與非遞迴(迭代)實現。遞迴實現的歸併排序是演算法設計中分治策略的典型應用,我們將乙個大問題分割成小問題分別解決,然後用所有小問題的答案來解決整個大問題。非遞迴(迭代)實現的歸併排序首先進行是兩兩歸併,然後四四歸併,然後是八八歸併,一直下去直到歸併了整個陣列。

歸併排序演算法主要依賴歸併(merge)操作。歸併操作指的是將兩個已經排序的序列合併成乙個序列的操作,歸併操作步驟如下:

1、申請空間,使其大小為兩個已經排序序列之和,該空間用來存放合併後的序列

2、設定兩個指標,最初位置分別為兩個已經排序序列的起始位置

3、比較兩個指標所指向的元素,選擇相對小的元素放入到合併空間,並移動指標到下一位置

4、重複步驟3直到某一指標到達序列尾

5、將另一串行剩下的所有元素直接複製到合併序列尾

歸併排序的**如下:

#include 

// 列印陣列

void printa (int *a, int len)

printf ("\n");

}// a 是陣列 tmp 是緩衝區

void merge(int *a, int left, int mid, int right, int *tmp)

while (i <= mid)

tmp[k++] = a[i++];

while (j <= right)

tmp[k++] = a[j++];

k = 0;

for (i = left; i <= right; i++)

}void mergesort(int *a, int left, int right, int *tmp)

int main()

; int len = sizeof(a) / sizeof(a[0]);

int tmp[10];

mergesort (a, 0, len-1, tmp);

printa (a, len);

return

0;}

9、快速排序

快速排序是由東尼·霍爾所發展的一種排序演算法。在平均狀況下,排序n個元素要o(nlogn)次比較。在最壞狀況下則需要o(n^2)次比較,但這種狀況並不常見。事實上,快速排序通常明顯比其他o(nlogn)演算法更快,因為它的內部迴圈可以在大部分的架構上很有效率地被實現出來。

快速排序使用分治策略(divide and conquer)來把乙個序列分為兩個子串行。步驟為:

1、從序列中挑出乙個元素,作為」基準」(pivot).

2、把所有比基準值小的元素放在基準前面,所有比基準值大的元素放在基準的後面(相同的數可以到任一邊),這個稱為分割槽(partition)操作。

3、對每個分割槽遞迴地進行步驟1~2,遞迴的結束條件是序列的大小是0或1,這時整體已經被排好序了。

快速排序的**如下:

#include 

// 交換函式

void swap (int a, int i, int j)

// 列印陣列

void printa (int *a, int len)

printf ("\n");

}// 分割槽操作,返回基準值的下標

int partition(int *a, int left, int right)

}swap (a, index, right);

return

index; // 基準值所在位置下標

}void qsort(int *a, int left, int right)

}int main()

; int len = sizeof(a) / sizeof(a[0]);

qsort (a, 0, len-1);

printa (a, len);

return

0;}

常用演算法總結

選擇排序(三) 堆排序

這樣,還剩下兩個問題 1.如何將乙個交換後的無序區調整為大根堆 2.如何在排序之前建立那個初始的大根堆。而第二個問題是可以通過第乙個問題的解決而解決的。1.如何將乙個交換後的無序區調整為大根堆?由於進行元素交換前,無序區是乙個大根堆,即左子樹和右子樹都是大根堆,所以根節點變化後左右子樹仍然都是大根堆...

排序演算法 三 堆排序

1.heap.class package cn.sort.heap 堆排序實現 公升序排序 author ly public class heap system.out.println 向下調整 先拿左右子樹進行比較,看誰比較大,然後再拿大的與父結點進行比較,若孩子結點比較大,則大孩子與父結點交換,...

選擇排序(三) 堆排序

這樣,還剩下兩個問題 1.如何將乙個交換後的無序區調整為大根堆 2.如何在排序之前建立那個初始的大根堆。而第二個問題是可以通過第乙個問題的解決而解決的。1.如何將乙個交換後的無序區調整為大根堆?由於進行元素交換前,無序區是乙個大根堆,即左子樹和右子樹都是大根堆,所以根節點變化後左右子樹仍然都是大根堆...