資料結構與演算法 15 堆排序

2021-10-05 01:22:11 字數 3090 閱讀 6080

3、**實現

4、時間複雜度

5、穩定性

6、測試

堆排序是利用堆這種資料結構而設計的一種排序演算法,堆排序是一種選擇排序。乙個待排序的陣列,把它看成是順序儲存的二叉樹,假設要公升序排列,先把這個二叉樹調整為大頂堆,其頂端元素為最大值,把頂端元素和末尾元素互換後,再次把堆調整為大頂堆。如此迴圈,直到整個陣列排序完畢。

堆是完全二叉樹,堆分為大頂堆和小頂堆。

每個結點的值都大於或等於其左右子結點的值,稱為大頂堆;反之稱為小頂堆。

用前面學到的順序儲存二叉樹,講這種邏輯結構對映到陣列中就變成了:

從陣列上講,在沒有超出索引情況下用公式來描述堆的定義就是:

大頂堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]

小頂堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

乙個二叉樹調整為堆結構的大前提是這個二叉樹是完全二叉樹。

以調整為大頂堆為例。

假設存在乙個二叉樹如下所示:

第一步:從最後乙個非葉子結點開始調整(最後乙個非葉子節點的索引為arr.length/2-1),此處是 5/2-1=1,也就是值為6的結點。先找出該結點的左右子結點中值最大的子結點,這裡是第4個結點,值為9。然後判斷該子結點是否大於該結點,9 > 6,於是交換結點6和結點9。

交換後,以倒數第乙個非葉子結點的堆結構就調整好了。

第二步,調整倒數第二個非葉子結點,即第0個結點,該結點值為4。同樣先找該結點的左右節點中值最大的子結點,這裡是誰索引為1值為9的結點。然後判斷該子結點是否大於該結點,9 >4,於是交換結點4和結點9。

本來索引1結點對應子樹已經調整為大頂堆結構,因為索引0結點發生交換,需要再一次調整索引0結點,使其對應子樹為大頂堆。

迴圈以上步驟,直到調整完所有的非葉子結點。

要點:從最下邊開始調整為大頂堆,如果乙個結點調整後對應的子樹已經為大頂堆,而其在後面沒有被交換,那麼這個結點到其對應的所有子結點都是大頂堆結構。比如這個例子中的第二步,如果索引0和索引1沒有發生交換,那麼我們是不用再倒回去調整索引1。

假設待排序陣列為arr,把它看成是順序儲存的二叉樹,然後根據上面流程把該完全二叉樹調整為大頂堆。此時arr的第乙個元素就是最大值,把第乙個元素和最後乙個元素互換,這時最後乙個元素為最大值。除去最後乙個元素的arr子陣列為arr1,對arr1繼續調整為大頂堆,然後又交換arr1的首尾元素。如此反覆進行交換、重建、交換。

package cn.klb.datastructures.tree;

/** * @author: konglibin

* @description: 實現堆排序(公升序用大頂堆,降序用小頂堆)

* @date: create in 2020/4/14 19:52

* @modified by:

*/public

class

heap

// 對於調整好的大頂堆,最大元素在第乙個位置

// 把第乙個元素和最後乙個元素互換,然後對不包括最大元素的剩餘元素繼續調整為大頂堆

// 知道剩下待調整元素剩下1個,即排序完畢

for(

int i = arr.length -

1; i >

0; i--)}

/** * 把以 arr[i] 為根結點所對應的子樹調整為大頂堆

** @param arr 順序儲存二叉樹

* @param i 第i個結點

* @param length 去掉上一輪排序完得到的最大值後剩下的有效結點個數

*/private

static

void

adjustheap

(int

arr,

int i,

int length)

// 如果當前結點的子結點比它大,則互換結點

if(arr[i]

< arr[j]

)else}}

/** * arr的 a和 b元素互換位置

** @param arr

* @param a

* @param b

*/private

static

void

swap

(int

arr,

int a,

int b)

}

o(nlogn)

演算法不能保證兩個相同元素的前後順序,因此是不穩定的。

@test

public

void

testheap()

******dateformat sdf =

new******dateformat

("yyyy-mm-dd hh:mm:ss");

date date1 =

newdate()

; system.out.

println

("-----"

+ sdf.

format

(date1)

+"-----");

heap.

sort

(arr)

; date date2 =

newdate()

; system.out.

println

("-----"

+ sdf.

format

(date2)

+"-----");

// 8000萬的隨機資料進行堆排序,我的電腦花了大約27秒

}

資料結構 堆與堆排序

堆其實是從完全二叉樹演變過來的並且用來儲存資料的,什麼是完全二叉樹呢?完全二叉樹就是 若設二叉樹的深度為h,除第h層外,其它各層 1 h 1 的結點數都達到最大個數,第h層所有的結點都連續集中 在最左邊,這就是完全二叉樹。我們知道二叉樹可以用陣列模擬,堆自然也可以。現在讓我們來畫一棵完全二叉樹 從圖...

堆資料結構與堆排序

堆資料結構 堆 二叉堆 是近似的完全二叉樹,最底層允許不滿,堆的相關,陣列長度length,heap size有效長度 堆的有效元素,未排序的數目 heap size堆雖然很像二叉樹,但是我的理解就是用二叉樹的邏輯,但是最主要的區別在,堆的儲存是用陣列,只是用下標來幫助理解 堆的儲存結構 從上往下,...

資料結構與演算法16 堆排序

毫無疑問,排序兩個字沒必要去死磕,這裡的重點,在於排序的方式,堆排序,就是以堆的形式去排序,毫無疑問,了解堆很重要。那麼,什麼是堆呢?這裡,必須引入乙個完全二叉樹的概念,然後過渡到堆的概念。上圖,就是乙個完全二叉樹,其特點在於 從作為第一層的根開始,除了最後一層之外,第n層的元素個數都必須是2的n次...