程式碼隨想錄第13天 | 二叉樹part01 基礎和遍歷

跳圈發表於2024-06-22

二叉樹基礎知識

二叉樹種類

滿二叉樹
滿二叉樹:如果一棵二叉樹只有度為0和度為2的結點,並且度為0的結點在同一層上,則這棵二叉樹為滿二叉樹(子節點要麼為0,要麼為2)
若滿二叉樹的深度為k(即k層,從1開始),則其節點個數為:2^k-1
完全二叉樹
完全二叉樹:從上到下,從左到右,都是連續的。 滿二叉樹一定是完全二叉樹。
優先順序佇列是一個堆,堆就是完全二叉樹
二叉搜尋樹
節點是有順序的,
若左子樹不為空,左子樹上節點的值小於根節點,
若右子樹不為空,右子樹上節點的值大於根節點
平衡二叉(搜尋)樹
它是一顆空樹或左右子數的高度差絕對值不超過1.並且左右子數都是一顆平衡二叉(搜尋)樹。
map、set、multimap、multiset 的底層實現都是平衡二叉樹,所以是有序的。

二叉樹的儲存方式

鏈式儲存
使用指標來連線左子樹和右子樹,一般用鏈式
線性儲存(記憶體連續分佈)
使用陣列來村儲存
計算孩子節點:若父節點陣列下標為n,則左孩子節點為2n+1,右孩子節點為2n+2;

二叉樹的遍歷

二叉樹主要有兩種遍歷方式:

  1. 深度優先遍歷:先往深走,遇到葉子節點再往回走。
    1.前序遍歷(遞迴法,迭代法(就是非遞迴方法)) 中左右
    2.中序遍歷(遞迴法,迭代法)左中右
    3.後序遍歷(遞迴法,迭代法)左右中
    深度優先遍歷,一般使用遞迴的方式來實現,使用棧結構,棧就是遞迴的一種實現結構,
  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.二叉樹的中序遍歷

思路:

  1. 遞迴三要素,引數返回值,終止條件,單層迴圈

程式碼:

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.二叉樹的層序遍歷Ⅱ

思路:

  1. 層序遍歷,然後翻轉,計算陣列大小,首尾對調
  2. 翻轉直接用reverse 因為vector的定義是 vector<vector<int>> result; result的元素就是vector

題目:199.二叉樹的右檢視

思路:

  1. 一直遍歷右子樹,遞迴,但不行,不一定從右邊看到的都是右子樹
  2. 同上,層序遍歷,結果只儲存每層遍歷的最後一個值。

坑:

佇列定義的時候,注意型別。不要預設是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.二叉樹的最小深度

思路:

同上,不過左右孩子都為空時,才是遍歷到葉子結點了

今日總結

二叉樹分類,深度和廣度遍歷

相關文章