首先要明白堆是基於二叉樹而言的,堆是二叉樹的一種形式。
並且堆是完全二叉樹,具有完全二叉樹的特點。
堆只有2種:大頂堆和小頂堆。
大頂堆:就是根節點大於子節點,小頂堆反之。
下面上圖:
一棵完全二叉樹如何才能轉換成乙個堆呢?
把握好堆的特點:大頂堆的根永遠大於左右孩子,那麼只需要把每乙個子樹中的左右孩子的較大值放到根的上面即可。
以大頂堆為例:
觀察以上的例子,通過自下向上進行堆的構造其實並不複雜,不過在上述例子的第三步可以看出發生交換的節點的子樹的堆平衡可能被破壞,需要重新對子樹的堆進行構造(第四步)。
因為堆是完全二叉樹,所以需要使用到完全二叉樹的一些特性
有關二叉樹和完全二叉樹的生成**可檢視二叉樹及完全二叉樹
對單個節點進行調整是上面圖中的單個子樹的交換過程
這個**實現一定要知道完全二叉樹的特性:
序列[8 1 3 9 12 21]
將序列從0開始編號,第0的是根節點,第1個是左孩子,第2個是右孩子
規律:第i個節點的左孩子是2i+1,右孩子是2i+2,,所以可以直接使用序列來調整完全二叉樹。
//對單個節點進行調整
public
static
void
node
(int
a,int i)
if(a[
2*i+2]
> a[i]
&& a[
2*i+2]
> a[
2*i+1]
)}else}}
}
以上**完成可能會留有乙個疑問:調整中可能出現上面第4步的問題,調整後該孩子節點被破壞了!那麼需要對調整後的節點進行往復的調整,遞迴思想!!!
完整的調整**:
//對單個節點進行調整
public
static
void
node
(int
a,int i)
if(a[
2*i+1]
> a[i]
&& a[
2*i+1]
> a[
2*i+2]
)}else}}
}
完成了單個節點的調整後對整個序列進行乙個堆的生成,接著呼叫上面的單個調整方法自下向上進行調整。
public
static
int[
]heap
(int
a)return a;
}
乙個堆的頂端是乙個序列的最大值或者最小值!排序的思路可以是每次拿走最大值讓剩餘的序列重新生成乙個堆,往復取根節點的最大值。
為了保證最大的空間利用率,將生成堆的最大值a[0]與最後的值交換,接著將前面的序列重新生成乙個堆,重複上述步驟。
基於單個節點的調整**注意事項
因為單個堆調整**中存在乙個對後續的堆的破壞進行檢驗的操作(上面的**中的遞迴),而堆排序的序列末尾會放置最大值會被重新平衡掉,所以需要控制調整節點的範圍:
public
static
void
node
(int
a,int i,
int length)
if(a[
2*i+2]
> a[i]
&& a[
2*i+2]
> a[
2*i+1]
)}else}}
}
接著要重新修改堆生成的方法,實現控制堆排序長度
public
static
int[
]heap
(int
a,int length)
return a;
}
最終進行乙個堆排序方法,生成堆後最大值a[0]放到後面,然後對前面的序列繼續進行堆排序
public
static
void
sort
(int
a)}
堆排序學習
資料來自 靜默虛空 萬分感謝 做筆記用 1 根據初始陣列去構造初始堆 構建乙個完全二叉樹,保證所有的父結點都比它的孩子結點數值大 2 每次交換第乙個和最後乙個元素,輸出最後乙個元素 最大值 然後把剩下元素重新調整為大根堆。設有乙個無序序列 構建初始堆 完整的堆排序處理 如果父結點的值已經大於孩子結點...
堆排序學習
參考博主dreamcatcher cx 這位博主還有許多優秀的排序方法學習記錄 構建n次最大堆,每次構建頂點元素即為陣列最大元素,找到最大元素之後將最大元素放在陣列最後 從最後乙個非葉子節點開始,將該節點調整最低階節點,也即它的小於父節點大於兩個子節點 調整次數為n 2 1 完成最大堆的構建之後,將...
堆排序學習筆記
參考此文的學習筆記 不用交換,則已經是最大堆,不用迴圈了 else break void sort int a,int length 開始排序,排序是從上到下從左到右的調整 for int j length 1 j 0 j int main sort a,length for int i 0 i l...