1. 程式人生 > >【資料結構】大小堆的理解,建立,增加和刪除元素操作

【資料結構】大小堆的理解,建立,增加和刪除元素操作

什麼是大小堆?

大小堆是基於完全二叉樹的結構; 大堆:任意一個結點的左右孩子的資料都小於此結點的資料,位於堆頂的結點的資料最大。 小堆:任意一個結點的左右孩子的資料都大於此結點的資料,位於堆頂的結點的資料最小。 下面以小堆為例,圖解:

在這裡插入圖片描述

以下都是以小堆為例

如何建立小堆?

首先我們只會得到一個數組,並且我們知道堆最終形態是完全二叉樹。通過遞迴的思想,如果能把最後一個以非葉子結點為根的樹變為小堆,然後改變倒數第二個以非葉子結點為根的樹,以此類推就可以將整個樹變為小堆。函式內需要用到向下調整法可看註釋:

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);		//向下調整將改變之後的樹變為小堆
}