二叉樹基礎知識
二叉樹種類
滿二叉樹
滿二叉樹:如果一棵二叉樹只有度為0和度為2的結點,並且度為0的結點在同一層上,則這棵二叉樹為滿二叉樹(子節點要麼為0,要麼為2)
若滿二叉樹的深度為k(即k層,從1開始),則其節點個數為:2^k-1
完全二叉樹
完全二叉樹:從上到下,從左到右,都是連續的。 滿二叉樹一定是完全二叉樹。
優先順序佇列是一個堆,堆就是完全二叉樹
二叉搜尋樹
節點是有順序的,
若左子樹不為空,左子樹上節點的值小於根節點,
若右子樹不為空,右子樹上節點的值大於根節點
平衡二叉(搜尋)樹
它是一顆空樹或左右子數的高度差絕對值不超過1.並且左右子數都是一顆平衡二叉(搜尋)樹。
map、set、multimap、multiset 的底層實現都是平衡二叉樹,所以是有序的。
二叉樹的儲存方式
鏈式儲存
使用指標來連線左子樹和右子樹,一般用鏈式
線性儲存(記憶體連續分佈)
使用陣列來村儲存
計算孩子節點:若父節點陣列下標為n,則左孩子節點為2n+1,右孩子節點為2n+2;
二叉樹的遍歷
二叉樹主要有兩種遍歷方式:
- 深度優先遍歷:先往深走,遇到葉子節點再往回走。
1.前序遍歷(遞迴法,迭代法(就是非遞迴方法)) 中左右
2.中序遍歷(遞迴法,迭代法)左中右
3.後序遍歷(遞迴法,迭代法)左右中
深度優先遍歷,一般使用遞迴的方式來實現,使用棧結構,棧就是遞迴的一種實現結構, - 廣度優先遍歷:一層一層的去遍歷。
層次遍歷(迭代法)
廣度優先遍歷,一般使用佇列來實現
二叉樹的遞迴遍歷
遞迴演算法三要素
- 確定遞迴函式的引數和返回值
- 確定遞迴函式的終止條件
- 確定單層遞迴條件
//Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
題目:144.二叉樹的前序遍歷
題目:145.二叉樹的後序遍歷
題目:94.二叉樹的中序遍歷
思路:
- 遞迴三要素,引數返回值,終止條件,單層迴圈
程式碼:
class Solution {
public:
void Traversal(TreeNode *cur,vector<int> &vec){ //注意vector是引用
if(cur==nullptr)
return;
vec.push_back(cur->val);
Traversal(cur->left,vec);
Traversal(cur->right,vec);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
Traversal(root,result);
return result;
}
};
二叉樹的層序遍歷
題目:102.二叉樹的層序遍歷
思路:
0.確定二維陣列儲存節點的值,使用佇列進行遍歷,隊首彈出儲存過值的節點,隊尾新增被彈出節點的左子樹、右子樹,計算每層的大小,在佇列中彈出對應數量,每一層的值存入一個陣列中,
程式碼:
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
queue<TreeNode*> que; //這裡是*
if(root!=nullptr)
que.push(root) ; //編譯報錯 root可能為空
while(!que.empty()){
vector<int> vec;
int size=que.size();
while(size--){
TreeNode* node=que.front();
vec.push_back(node->val);
if(node->left!=nullptr)
que.push(node->left);
if(node->right!=nullptr)
que.push(node->right);
que.pop();
}
result.push_back(vec);
}
return result;
}
};
題目:107.二叉樹的層序遍歷Ⅱ
思路:
- 層序遍歷,然後翻轉,計算陣列大小,首尾對調
- 翻轉直接用reverse 因為vector的定義是
vector<vector<int>> result;
result的元素就是vector
題目:199.二叉樹的右檢視
思路:
- 一直遍歷右子樹,遞迴,但不行,不一定從右邊看到的都是右子樹
- 同上,層序遍歷,結果只儲存每層遍歷的最後一個值。
坑:
佇列定義的時候,注意型別。不要預設是int
queue<TreeNode*> queue;
題目:637.二叉樹的層平均值
思路:
同上,每層結果取平均值
坑:
報錯,超出記憶體,忘了出隊。
題目:429.N叉樹的層序遍歷
思路:
類似,每個節點,判斷孩子數是否全部被新增完
題目:515.在每個樹行中找最大值
思路:
同上,遍歷的時候,挨個比較,儲存最大值
題目:116.填充每個節點的下一個右側節點指標
思路:
這個是定義的“完美”二叉樹
遍歷時,儲存上一個節點,判斷當前節點是否有左孩子,沒有就右孩子,使其指向下一個右側節點,當size==0時,指向null
題目:117.填充每個節點的下一個右側節點指標II
思路:
這個是二叉樹
同上
題目:104.二叉樹的最大深度
思路:
0.0遞迴,一直找子樹,直到為null,返回,記錄次數
0.1棧儲存,遍歷到null的時候計算棧長度
返回值是長度,引數是節點和&儲存長度的變數
終止條件是節點的孩子數為0
單層迴圈,中序遍歷,
啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊,有簡單的啊啊啊啊啊,嗎嘍心塞塞.jpg
1.層序遍歷,計算層數,使用迭代法(非遞迴),深度嘛,就是層數啊
題目:111.二叉樹的最小深度
思路:
同上,不過左右孩子都為空時,才是遍歷到葉子結點了
今日總結
二叉樹分類,深度和廣度遍歷