Java版大顶堆的实现
生活随笔
收集整理的這篇文章主要介紹了
Java版大顶堆的实现
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
堆的概念
堆是一棵完全二叉樹,一般使用數組來存儲。通俗來講堆其實就是利用數組來維護一個完全二叉樹。
按照堆的特點可以把堆分為大頂堆和小頂堆
-
大頂堆:堆的每個結點的值都大于或等于其左右孩子結點的值
-
小頂堆:堆的每個結點的值都小于或等于其左右孩子結點的值
根據堆的概念(利用數組維護的完全二叉樹),可以推導出:
假設 節點A 在數組 tree 的索引為 i 則
(1)A節點的左節點索引:leftIdx = (i+1)*2 -1
(2)A節點的右節點索引:rightIdx = (i+1)*2
(3)A的父節點索引:parentIdx = (i-1)/2
堆的構建
堆的構建可以看成是空堆中逐漸插入數據,因此構建堆,應該先實現堆的插入方法。
往堆中插入節點
往堆中插入數據時,可能會破壞大頂堆(或小頂堆),根節點大于左右節點的性質,因此需要做出調整。
堆的插入流程如下:
示例代碼:
/*** 插入的流程:* 1.先把元素放到數組最后* 2.與父元素比較,若父元素小于子元素則交換父子元素,直到父元素大于等于子元素* @param n*/public void add(int n){if(size>=capacity){throw new RuntimeException("堆達到最大容量");}//新節點的索引int curIdx = size;//將新節點插入數組尾部table[curIdx] = n;//獲得父節點索引,具體代碼在參考后文的完整示例//父節點索引 pIdx = (curIdx-1)/2int pIdx = getParent(curIdx);/*** 調整堆,使其符合大頂堆的性質,時間復雜度O(logn)* 與父元素比較,若父元素小于子元素則交換父子元素,直到父元素大于等于子元素*/while(table[curIdx]>table[pIdx]){//子節點值大于父節點,交換父子節點int t = table[pIdx];table[pIdx] = table[curIdx];table[curIdx] = t;curIdx = pIdx;pIdx = getParent(curIdx);}size++;}在清楚堆的插入過程之后,堆的構建就是直接調用插入方法,往堆中存放數據。
同時由上述可知,往堆中添加元素的時間復雜度為 O(logN),因此構建堆的時間復雜度為n次插入,即 O(NlogN)
刪除堆頂節點
刪除堆頂元素的流程:
示例代碼:
/*** 刪除并返回堆頂元素* 刪除流程:* 1.把最后一個元素代替刪除位置的元素* 2.與子元素比較,把較大的子元素與當前元素交換,直到當前元素大于左右子元素* @return 堆頂元素*/public int remove(){//待刪除的堆頂元素int v = table[0];//用堆的最后一個元素(數組中的最后一個元素),代替堆頂元素(數組的第一個元素)table[0] = table[size-1];size--;//調正堆,使堆滿足大頂堆的性質//當前元素索引,一開始為堆頂元素int curIdx = 0;while(true){//獲得當前元素的左右節點索引,具體代碼參考后面完整示例int lf = getLeftChild(curIdx);int rt = getRightChild(curIdx);if(lf==-1&&rt==-1){//沒有左右元素,無需調整break;}//較大的子元素索引int swapIdx;if(lf==-1||rt==-1){swapIdx = lf==-1?rt:lf;}else{swapIdx = table[rt]>table[lf]?rt:lf;}if(table[curIdx]>table[swapIdx]){//父元素大于左右子元素,結束交換break;}//用較大的子元素代替父元素int t = table[curIdx];table[curIdx] = table[swapIdx];table[swapIdx] = t;curIdx = swapIdx;}//返回被刪除的元素return v;}完整代碼
/*** @author Darren* @date 2021/6/24 15:54* 簡單大頂堆的實現*/ public class Heap {//堆的容量int capacity;//已存放的節點數int size;//存放完全二叉樹結構的數組int[] table;Heap(int capacity){this.capacity = capacity;table = new int[capacity];}/*** 插入的流程:* 1.先把元素放到數組最后* 2.與父元素比較,若父元素小于子元素則交換父子元素,直到父元素大于等于子元素* @param n*/public void add(int n){if(size>=capacity){throw new RuntimeException("堆達到最大容量");}//當前元素的索引int curIdx = size;//將新節點插入數組尾部table[curIdx] = n;int pIdx = getParent(curIdx);/*** 調整堆,使其符合大頂堆的性質,時間復雜度O(logn)* 與父元素比較,若父元素小于子元素則交換父子元素,直到父元素大于等于子元素*/while(table[curIdx]>table[pIdx]){int t = table[pIdx];table[pIdx] = table[curIdx];table[curIdx] = t;curIdx = pIdx;pIdx = getParent(curIdx);}size++;}/*** 刪除堆頂元素* 刪除流程:* 1.把最后一個元素代替刪除位置的元素* 2.與子元素比較,把較大的子元素與當前元素交換,直到當前元素大于左右子元素* @return*/public int remove(){//待刪除的堆頂元素int v = table[0];//用堆的最后一個元素(數組中的最后一個元素),代替堆頂元素(數組的第一個元素)table[0] = table[size-1];size--;//調正堆,使堆滿足大頂堆的性質//當前元素索引,一開始為堆頂元素int curIdx = 0;while(true){int lf = getLeftChild(curIdx);int rt = getRightChild(curIdx);if(lf==-1&&rt==-1){//沒有左右元素,無需調整break;}//較大的子元素索引int swapIdx;if(lf==-1||rt==-1){swapIdx = lf==-1?rt:lf;}else{swapIdx = table[rt]>table[lf]?rt:lf;}if(table[curIdx]>table[swapIdx]){//父元素大于左右子元素,結束交換break;}//用較大的子元素代替父元素int t = table[curIdx];table[curIdx] = table[swapIdx];table[swapIdx] = t;curIdx = swapIdx;}return v;}public int getLeftChild(int i){int index = (i+1)*2-1;//index>=size 說明沒有左子節點return index<size?index:-1;}public int getRightChild(int i){int index = (i+1)*2;//index>=size 說明沒有右子節點return index<size?index:-1;}public int getParent(int i){return (i-1)/2;} }參考
-
推薦:堆排序(大頂堆、小頂堆)----C語言
-
排序六 堆排序
-
數據結構:堆(Heap)
總結
以上是生活随笔為你收集整理的Java版大顶堆的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么建立网站赚钱(怎么建立网站赚钱平台)
- 下一篇: 一篇文章指明做JavaWeb项目需要的前