【資料結構】大小堆的理解,建立,增加和刪除元素操作
阿新 • • 發佈:2018-12-16
什麼是大小堆?
大小堆是基於完全二叉樹的結構; 大堆:任意一個結點的左右孩子的資料都小於此結點的資料,位於堆頂的結點的資料最大。 小堆:任意一個結點的左右孩子的資料都大於此結點的資料,位於堆頂的結點的資料最小。 下面以小堆為例,圖解:
以下都是以小堆為例
如何建立小堆?
首先我們只會得到一個數組,並且我們知道堆最終形態是完全二叉樹。通過遞迴的思想,如果能把最後一個以非葉子結點為根的樹變為小堆,然後改變倒數第二個以非葉子結點為根的樹,以此類推就可以將整個樹變為小堆。函式內需要用到向下調整法可看註釋:
void AdjustDown(pHeapStack pHs,int root) //向下調整法,以phs為根節點的整棵樹變為大小堆 { int parent = root; int child = (root<<1)+1; assert(pHs); while(child<pHs->sz) { if(child+1<pHs->sz && pHs->_compare(pHs->data[child+1],pHs->data[child])) child = child+1; //誰跟頂層的換值,下一步就調整誰,因為換了的就有可能不符合小堆 if(pHs->_compare(pHs->data[child],pHs->data[parent])) Swap(&pHs->data[child],&pHs->data[parent]); parent = child; //先把頂層的調整好再去調整後面的 child = (child<<1)+1; } } void CreatHeapStack(pHeapStack pHs,Heap_DT* array,int ArrSz,PCompare compare) { int root; assert(array); pHs->data = (Heap_DT*)malloc(sizeof(Heap_DT)*ArrSz); pHs->_compare = compare; if(NULL == pHs->data) { assert(0); return; } memcpy(pHs->data,array,ArrSz*sizeof(Heap_DT)); pHs->sz = ArrSz; pHs->dilatation = ArrSz; for(root=((pHs->sz-1-1)>>1) ;root>=0 ;root--) //得到最後一個非葉子節點的下標,進行迴圈 AdjustDown(pHs,root); }
小堆的增加元素操作
直接往原堆陣列的最後新增一個元素,然後通過向上調整的方式。對新加的元素,它到根節點這條路上的所有樹都調整符合小堆的特性就好。
void AdjustUp(pHeapStack pHs,int root) { int child = root; int parent = ((root-1)>>1); assert(pHs); while(parent>=0) { if(pHs->_compare(pHs->data[child],pHs->data[parent])) Swap(&pHs->data[parent],&pHs->data[child]); child = parent; //向上調整,孩子變父親, parent = ((parent-1)>>1); //雙親變新的雙親 } } void InsertHeap(pHeapStack pHs,Heap_DT d) { assert(pHs); IsFull(pHs); pHs->data[pHs->sz++] = d; AdjustUp(pHs,pHs->sz-1); }
小堆的刪除元素操作
將要刪除的元素與堆陣列最後一個元素的值交換,然後堆陣列數量減一,現在已經刪除了要刪除的元素,但是因為交換了元素值,小堆的性質被破壞。用向下調整的方法,從原本交換的結點位置開始,將以它為根的樹變為小堆。
void AdjustDown(pHeapStack pHs,int root) { int parent = root; int child = (root<<1)+1; assert(pHs); while(child<pHs->sz) { if(child+1<pHs->sz && pHs->_compare(pHs->data[child+1],pHs->data[child])) child = child+1; if(pHs->_compare(pHs->data[child],pHs->data[parent])) Swap(&pHs->data[child],&pHs->data[parent]); parent = child; child = (child<<1)+1; } } void RemoveHeap(pHeapStack pHs) { assert(pHs); Swap(&pHs->data[0],&pHs->data[pHs->sz-1]); //交換 pHs->sz--; //刪除 AdjustDown(pHs,0); //向下調整將改變之後的樹變為小堆 }