Java 堆排序 大頂堆 小頂堆

2021-07-15 11:41:09 字數 3614 閱讀 6745

引用:

堆排序(heapsort

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

堆排序的平均時間複雜度為

ο(nlogn) 。

演算法步驟:

1. 建立乙個堆h[0..n-1]

2. 把堆首(最大值)和堆尾互換

3. 把堆的尺寸縮小

1,並呼叫

shift_down(0),

目的是把新的陣列頂端資料調整到相應位置

4. 重複步驟

2,直到堆的尺寸為1堆:

堆實際上是一棵完全二叉樹,其任何一非葉節點滿足性質: key[i]<=key[2i+1]&&key[i]<=key[2i+2]

或者key[i]>=key[2i+1]&&key>=key[2i+2] 

即任何一非葉節點的關鍵字不大於或者不小於其左右孩子節點的關鍵字。 堆分為大頂堆和小頂堆,滿足

key[i]>=key[2i+1]&&key>=key[2i+2]

稱為大頂堆,滿足 

key[i]<=key[2i+1]&&key[i]<=key[2i+2]

稱為小頂堆。由上述性質可知大頂堆的堆頂的關鍵字肯定是所有關鍵字中最大的,小頂堆的堆頂的關鍵字是所有關鍵字中最小的。

堆排序思想:

利用大頂堆(

小頂堆)

堆頂記錄的是最大關鍵字

(最小關鍵字

)這一特性,使得每次從無序中選擇最大記錄

(最小記錄

)變得簡單。 其基本思想為

(大頂堆): 

1)將初始待排序關鍵字序列

(r1,r2….rn)

構建成大頂堆,此堆為初始的無序區; 

2)將堆頂元素

r[1]

與最後乙個元素

r[n]

交換,此時得到新的無序區

(r1,r2,……rn-1)

和新的有序區

(rn),

且滿足r[1,2...n-1]<=r[n]; 3)

由於交換後新的堆頂

r[1]

可能違反堆的性質,因此需要對當前無序區

(r1,r2,……rn-1)

調整為新堆,然後再次將

r[1]

與無序區最後乙個元素交換,得到新的無序區

(r1,r2….rn-2)

和新的有序區

(rn-1,rn)

。不斷重複此過程直到有序區的元素個數為

n-1,則整個排序過程完成。 操作過程如下: 

1)初始化堆:將

r[1..n]

構造為堆; 

2)將當前無序區的堆頂元素

r[1]

同該區間的最後乙個記錄交換,然後將新的無序區調整為新的堆。 因此對於堆排序,最重要的兩個操作就是構造初始堆和調整堆,其實構造初始堆事實上也是調整堆的過程,只不過構造初始堆是對所有的非葉節點都進行調整。

乙個圖示例項

給定乙個整形陣列a=

,對其進行堆排序。 首先根據該陣列元素構建乙個完全二叉樹,得到

然後需要構造初始堆,則從最後乙個非葉節點開始調整,調整過程如下:

20和16交換後導致

16不滿足堆的性質,因此需重新調整

這樣就得到了初始堆。

先進行一次調整時其成為大頂堆,

即每次調整都是從父節點、左孩子節點、右孩子節點三者中選擇最大者跟父節點進行交換(

交換之後可能造成被交換的孩子節點不滿足堆的性質,因此每次交換之後要重新對被交換的孩子節點進行調整

)。有了初始堆之後就可以進行排序了。

此時3位於堆頂不滿堆的性質,則需調整繼續調整

這樣整個區間便已經有序了。從上述過程可知,堆排序其實也是一種選擇排序,是一種樹形選擇排序。只不過直接選擇排序中,為了從

r[1...n]

中選擇最大記錄,需比較

n-1次,然後從

r[1...n-2]

中選擇最大記錄需比較

n-2次。事實上這

n-2次比較中有很多已經在前面的

n-1次比較中已經做過,而樹形選擇排序恰好利用樹形的特點儲存了部分前面的比較結果,因此可以減少比較次數。對於

n個關鍵字序列,最壞情況下每個節點需比較

log2(n)

次,因此其最壞情況下時間複雜度為

nlogn

。堆排序為不穩定排序,不適合記錄較少的排序。 上面描述了這麼多,簡而言之

,堆排序的基本做法是

:首先,用原始資料構建成乙個大(小

)堆作為原始無序區,然後,每次取出堆頂元素,放入有序區。由於堆頂元素被取出來了,我們用堆中最後乙個元素放入堆頂,如此,堆的性質就被破壞了。我們需要重新對堆進行調整,如此繼續

n次,那麼無序區的

n個元素都被放入有序區了,也就完成了排序過程。

(建堆是自底向上)

實際應用:

實際中我們進行堆排序是為了取得一定條件下的最大值或最小值,例如:需要在100

個數中找到

10個最大值,因此我們定義乙個大小為

10的堆,把

100中的前十個資料建立成小頂堆(堆頂最小),然後從

100個資料中的第

11個資料開始與堆頂比較,若堆頂小於當前資料,則把堆頂彈出,把當前資料壓入堆頂,然後把資料從堆頂下移到一定位置即可,

**:

public class test0 

static int m=0;

static int size=0;//用來標記堆中有效的資料

public void addtosmall(int v);

//堆的大小為10

//arr = new int[10];

if(sizearr[par*2]){

swap(arr,index,par*2);

if(arr[index]

排序演算法 堆排序(大頂堆 小頂堆)

堆排序的思想這裡就先不講了,以後有時間再補上,下面是分別採用大頂堆和小頂堆實現的堆排序。注意 下面例子中排序的數字是。大頂堆方式 include include using namespace std 堆調整 將nums s.m 調整為大頂堆,其中除了nums s 之外均滿足大頂堆的定義 void ...

大頂堆 小頂堆 堆排序

堆的定義 n個元素的序列當且僅當滿足下列關係之一時,稱之為堆。大頂堆 k i k 2i 且k i k 2i 1。小頂堆 k i k 2i 且k i k 2i 1。堆序列可以理解成乙個完全二叉樹,該樹任意乙個結點的關鍵字的值都小於或等於它的孩子結點的關鍵字。例如 堆排序 若在輸出堆頂的最小值之後,使得...

大頂堆小頂堆

堆通常是乙個可以被看做一棵完全二叉樹的陣列物件 如果對一棵有n個結點的完全二叉樹的結點按層序編號 從第1層到第 1層,每層從左到右 則對任一結點i 1 i n 有 1 如果i 1,則結點i無雙親,是二叉樹的根 如果i 1,則其雙親是結點。2 如果2i n,則結點i為葉子結點,無左孩子 否則,其左孩子...