文章目錄
- 1.完全二叉樹
- 2.堆向上調整
- 3.堆向下調整
- 4.測試代碼
1.完全二叉樹
下面的這個就是對于我們的完全二叉樹的這個邏輯結構和物理結構的說明:
邏輯結構就是我們自己認為的進行購想出來的;
但是這個物理結構卻是我們的這個數據結構在內存里面的真是進行存儲的這個形態的一個體現;
1)通過下面的這個圖片,我們首先需要知道這個完全二叉樹的定義,其實下面的這個實例很特殊,它既是一個完全二叉樹,也是一個滿二叉樹;
2)我們的這個完全二叉樹它的定義就是他的這個所有的節點進行編號和我們的這個滿二叉樹是一樣的,這個時候我們就把這個樹稱之為完全二叉樹;
3)下面的這個滿二叉樹實際上就是一個完全二叉樹;
4)我們可以看到這個完全二叉樹在我們的這個內存里面實際上是使用這個數組進行存儲的,但是我們在學習這個數據結構的時候,使用的是他的邏輯結構,也就是二叉樹;
2.堆向上調整
這個主要是我們的建堆的過程,就是我們進行建堆的時候,這個數據從我們的葉子結點開始需要進行這個向上調整的過程;
我們從上面的這個建堆的過程是可以看到的,他是需要和自己的這個父親節點不斷地進行比較,直到他的數值比父親節點的數值小,這個大堆才完成;
我們的建堆主要是在下面的這個插入數據的過程里面使用的:我們首先就是進行的這個空間的開辟,最后是調用我們的這個向上調整的函數,這個就是說:我們的這個向上調整就是進行插入的時候保證我們的這個大堆的結構(就是我們插入數據之后,他還是一個堆);
下面的這個:我們的這個child參數就是我們插入的數據,我們的這個函數就是對于這個數據的位置進行調整,使用這個父子節點的關系,我們根據這個子節點的小標,找到這個parent節點的大小;
如果我們的這個兒子數值比我們的這個父親大,這個時候就是需要向上進行調整的,我們的這個調整的方法就是先交換,交換之后讓我們的這個兒子向上走(也就是代碼里面的這個child=parent);
我們的這個child向上之后,這個對應的這個parent也就是需要發生變化的,這個變化就是把我們的這個child-1/2之后的值作為新的這個parent節點的下標;
我們如何去驗證這個調整的結果是否正確:我們去進行這個堆的初始化,向這個里面進行我們的數據的插入,這個時候斷掉調試,hp.a,6----這個就會顯示我們的這個數組里面的6個元素的位置,我們根據這個調試的結果做出來這個對應的樹,這個時候發現我們插入數據之后,這個最后的解構就是一個大根堆(如圖所示);
3.堆向下調整
這個向下調整是如何引出來的,就是我們的這個數據進行插入之后,這個時候我們的大堆的結構就形成了,這個時候我們的這個父親節點肯定就是最大的這個元素,這個時候,我們的處理就是想要知道這個第二大的元素(這個過程實際上就是我們堆排序的雛形,但是這個并不是真正的堆排序);
我們去掉這個父親節點之后,想要直到這個第二大的元素是哪一個,并且去掉這個父親節點之后的這個樹的結構又是什么樣子的,這個時候有些人的方案就是:
1)這個完全二叉樹不就是一個數組嗎,我們的這個父親節點就是這個數組里面的第一個元素,這個時候我們直接把這個后面的所有的元素向前移動不就可以了;
2)但是上面的這個方案是不可取的,主要是因為我們如果使用上面的這個方式進行調整,我們的這個數據之間的這個父子關系就完全發生了變化,因此我們否定這個解法;
3)正確的解法就是我們讓這個父親節點和我們的這個最后的這個節點進行交換,直接使用我們的這個pop刪除這個最后的元素,這個時候原本的最后的一個元素放到了根節點的位置,其他的所有的元素的位置都是不變的,這樣可以維持我們的這個數據之間的這個父子的關系;
4)但是現在他是不符合我們的大根堆的定義的,因此這個時候我們的處理就是讓這個元素向下進行比較,不斷的向下調整-----------這個就是我們的向下調整的這個出現的場景;
下面的這個就是我們進行pop操作的時候,我們需要交換之后size–就可以了,然后我們對于這個時候的0下標的位置的元素向下調整;
這個時候我們的方法就是需要找到這個時候的兩個兒子里面的最大的那個元素:也就是和我們的這個父親節點相鄰的兩個孩子,找到他們里面的較大的一個,如果我們比這兩個里面的較大的一個小,這個時候我們就是需要進行調整的,這個里面的child+1<N是為了防止越界;
這個while控制的是我們的這個比較的過程是不是到達了根節點,第一個if是默認我們的這個左邊的孩子是最大的,如果發現是這個右邊的比左邊的大,我們的這個child++,同時如果出現了這個只有左邊的孩子,沒有右邊的孩子,這個時候child+1就會越界,因此我們使用這個child+1防止越界;
下面的這個就是我們的4和17里面的這個較大的就是17,因此我們的這個3就需要和我們的17進行比較,這個時候發現是不滿足我們的這個大根堆的定義的,因此這個就需要向下調整:
child的值賦值給我們的parent,這個時候新的child就是我們這個時候的parent*2+1即可;
4.測試代碼
這個時候,我們既可以隨機的插入數據,打印這個大堆的結果;
我們也可以插入很多的數據,使用這個k限制,打印出來有限多個數據,兩個方式都是可以的;
這個時候,我們既可以隨機的插入數據,打印這個大堆的結果;
我們也可以插入很多的數據,使用這個k限制,打印出來有限多個數據,兩個方式都是可以的;