注意大家在學(xué)習(xí)編程的過(guò)程中, 肯定聽(tīng)說(shuō)過(guò)內(nèi)存中的堆和棧以及靜態(tài)區(qū)這種的, 這些是屬于操作系統(tǒng)虛擬進(jìn)程地址空間中的,
我們要說(shuō)的堆和這個(gè)并不是一回事,堆是二叉樹(shù)的一種, 是數(shù)據(jù)結(jié)構(gòu)的一種,我們來(lái)看看吧
普通的二叉樹(shù)不使用數(shù)組來(lái)存儲(chǔ),只有堆用數(shù)組來(lái)存儲(chǔ),
所以說(shuō)堆的邏輯結(jié)構(gòu)是二叉樹(shù), 物理結(jié)構(gòu)是數(shù)組
如果有一個(gè)關(guān)鍵碼的集合K = { , , ,…, },把它的所有元素按完全二叉樹(shù)的順序存儲(chǔ)方式存儲(chǔ),在一個(gè)一維數(shù)組中,并滿(mǎn)足:<= 且<= ( >= 且 >= ) i = 0,1,2…,則稱(chēng)為小堆(或大堆)。將根節(jié)點(diǎn)大的堆叫做大堆或大根堆,根節(jié)點(diǎn)最小的堆叫做最小堆或小根堆
堆的性質(zhì):
- 堆中某個(gè)節(jié)點(diǎn)的值總是不大于或不小于其父節(jié)點(diǎn)的值;
- 堆總是一棵完全二叉樹(shù)。
小堆: 子節(jié)點(diǎn)都比不小于父節(jié)點(diǎn)
大堆
堆的實(shí)現(xiàn)那我們嘗試用數(shù)組來(lái)實(shí)現(xiàn)這種數(shù)據(jù)結(jié)構(gòu)
類(lèi)的定義那我們來(lái)分析一下堆這個(gè)類(lèi)中需要哪些成員,
templateclass Heap
{public:
Heap();
void push(T val);
void pop();
T Top();
bool empty();
size_t size();
~Heap();
private:
T* _data;
int _top;//指向最后一個(gè)數(shù)據(jù)的下一個(gè)位置
int _capacity;
};
構(gòu)造函數(shù)默認(rèn)構(gòu)造就是把成員都初始化一下,我這里沒(méi)有開(kāi)默認(rèn)空間, 大家可以選擇開(kāi)
Heap()
:_data(nullptr)
, _top(0)
, _capacity(0)
{}
析構(gòu)函數(shù)析構(gòu)函數(shù)進(jìn)行資源清理,所以要把申請(qǐng)的空間都釋放掉
~Heap()
{free(_data);
_top = _capactiy = 0;
}
pushpush就是插入一個(gè)數(shù)據(jù),堆這里的插入和其他數(shù)據(jù)結(jié)構(gòu)不同, 堆插入任何一個(gè)數(shù)據(jù)都要保證堆的特性, 不可以本來(lái)是堆,最后不是堆, 我們來(lái)分析一下,我們這里都以建大堆為例子
插入的代碼比較簡(jiǎn)單,關(guān)鍵是向上調(diào)整,插入唯一需要注意的就是擴(kuò)容的問(wèn)題
void push(T val)
{//如果容量 == 個(gè)數(shù)
if (_capacity == _top)
{//擴(kuò)容 -- >2倍擴(kuò)容
int newCapacity = _capacity == 0 ? 4 : _capacity * 2;
T* ptr = (T*)realloc(_data, sizeof(T) * newCapacity);
if (nullptr == ptr)
{ perror("realloc fail");
exit(-1);
}
_capacity = newCapacity;
_data = ptr;
}
//擴(kuò)容完畢
_data[_top] = val;
//++ 長(zhǎng)度
++_top;
//向上調(diào)整
AdjustUp(_data, _top - 1);
}
向上調(diào)整為了保證堆的特性而向上調(diào)整,
那我們來(lái)分析一下這個(gè)向上調(diào)整該如何實(shí)現(xiàn)
void AdjustUp(T* data, int child)
{int parent = (child - 1) / 2;
while (child >0)
{ //這里是以大堆為例,如果孩子大于父親, 那么就調(diào)整
if (data[child] >data[parent])
{ swap(data[child], data[parent]);
//迭代
child = parent;
parent = (child - 1) / 2;
}
else
{ break;
}
}
判斷堆是否為空這個(gè)相對(duì)比較簡(jiǎn)單
bool empty()
{//如果top等于0為空
return _top == 0;
}
返回堆中有效數(shù)據(jù)個(gè)數(shù)size_t size()
{return _top;
}
返回堆頂?shù)臄?shù)據(jù)首先要判斷堆是否為空, 如果堆不為空, 還取個(gè)啥啊
T Top()
{assert(!empty());
return _data[_top - 1];
}
pop數(shù)據(jù),刪除堆頂?shù)臄?shù)據(jù)我們來(lái)分析一下
void pop()
{assert(!empty());
//交換堆頂?shù)臄?shù)據(jù)和最后一個(gè)數(shù)據(jù)
swap(_data[0], _data[_top - 1]);
--_top;
//向下調(diào)整
AdjustDown(_data, n, 0);
}
向下調(diào)整核心思想就是如果大孩子大于根節(jié)點(diǎn), 就交換,直到最后歐一層
void AdjustDown(T* data, int n, int parent)
{//先給出左孩子
int child = parent * 2 + 1;
while (child< n)
{ //如果右孩子存在,并且比左孩子大
if (child + 1< n && data[child + 1] >data[child])
child++;
if (data[child] >data[parent])
{ swap(data[child], data[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{ break;
}
}
}
堆的應(yīng)用
TopK問(wèn)題堆排序關(guān)于TopK問(wèn)題,用堆解決是非常合適的問(wèn)題,我之前寫(xiě)過(guò)一篇 TopK問(wèn)題詳解
堆排序是一種非常厲害的排序, 核心思想就利用了堆這種數(shù)據(jù)結(jié)構(gòu),我們來(lái)看看吧,我們距離
如果排升序的話(huà),我們建小堆還是大堆呢??我們來(lái)分析一下
那我們?cè)撊绾谓ǘ涯?
插入建堆
int arr[] = {6,1,2,7,9,3,4,5,10,8 };
int len = sizeof(arr) / sizeof(int);
for (int i = 1; i< len; ++i)
{AdjustUp(arr, i);
}
2.第二種建堆方式—>向下調(diào)整向下調(diào)整建堆就是二叉樹(shù)的典型分治思想,我們來(lái)分析一下
int arr[] = {6,1,2,7,9,3,4,5,10,8 };
int len = sizeof(arr) / sizeof(int);
//建堆 最后一個(gè)節(jié)點(diǎn)的下標(biāo)是len-1 ,所以它的父親下標(biāo)是(len-2)/2
for (int i = (len - 1 - 1) / 2; i >= 0; --i)
{AdjustDown(arr, len, i);
}
排序所以更推薦使用向下調(diào)整的方式來(lái)建堆,因?yàn)閺?fù)雜度比較低
建好堆了以后就相對(duì)比較簡(jiǎn)單了,
利用堆的特性, pop的思想,把大的放到最后面, 然后調(diào)整前面的
void HeapSort(int* arr, int len)
{//建堆
for (int i = (len - 1 - 1) / 2; i >= 0; --i)
{AdjustDown(arr, len, i);
}
int end = len - 1;
while (end >0)
{swap(arr[0], arr[end]);
AdjustDown(arr, end, 0);
--end;
}
}
建堆的復(fù)雜度O(N) , 調(diào)整的復(fù)雜度O(N* logN)
所以堆排序的復(fù)雜度就是O(N*logN)
總結(jié)堆還是非常常用的,一定要利用堆的特性, 后面的優(yōu)先級(jí)隊(duì)列還會(huì)涉及到,
感謝收看
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
當(dāng)前題目:[數(shù)據(jù)結(jié)構(gòu)]二叉樹(shù)--堆-創(chuàng)新互聯(lián)
轉(zhuǎn)載來(lái)源:http://jinyejixie.com/article24/ceedce.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶(hù)體驗(yàn)、動(dòng)態(tài)網(wǎng)站、網(wǎng)站內(nèi)鏈、云服務(wù)器、電子商務(wù)、服務(wù)器托管
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容
全網(wǎng)營(yíng)銷(xiāo)推廣知識(shí)