堆排序
用堆封裝優先級隊列
海量數據TopK問題
堆的完整源代碼
什麼是堆
首先,堆是完全二叉樹。
小堆: 任何一個節點的值都小於它的左右孩子的值,位於堆頂節結點的值是最小的,從根結點到每個結點的路徑上數組元素組成的序列是遞增的。
大堆:任何一個節點的值都大於它的左右孩子的值,位於堆頂節結點的值是最大的,從根結點到每個結點的路徑上數組元素組成的序列是遞減的。
堆的基本操作簡單解析
建堆
- 先申請一塊空間,然後在對其賦值形成二叉樹,在對二叉樹調整使之形成小堆
- 這裏要注意,每次向下調整隻是對一個元素調整,因此需要一個for循環。
//創建堆
void CreateHeap(Heap *hp, DataType *array, int size)
{
assert(hp);
//申請空間
hp->_array = (DataType *)malloc(sizeof(DataType)*size);
if (NULL == hp)
assert(0);
hp->_size = 0;
hp->_capacity = size;
//賦值
for (int i = 0; i < size; ++i)
{
hp->_array[i] = array[i];
hp->_size += 1;
}
hp->_capacity = size;
//找出最後一個非葉子節點
int root = (size - 1 - 1) >> 1;
//調整元素
for (; root >= 0; root--)
AdjustDown(hp,root);
}
向下調整算法(小堆爲例)
- 設該結點的下標爲parent
- 找到該結點的左孩子(child = (parent<<1)+1;)
- 如果右孩子存在,則找出左右孩子中最小的孩子(建立大堆,則找出最大的孩子)
- 比較parent和child的大小,如果parent小於child,則調整結束,否則,交換parent的child的值,此時如果其子樹還不滿足,則繼續調整,直至子樹也滿足堆的性質
void AdjustDown(Heap *hp, DataType parent)
{
int child = (parent<<1)+1;
if (NULL == hp)
return;
while (child < hp->_size)
{
//找到孩子中較小的一個
if ((child+1) < hp->_size &&
hp->cmp(hp->_array[child+1], hp->_array[child]))
{
child += 1;
}
//如果雙親大於孩子,則交換
if (hp->cmp(hp->_array[child], hp->_array[parent]))
{
Swop(&hp->_array[parent], &hp->_array[child]);
parent = child;
child = (parent << 1) + 1;
}
else
{
break;
}
}
}
插入元素
- 如果堆爲空,返回
- 檢測容量,看是否還有空間,沒有則擴容
- 將元素添加到二叉堆的最後
- 然後調整堆
void InsertHeap(Heap *hp, DataType data)
{
if (NULL == hp)
return;
CheckCatacity(hp);
hp->_array[hp->_size] = data;
hp->_size++;
if (hp->_size > 1)
AdjustUp(hp, hp->_size - 1);
}
向上調整算法(插入元素)
在插入之前堆已經使最小堆了,因此插入元素之後,需要重新對堆進行調整。
- 比較新插入的元素和parent的值的大小,如果大於,則返回,如果小於,則需要交換parent和child的值,然後繼續比較,調整後的parent和他的parent的大小,直至滿足小堆的性質
void AdjustUp(Heap *hp, int child)
{
int parent = (child - 1) >> 1;
while (child)
{
if (hp->cmp(hp->_array[child] , hp->_array[parent]))
{
Swop(&hp->_array[parent], &hp->_array[child]);
child = parent;
parent = (child - 1) >> 1;
}
else
break;
}
}
刪除元素
- 將堆中最後一個元素和堆頂元素交換
- 將堆的元素個數減少一個,相當於刪除堆中最後一個元素
- 然後利用向下調整,使其滿足最小堆的性質
void DeleteHeap(Heap *hp)
{
assert(hp);
if (NULL == hp)
return;
if (EmptyHeap(hp))
return;
Swop(&hp->_array[0], &hp->_array[hp->_size-1]);
hp->_size--;
AdjustDown(hp, 0);
}