資料結構 堆及堆的應用

2021-07-25 17:47:35 字數 4188 閱讀 6188

堆是一種特殊的樹形結構,堆的把每乙個節點都有乙個值,我們通常所說的堆這種資料結構,指的就是二叉堆。  

其實它可以被看做乙個完全二叉樹。

它的每個節點的子樹又可以被看做是堆。

堆可以分為最大堆和最小堆:

最大堆:每個父節點都大於孩子節點

最小堆:每個父節點都小於孩子節點

a:我們在定義堆的資料成員的時候,利用stl中的vector來進行資料成員的建立(為什麼要這麼做,我後面有說明)

vector_a
b:然後我們肯定是要給出建構函式

//建構函式

heap(){}

c:接著我們就來進行建堆,這裡用到了乙個很重要的方法:

向下調整演算法

(我這裡以建乙個大堆為例)

如上圖:

##向下調整演算法的說明:

*要建乙個大堆,即最後每乙個堆的節點的值都大於它的孩子

*我們先找左右孩子中最大的乙個

*然後讓最大的乙個孩子和父節點進行比較:

如果孩子大於父節點的值,那麼進行交換,並將孩子的值賦給父節點,孩子的值也隨父節點的值變化

否則就結束

*進行向下調整是從根節點開始的,因此,最終的大迴圈是孩子的值要小於陣列儲存的元素的值

##建堆

*我們最終的目的是要建乙個大堆

*每乙個葉子節點都是乙個堆

*因此,我們要從第乙個非葉子節點開始進行建立,然後逐步呼叫向下調整演算法,實現大堆的建立

【說明】:

關於使用vector來作為堆的資料成員的好處:

使用vector了之後,我們在實現堆類的成員函式的時候,就不用顯示的給出拷貝建構函式,賦值運算子過載函式和析構函式了,因為當我們用vector進行物件的建立的時候,編譯器就會自動的呼叫vector的這些成員函式,我們就不用多此一舉的進行給出了。

//建堆

heap(t* a, size_t n)

:_a(a,a+n) }

//向下調整

void _adjustdown(int root)

//將孩子和父母做比較

if(_a[child]>_a[parent])

else}}

a:尾插函式的實現:

思路分析:先在尾部插入乙個元素,然後要進行

向上調整

##向上調整演算法:和向下調整演算法很相似

*直接讓孩子和父節點進行比較

如果孩子比父節點大的話,就將父親賦給孩子,然後父親的值進行改變,一直網上調整

否則結束

*調整結束的另乙個結束條件是當調整到最上面的堆頂的時候結束,即就是孩子的值<0

**如下:

//尾插

void push(const t& x)

//向上調整

void _adjustup(int i)

else}}

b:堆頂元素刪除的實現

思路分析:

*先將要刪除的堆頂的元素和最後乙個元素進行交換

*然後刪除尾部的元素

*再進行向下調整

**實現:

//尾刪

void pop()

#概念:與普通的先進先出的佇列不同的是,優先順序佇列每次都會取出佇列中優先順序最高的那乙個

#如何實現:(這裡我們通過堆來實現優先順序佇列)

*首先:優先順序有高的優先順序最高,低的優先順序最高,這裡我們如何進行這兩個的控制:使用仿函式來進行實現

*其次:我們是結合堆來進行具體實現的,所以優先順序佇列的一系列介面我們就通過直接呼叫堆裡的介面就可以了

#**實現:

#include#includeusing namespace std;

templatestruct less

};template>

class heap

//建堆

heap(t* a, size_t n)

:_a(a,a+n) }

//尾插

void push(const t& x)

//尾刪

void pop()

//求堆裡元素的個數

size_t size()

//求堆頂的元素

t& top()

//判斷堆是否為空

bool empty()

protected:

//向下調整

void _adjustdown(int root)

//將孩子和父母做比較

if(com()(_a[child],_a[parent]))

else

}} //向上調整

void _adjustup(int i)

else

}}protected:

vector_a;

};template>

class priorityqueue

void push_back(const t& x)

void pop_front()

size_t pq_size()

t& pq_top()

bool pq_empty()

protected:

heap_hp;

};int main()

; heaphp1(a,sizeof(a)/sizeof(a[0]));

hp1.push(20);

hp1.pop();

priorityqueue> hep2;

hp2.push_back(4);

return 0;

}

問題描述:  n個資料,此n 個數很大,找出最大的前k個

思路分析:

方法一:我們首先會想到排序(外排):因為是n個資料,並且n個資料是比較大的,有的讀者可能會想到用陣列進行儲存,但是當資料非常大的時候,記憶體會不足,我們總不可能要買記憶體吧。但是外排是在磁碟上的,效率會很低。時間複雜度是nlg(n).

方法二:利用堆來進行實現

*我們首先建立乙個k大小的堆,

*接著,我們是要找最大的前k個數,我們應該建大堆還是小堆呢,可能很多讀者會不假思索的說建大堆,但是我們來仔細的考慮下,如果建大堆的話,堆頂的元素就是最大的,那麼後面的元素就進不來了,只會找到乙個最大的元素,所以我們要建小堆。

*我們建好堆後,每次將來的乙個元素和堆頂的元素進行比較,如果大於堆頂的元素的話,那麼我們就將此元素直接賦給堆頂的元素。然後進行向下調整

**的實現:

/*函式說明:有n個資料,找最大的前k個*/

#includeusing namespace std;

void _adjustdown(int* a,int n,int root)

//將頂部的元素和後面的元素進行比較,如果比

//頂部的元素大,直接賦值,然後向下調整

for(int i = k; i_heap[0])

}for(int i = 0; i

思路分析:

*如果我們是公升序的話,要建大堆

*將第乙個元素和最後乙個元素進行交換,然後進行向下調整

*然後迴圈第二步,知道堆裡剩乙個元素,結束

**分析:

#include#includeusing namespace std;

templateclass heap

//建堆

heap(t* a, size_t n)

:_a(a,a+n) }

//堆排

void heapsort()

int end = _a.size()-1;

while(end>0)

}protected:

//向下調整

void _adjustdown(int root)

//將孩子和父母做比較

if(_a[child]>_a[parent])

else

}} //向上調整

void _adjustup(int i)

else

}}protected:

vector_a;

};

堆排的時間複雜度是:klg(k)+lg(k)*(n-k) =nlg(k)

資料結構 堆及堆的應用

1.堆 把一組資料按照完全二叉樹的順序儲存模式儲存在乙個二維陣列中,若ai 若ai ai 1 ai ai 2,則稱為大堆 i 0,1,2.n 在堆中,若設父親節點為parent,則它的左孩子為2 parent 1,右孩子為2 parent 2 void makeheap datatype a,siz...

資料結構 堆的應用

public class heap 插入操作的 public void insert int value count a count value 插入後,從節點開始從下往上開始堆化,插入 自下往上堆化 int i count while i 2 0 a i a i 2 public int remo...

資料結構綜合應用 堆

動態維護中位數問題,可以用堆,樹狀陣列,線段樹等資料結構解決 堆,可以用來進行插入,查詢最值,刪除最值等操作 對頂堆 一大根堆和一小根堆,大根堆維護最小值,小根堆維護最大值。洛谷1168 題意 每輸入奇數個數字,實時輸出中位數 解題思路 定義乙個對頂堆,輸入第乙個數字,並作為中位數輸出,每輸入乙個數...