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次...