堆以及堆的實際應用

2021-08-15 19:14:01 字數 2718 閱讀 1574

1.堆的概念

堆的儲存可以看成是陣列儲存的變形,不過,堆的儲存又具有二叉樹的結構,堆的儲存按型別可以分為大堆和小堆。小堆(大堆)中:任一節點的關鍵碼均小於(大於)等於它的左右孩子的關鍵碼,位於堆頂節點的關鍵碼最小(最大),從根節點到每個結點的路徑上陣列元素組成的序列都是遞增(遞減)的。

2.堆的建立

堆可以看做是由乙個陣列轉化而來的。因此,堆的建立也可以進行一些轉化

第一步,將乙個陣列裡面的元素通過下標按層·排序的方式構建乙個完全二叉樹

第二步·,將這個二叉樹通過向下調整的方法調整成為最小堆

原理:從最後乙個非葉子結點開始調整,一直到根節點為止,將每個結點及其子樹調整到滿足小堆的性質即可。

具體調整方法:

1.假設該節點的下標為parent

2.找到該節點的左孩子left=parent*2+1

3.如果右孩子right=parent*2+1存在,找到left和right之中最小的孩子

4.比較parent是否小於其左右孩子較小者,如果小於等於較小者則調整結束

否則將parent中元素與較小的孩子交換,如果調整過後不滿足小堆性質,那就繼續調整直到子樹滿足性質即可。

3.堆的插入和刪除

由於堆具有特殊的性質,因此它的插入和刪除比一般的二叉樹要麻煩很多

1。堆的插入:在已經建成的最小堆的後面插入乙個新的元素,插入之後,插入之後,如果樹中節點不滿足堆的性質時,就需要進行調整。

方法 由於已經是小堆,因此,需要調整的只是從該葉子節點到根節點的子樹。先找到該節點的父親節點,如果小於父親節點,那麼就需要進行向上調整,使其調整之後滿足小堆的性質,如此重複多次,直到整個堆都滿足小堆的性質

2.堆的刪除:堆的刪除也是不可以隨便亂刪的,因為隨便刪除的話會完全破壞小堆的結構,使其不再具備小堆的性質,如果想要保持這種性質,就需要重新建堆,那麼時間複雜度將會很大。

方法 將堆中最後乙個元素替代堆頂元素

由於堆的元素個數是按下標控制,因此只需要將下標減一就可以將堆中最後乙個元素刪除

此時,如果堆的結構被破壞,只需要進行簡單的向下調整就可以使其重新滿足小堆的性質,而其時間複雜度只有log n,因此用堆來進行排序也是可以行得通的。

堆的應用

1.優先順序佇列

思路分析:優先順序佇列可以用排隊這個實際現象來說明。當你要去排隊買飯的時候,如果去得早,那麼就可以很快買到,如去的晚,那麼就要排在別人的後面,你也就很晚才能買到,這時候還需要考慮乙個問題,如果有的人特別慢,那就需要考慮優先順序了。優先順序的特點就是給較小的數字設定較高的優先順序那麼就可以很快的訪問到,資料的處理也就可以更加快速我把**放在下面。

void priorityqueueinit(priorityqueue* q)

void priorityqueuepush(priorityqueue* q, datatype x)

q->_a[q->_size++]=x;

adjustup(q->_a,q->_size,q->_size-1);

}void priorityqueuepop(priorityqueue* q)

q->_a[0]=q->_a[q->_size-1];

q->_size--;

adjustdown(q->_a,q->_size,0);

}datatype priorityqueuetop(priorityqueue* q)

return q->_a[0];

}size_t priorityqueuesize(priorityqueue* q)

size_t priorityqueueempty(priorityqueue* q)

void heapsort(datatype* a, size_t n)

2.100億個數中找出最大的前k個數(海量資料topk問題)

思路分析:乍一看,100億個數,確實很大,乙個數占四個位元組,那麼100億個數就需要40g的儲存空間,這對與普通電腦來說確實是不可能的。但是,這道題肯定不可能讓我們建立乙個具有100億個資料的堆,這樣不說儲存空間不夠大,時間複雜度也是很大的,正確·的做法是,

1.建立乙個有k個元素的小堆

2.利用迴圈,將最後乙個元素和第乙個元素進行替換,然後進行向下調整使其滿足小堆的性質,如果這個數比根節點都小,那就直接捨棄,否則進行調整,直到這個堆裡面所有的資料都是你要找的最大的那幾個數為止,這樣再進行列印就可以了

主要**如下:

#include"heap.h"

void makeheap(datatype* a, size_t n)//構建堆

}void adjustdown(datatype* a, size_t n, int root)//向下調整

if(a[child]parent])

else

}}void adjustup(datatype* a, size_t n, int child)//向上調整

else

}}void topk(datatype* a, size_t n, size_t k)

for(i=0;i"%d ",a[i]);

}

堆以及堆的相關應用

本文中的堆是一種樹形資料結構,可以把堆看成一種特殊的完全二叉樹,再從二叉樹上加上一些限制條件即可以構成堆。即要求父節點元素全部都大於或等於子節點元素,或者小於等於。這就構成了倆種堆 堆的常見應用為 使用堆進行排序,也就是常說的堆排序,時間複雜度為nlgn 這是比較排序時間複雜度的下限,即使用比較的排...

堆及其應用

對於堆的資料結構的介紹,在網上搜了下,具體講的不是很多。發現比較好的一篇介紹堆的部落格是在此感謝他。通過對上面那篇部落格的學習,然後自己也去翻了下 演算法導論 裡面關於堆排序 heapsort 的介紹。這樣就對堆有了更加深刻的認識,在此,我結合自己的一點點理解,主要還是基於上面那篇部落格的內容 主要...

堆及其應用

應用1.優先順序佇列 優先順序佇列 是不同於先進先出佇列的另一種佇列。每次從佇列中取出的是具有最高優先權的元素。pragma once include include include include heap.h using namespace std template class priority...