《啊哈演算法》第七章 神奇的樹
參考:《啊哈演算法》
樹
樹其實就是不包含迴路的連通無向圖
**
連通是說其其中任意兩點之間是可達的
不包含迴路就是說一定能夠不會出現走一圈的情況
**
樹的特性
一棵樹中的任意兩個結點有且僅有唯一的一條路徑連通
一棵樹如果有n個結點,那麼它一定恰好有n-1條邊
在一棵樹中加一條邊將會構成迴路
為了確定一棵樹的形態,在樹中可以指定一個特殊的結點—–根
如果一個結點沒有子結點,這個結點就稱為葉結點。
沒有父結點的結點稱為根結點。
如果一個結點既不是根結點也不是葉結點,則稱為內部結點。
每個結點還有深度,深度是指從根結點到這個結點的層數(根為第一層)
二叉樹
嚴格遞迴定義:二叉樹要麼為空,要麼由根結點、左子樹和右子樹組成,而左子樹和右子樹分別是一棵二叉樹
二叉樹中還有兩種特殊的二叉樹:
滿二叉樹
所有的葉結點都有相同的深度完全二叉樹
如果一棵二叉樹除了最右邊位置上有一個或者幾個葉結點缺少外,其他事豐滿的二叉樹,就是滿二叉樹。
(完全二叉樹的典型應用就是堆)
堆—神奇的優先佇列
所有的父結點都比子結點要小的完全二叉樹稱為最小堆(小頂堆)
所有的父結點都比子結點要大的完全二叉樹稱為最大堆(大頂堆)
完全二叉樹一個性質:最後一個非葉結點是第n/2個結點
建堆及堆排序的展示(小頂堆)
演算法分析:先輸入資料存在陣列中建立一棵完全二叉樹,然後從最後一個非葉結點一次向前進行調整。調整結束後就滿足小頂堆,根結點就是最小值,此時記錄下根結點,並將其從堆中刪除,將最後一個結點送到根結點的位置,此時不滿足小頂堆,我們就向下調整使其再次滿足。重複步驟至完全二叉樹為空
#include <iostream>
#include <cstdio>
using namespace std;
//向下調整
int h[102];
int n;
void siftdown(int i) {
int t,flag;
while(i*2<=n&&flag==0) {
if(h[i]>h[i*2]) {//先於左結點比
t=i*2;
} else {
t=i;
}
if(i*2+1<=n) {//是否有右結點
if(h[t]>h[i*2+1]) {
t=i*2+1;
}
}
if(t!=i) {
swap(h[i],h[t]);//交換
i=t;
} else {
flag=1;//滿足頂堆條件的訊號傳出
}
}
}
//建堆
void create() {
//從最後一個非葉結點到第一個結點依次進行向下調整
for(int i=n/2; i>=1; i--) {
siftdown(i);
}
}
//刪除最大元素
int deletemax() {
int t;
t=h[1];//用臨時變數記錄堆頂點的值
h[1]=h[n];//將堆的最後一個頂點賦值到堆頂
n--;//堆元素少一
siftdown(1);//向下調整
return t;//返回記錄的堆的頂點的最小值
}
int main() {
int num;
scanf("%d",&num);
for(int i=1; i<=num; i++) {
scanf("%d",&h[i]);
}
n=num;
create();
for(int i=1; i<=num; i++) {
printf("%d ",deletemax());
}
return 0;
}
測試樣例
14
99 5 36 7 22 17 46 12 2 19 25 28 1 92
當然還可以通過建立大頂堆的方式進行堆排序。
雖然這裡的堆排序看上去很是費時,但是要是使用在新增一個數,或者新增一個數同時刪除一個數的情況時就比較的高效了。比如我們刪除一組數的最小值,並新增一個數,同時求新陣列的最小值時。直接將新增的數放到小頂堆的堆頂(本身這裡之前是最小的數),然後調整到符合小頂堆時的堆頂就是新的最小值。
另外要是我們新增一個數,但是不進行任何刪除操作,只是最快求出新的最小值時,只需要將新增的數新增到最後。然後一路向上調整至符合要求,新的堆頂就是新的最小值。
堆還經常被用作求一個數列中第k大的數,只需要建立一個大小為k的小頂堆,堆頂就是第k大的數
相關文章
- JavaScript實現《啊哈!演算法》中的系列演算法JavaScript演算法
- 啊哈
- 《啊哈!演算法》我要做月老 ——二分圖最大匹配演算法
- 《啊哈!演算法》-第 2 章:棧、佇列、連結串列演算法佇列
- 演算法金 | Transformer,一個神奇的演算法模型!!演算法ORM模型
- 神奇的字串匹配:擴充套件KMP演算法字串匹配套件KMP演算法
- 揭秘語音識別演算法的神奇之處演算法
- 第七章 回溯演算法part01演算法
- 第七章 回溯演算法part03演算法
- 神奇的yield
- 神奇的 CanvasCanvas
- 最小生成樹的演算法演算法
- 神奇的npm -- scriptsNPM
- 神奇的莫隊
- #define 的神奇操作
- Day22 第七章 回溯演算法part01演算法
- 生成樹演算法演算法
- 【演算法】字首樹演算法
- 演算法技能樹演算法
- 演算法筆記 - 樹的直徑演算法筆記
- 神奇的Cookie互通魔法Cookie
- 這神奇的程式碼
- 新的神奇的部署策略
- 初級演算法-樹演算法
- 決策樹演算法演算法
- 樹佈局演算法演算法
- 演算法 最小高度樹演算法
- 第七章
- 最小生成樹(MinSpanTree)的Kruskal演算法演算法
- 神奇的位非運算
- JS神奇的或0(|0)JS
- 神奇的魔方陣--(MagicSquare)(1)
- 【LeetCode】初級演算法:樹LeetCode演算法
- 演算法-二叉樹演算法二叉樹
- Day25 第七章 回溯演算法part04 回溯終章演算法
- [Golang]力扣Leetcode—初級演算法—樹—二叉樹的最大深度Golang力扣LeetCode演算法二叉樹
- 最常用的決策樹演算法!Random Forest、Adaboost、GBDT 演算法演算法randomREST
- Reinventing the wheel:決策樹演算法的實現演算法
- k近鄰演算法的實現:kd樹演算法