日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据结构-----最大堆的实现

發布時間:2024/4/19 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构-----最大堆的实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

定義:一棵大根樹(小根樹)是這樣一棵樹,其中每一個節點的值都大小(小于)或等于其子節點(如果有子節點的話)的值。

一個大根堆(小根堆)既是大根樹(小根樹)也是完全二叉樹。

大根堆

小根堆



本篇主要實現大根堆的初始化,插入以及刪除操作。

在實現這些之前,先來簡單介紹一下大根堆類的主要數據成員:

私有成員變量:

heap:一維數組,用于存儲堆中的元素;

heapSize:整型變量,用于記錄堆中元素個數;

arrayLength:整形變量,用于記錄堆最大容量,即最多可以容納多少個元素;

公有成員函數:

initialize(T* ,int):初始化最大堆,第一個形參為初始化的數組,第二個形參為元素個數;

remove(int);刪除最大堆中特定元素;

push(const T&);添加新元素;

私有成員函數:

changeArrayLength(T*, int):當實際容量等于額定容量時,擴充額定容量;

adjust(T&,int, int):用于調整堆結構的函數,插入刪除和初始化都會用到;


堆雖然也是二叉樹,但本例中沒有使用構建樹的方式(即用節點指針)來構建最大堆,而是用數組的方式存儲元素,這樣我們假設數組[1:heapSize]用來存儲堆元素,而對堆中元素進行調整的過程就是改變元素在數組中位置的過程。

另外需要明確的是,1是根節點的下標,heapSize/2是最后一個節點的父節點下標。

對于某一個節點下標n來說,如果2*n<=heapSize,則2*n是該節點左孩子的下標;

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?如果2*n+1<=heapSize,則2*n+1是該節點右孩子的下標。


首先來看一下初始化操作的實現,傳入的參數為一維數組和元素個數。

步驟1:用參數的數組初始化堆中數組heap,用第二個參數初始化堆中元素個數heapSize;

步驟2:從最后一個節點的父節點開始(heapSize/2),一個個循環,每次循環結束節點索引減一。即第一次是heapSize/2,第二次則是heapSize/2-1,第三次是heapSize/2-2,一直循環到1。暫且叫步驟2為外層循環,該循環是逐個向上。每循環完一次都確保以該下標的節點為根節點的子樹是一個最大堆。

步驟3:在步驟2中的每一次循環中(內層循環),逐層向下索引,同時比較當前結點和其子節點的大小,將大節點作為子樹的根節點,將原先的根節點下移到子樹的位置。直到索引到達heapSize。與步驟2不同,步驟3是逐層向下索引,即某一次索引為n,則下一次是2*n。

template<class T> void maxHeap<T>::initialize(T* theHeap, int theSize) {delete[] heap; //刪除堆中原先的元素heap = theHeap; //指針賦值,將參數中數組的元素賦值給堆heapSize = theSize; //元素個數賦值//執行循環,從最后一個節點的父節點開始,逐個向上,外層循環for(int root = heapSize/2; root >= 1; --root) {T theElement = heap[root]; //保存外層循環的當前結點,每次都可以理解為給這個值找位置。//內層循環開始,給theElement找位置,將大的上移,大節點原先的位置變成空位置。int currentNode = root; //始終是空位置的下標,也是child下標的父節點位置int child = 2*root; //當前結點左孩子下標while(child <= heapSize){if(child < heapSize && heap[child+1] > heap[child])++child; //令child指向值較大的孩子//如果theElement比兩個孩子都大,那么就證明找到位置if(theElement > heap[child])break;//如果沒有找到,將大的節點放在空位置上,大節點原先的位置變為空位置heap[currentNode] = heap[child];current = child;//更新孩子下標,繼續向下尋找位置child *= 2; }}//找到位置,將theElement放在空位置上heap[currentNode] = theElement; }

接下來是插入操作,參數是要插入的值theElement,原理同初始化一樣,也是為theElement找位置,只是開始的位置不是heapSize/2,而是(++heapSize)/2。此時空位置是heapSize。

步驟1:檢查數組容量,如果數組滿了,則需要擴充數組大小。

步驟2:堆元素個數加一。

步驟3:比較theElement和當前節點大小,如果theElement大,則把當前結點移動到空位置上,把該節點原先的位置設為空位置。繼續向上尋找。

template<class T> void maxHeap<T>::push(const T& theElement) {//檢測堆是否已滿,若滿則需要擴充if(heapSize == arrayLength - 1){changeArrayLength(heap, 2*heapSize);heapSize *= 2;}int currentNode = ++heapSize; //堆元素個數加一,空位置為末尾下標//從下到上一層一層比較,把小節點下移,空位置上移。//直到空位置的父節點比theElement大,子節點比theElement小while(currentNode != 1 && heap[currentNode/2] < theElement){heap[currentNode] = heap[currentNode/2];currentNode /= 2;}heap[currentNode] = theElement; }

最后是刪除操作,參數是要刪除的下標索引。刪除后,以該位置為根節點的子樹已經不是最大堆,只需要對這一小部分進行調整。

原理依舊相同,把要刪除的那個下標設為空位置。逐層向下尋找位置,把大節點上移,空位值下移。

步驟1:取出末尾下標的元素theElement,并將堆元素個數減一。

步驟2:在以刪除節點為根節點的子樹中為theElement找位置。

template<class T> T maxHeap<T>::remove(int index) {//判斷下標是否合法if(index < 1 || index > heapSize)throw heapError("Error: the index is illegal"); T theElement = heap[heapSize--]; //取出最后一個元素,同時元素個數減一int currentNode = index; //始終指向空位置,也是child的父節點int child = 2 * index; while(child <= heapSize){//令child是較大孩子的下標if(child < heapSize && heap[child+1] > heap[child])child++;//如果theElement大,則說明找到位置存放theElement了if(theElement > heap[child])return;//若沒找到,繼續向下尋找heap[currentNode] = heap[child];currentNode = child;child *= 2;}heap[currentNode] = theElement;return theElement; }


另外因為初始化和刪除操作中while循環中的部分相同,可以單獨抽出來作為一個私有成員函數。

總結

以上是生活随笔為你收集整理的数据结构-----最大堆的实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。