本文作為堆的基礎,只涉及最基礎的二叉堆。同時為了行文方便,約定本文中的堆都是大根堆。
這是二叉堆。
而這是下篇文章要講的bst。
(它們倆差別還是挺大的)。
而二叉堆,就是每個父節點下面至多有兩個子節點的一種堆。
細心的應該有人發現了:堆的左右兒子好像沒有明顯大小關係。左兒子可以大於右兒子,也可以小於。而且左子樹內的元素大小也和另乙個子樹完全沒有關係。也就是說,二叉堆中只有根節點最大這麼一條限制,下面的想怎麼玩兒就怎麼玩兒。
而這個也帶來了一些不便——顯然只有訪問最大值是比較方便的。stl當中的優先佇列,就是二叉堆。
接下來來講一下二叉堆是如何使用的。
以下的二叉堆都是以陣列作為載體,和線段樹一樣。由於二叉堆的這種二分結構,因此它訪問子節點和父節點的方式和線段樹一樣:
左兒子:place<<1
右兒子:place<<1|1
父節點:place>>1
與其說它在建堆,不如說它只是在調整數列中數的順序,讓它符合堆的要求。
首先來看它的操作過程。約定:陣列長度為n,堆的大小也為n。
先來看乙個最基礎的操作——max_heaplify(維護堆性質)
現在有乙個亂序的陣列:1,8
,3,7
,4,5
,2,9
,61,8,3,
7,4,
5,2,
9,6。為了觀察便利,畫成乙個二叉堆的形式。
顯然它不符合二叉堆的性質,因而需要調整。我們先從最簡單的結構看起:
紅色標出的結構中,如果這裡都不滿足那不用看了。那我們應該怎麼做呢?
顯然兩個兒子都比根大,這是不合規矩的。由於根是根、左右兒子這三者中最大的元素,我們只需要找到左右兒子中大的,往上放就可以了。
標紅的結構就已經搞好了。顯然二叉堆就是由大量的這樣的小結構構成的,對於每乙個這樣的小結構都可以使用這種方法處理,然後整合起來,就可以了。
但是可以注意到,我們上來先搞堆頂,使得下面不一定滿足,因此真正建堆的時候是從下往上處理的。
因此在建堆的時候,首先是要先維護堆的性質(max_heaplify)。這一過程通常像線段樹一樣遞迴操作。
void
max_heapify
(int place)
}
由主方法可以知道,它的單步複雜度僅為logn。
當然它也有迭**法,這裡不再贅述。
然後,就要建堆。這一過程仰賴維護堆性質這一過程,**非常簡單:
for
(int i=n/
2;i>=
1;i--
)//從後往前的進行,這樣就不會造成二次修改
max_heaplify
(i);
這樣就可以建起乙個大根堆了,按照次序訪問這個堆,就可以給陣列排序。這就是堆排序,時間複雜度nlogn。
由於我們是陣列,顯然不便於插入到陣列的中間。因此每次操作的時候插入到陣列尾端就行。
但是這樣又可能破壞了大根堆的性質,因而需要調整函式(shiftup)。首先來看看它的操作過程。
這是現有的一顆二叉樹。節點上方編號為陣列下標。
現在我們要插入元素15,放入下標為13的地方。
顯然這樣做之後6、12、13這個小大根堆的性質被破壞了,進行調整:把子節點中大的換上來,根換下去。
然後3、6、7這個大根堆又壞了……繼續調整。
現在1、2、3這三者關係總算是符合了,可以停止了。
因此總結一下:從最後面插入,依次上浮,直到無法調整或者已經到頂。顯然每一層只用操作一次,複雜度logn
上**:
void
shiftup
(int place)
}
由主定理可以知道時間複雜度僅為logn——每層就操作了乙個數。
這裡的彈出元素,通常是指彈出最大值,也就是堆頂。顯然我們很容易訪問到最大值——畢竟就在陣列的第乙個元素。但是如果要彈出怎麼辦呢?
我們拿上乙個插入好了的二叉堆舉例。
我們現在要彈出16了。
但是乙個堆不能沒有根啊。於是我們就找葉節點來頂。因為這樣就不存在子節點又沒有父親的情況。於是我們把最後乙個元素頂上來。
那現在這個不就變成了維護堆的性質嗎?heaplify走起。
所以我們的過程就是——把最後乙個元素放上來,然後從上到下進行一次更新(heaplify)。總複雜度logn。這樣做也是盡可能不破壞二叉堆的結構,讓樹保持相對平衡的狀態,而不會退化成鏈增加複雜度。
void
pop(
)
資料結構學習筆記 二叉樹
樹,非線性表結構 樹有三個概念 高度從下向上數,起點是0 深度從上向下數,起點是0 層數從上向下數,起點是1 每個節點最多兩個叉 有兩種特殊二叉樹 滿二叉樹,除了葉子節點,每個節點都有左右兩個子節點 完全二叉樹,葉子節點都在最底下兩層,最後一層葉子節點都靠左排列,且除了最後一層,其它層節點個數都達到...
資料結構 二叉堆
二叉堆一般用來實現優先佇列 優先佇列是一種至少允許以下兩種操作的資料結構 insert 以及 deletemin 同查詢樹一樣,二叉堆具有結構性與堆序性,對二叉堆的基本操作可能會破壞這些性質,所以二叉堆的操作要直到其基本性質滿足才能結束。一 結構性 二叉堆在結構上為完全二叉樹,其具有完全二叉樹的結構...
資料結構 二叉堆
二叉堆 優先佇列 具有結構性和堆序性 結構性為 二叉堆是一棵完全被填滿的二叉樹,有可能的例外是在底層,底層上的元素從左到右填入。這樣的樹稱為完全二叉樹。二叉堆可以用陣列表示,對於陣列中任意位置i上的元素,其左兒子在位置2i上,右兒子在位置2i 1上,父親則在i 2上 小於i 2的最小整數 堆序性為 ...