首页 > 其他分享 >(14/60)二叉树理论基础、递归遍历、迭代遍历、统一迭代

(14/60)二叉树理论基础、递归遍历、迭代遍历、统一迭代

时间:2024-02-06 21:22:18浏览次数:32  
标签:结点 right TreeNode val 迭代 st 遍历 二叉树 left

二叉树理论基础

分类

  1. 满二叉树:只有度为0和度为2的结点,且度为0结点在同一层上(每一层的结点都是满的)。

  2. 完全二叉树:除了底层外其他层结点都是满的(底层当然也可以是满的),且底层结点从左往右连续不断。

  3. 二叉搜索树:

    树的每个结点满足:

    • 左子树所有结点值均小于根结点的值
    • 右子树所有结点值均大于根结点的值
    • 左右子树分别是二叉排序树
  4. 平衡二叉搜索树:二叉搜索树的基础上,满足左右子树高度差绝对值不超过1。

    map、set、multimap、multiset底层实现就是平衡二叉树,所以增删操作时间复杂度为O(logN),同时也是有序的。

存储方式

  1. 链式存储(链表):结点元素、左指针、右指针。
  2. 线性/顺序存储(数组):2*i + 1是左孩子;2*i + 2是右孩子。

遍历方式

深度优先搜索DFS

  1. 前序遍历:中左右
  2. 中序遍历:左中右
  3. 后序遍历:左右中

广度优先搜索BFS

  • 层序遍历

定义方式

// 链式为例
struct TreeNode{
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x),left(NULL),right(NULL);
};

遍历二叉树

leetcode:

递归遍历

思路

前序遍历,中左右。

因此单层递归逻辑就是:1. 记录当前结点val;2. 递归当前结点左孩子;3. 递归当前结点右孩子。

复杂度分析

时间复杂度:O(N)。遍历一遍二叉树结点。

空间复杂度:O(N)。最坏情况下,二叉树完全偏斜成为一条链,递归深度会达到N。

注意点

递归三部曲

  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) {}
 * };
 */
class Solution {
public:
    void preTraverse(TreeNode* root,vector<int>& result){
        if(root == NULL)
            return;
        // 前序:中左右
        result.push_back(root->val);
        preTraverse(root->left,result);
        preTraverse(root->right,result);
    }
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        preTraverse(root,result);

        return result;
    }
};

迭代遍历(前序、后序)

思路

前序遍历为例,中左右。(后序遍历就是先入栈左孩子、再入栈右孩子,得到中右左,逆序得到左右中)

  1. 先把根节点放入栈中

  2. 元素出栈,val存入数组中;(注意判断非空结点)右孩子入栈、左孩子入栈。

    (入栈为右、左,出栈才能是左、右)

复杂度分析

时间复杂度:O(N)。

空间复杂度:O(N)。

注意点

代码实现

/**
 * 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) {}
 * };
 */
class Solution {
public:
    // 前、后序:遍历和处理是重合的
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        if(root == NULL) return result;
        st.push(root);
        while(!st.empty()){
            TreeNode* node = st.top();st.pop();  // 中
            result.push_back(node->val);
            
            if(node->right) st.push(node->right);   // 右
            if(node->left) st.push(node->left); // 左
        }

        return result;
    }
};

迭代遍历(中序)

思路

  1. 遍历指针cur指向root
  2. 当指针和栈不同时为空时循环:当cur不为空时,入栈当前结点,指针指向左孩子;cur为空时,cur指向栈顶结点,栈顶元素pop,记录当前cur的val,cur指向右孩子。

复杂度分析

时间复杂度:O(N)。

空间复杂度:O(N)。

注意点

代码实现

/**
 * 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) {}
 * };
 */
class Solution {
public:
    // 迭代法中序
    // 1.处理:result加入元素
    // 2.访问:遍历结点
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result; // 结果数组
        stack<TreeNode*> st;    // 结点栈,记录遍历过的结点
        TreeNode* cur = root;	// 遍历指针
        
        while(cur != NULL || !st.empty()){ // 当前指针不为空或栈不空
            if(cur != NULL){    // cur不为空时,入栈当前结点
                st.push(cur);
                cur = cur->left;
            }else{  // 否则出栈元素,记录当前结点,看右孩子
                cur = st.top();st.pop();
                result.push_back(cur->val);
                cur = cur->right;
            }
        }

        return result;
    }
};

统一迭代法

思路

统一处理、访问两件事。在待处理的结点后面放入一个NULL指针作为标记。

  1. 根结点入栈
  2. 如果栈不空,循环:
    1. 如果结点非空,栈顶结点弹出,(判断非空后)依次放入右、中(同时放入NULL作为标记)、左结点。

复杂度分析

时间复杂度:O(N)

空间复杂度:O(N)

注意点

代码实现

/**
 * 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) {}
 * };
 */
class Solution {
public:
    // 统一迭代法(中序)
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        if(root != NULL)
            st.push(root);
        while(!st.empty()){
            TreeNode* node = st.top(); st.pop();
            if(node != NULL){
                // 右中左
                if(node->right) st.push(node->right);
                st.push(node); st.push(NULL);   // 当前结点打标记
                if(node->left) st.push(node->left);
            }else{
                result.push_back(st.top()->val); st.pop();
            }
        }

        return result;
    }
};

标签:结点,right,TreeNode,val,迭代,st,遍历,二叉树,left
From: https://www.cnblogs.com/tazdingo/p/18010319

相关文章

  • 代码随想录算法训练营第十四天| 理论基础 递归遍历 迭代遍历 统一迭代
    理论基础代码随想录(programmercarl.com)二叉树的链接形式定义(防忘)structTreeNode{intval;TreeNode*left;TreeNode*right;TreeNode(intx):val(x),left(NULL),right(NULL){}};额外补充(关于unordered_map和map)unordered_map和map类似,都是存储......
  • 代码随想录算法训练营第十四天 | 94. 二叉树的中序遍历,144.二叉树的前序遍历,145.二叉
    145.二叉树的后序遍历 已解答简单 相关标签相关企业 给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 。 示例1:输入:root=[1,null,2,3]输出:[3,2,1]示例2:输入:root=[]输出:[]示例3:输入:root=[1]输出:[1] 提示:树中节点......
  • 一套模板搞定二叉树算法题--二叉树算法讲解004
    1、二叉树经典习题模拟忘记知识点和技巧时,遇到一个新的二叉树习题,该如何处理思考和写代码解题?1.1、leetcode965题目和题意:题解1成员变量self.ans:题解2递归回传:1.2、leetcode257该题是个经典二叉树题目题目和题意:题解:分析,所有路径,每一个叶子节点都需要到达。到......
  • 图片传输和图片防遍历技术方案
    图片传输和图片防遍历技术方案需求描述:1.如果用一个接口列表,可能报文太长了,实现URL是短期有效且防遍历的2.接口文件流,拆两个接口,一个接口返回文件列表,另一个根据文件ID返回文件流3.如果都是图片,base64通过接口来传输图片也可以。4.发送端和接收端可以对文件做MD5加密,这样可以验证......
  • leedcode 对称二叉树
    迭代法:#Definitionforabinarytreenode.#classTreeNode:#def__init__(self,val=0,left=None,right=None):#self.val=val#self.left=left#self.right=rightclassSolution:defisSymmetric(self,root):......
  • 目录遍历(建立目录树,记录目录属性)仅适用于小样本
    directory.h#pragmaonce#include<windows.h>#include<tchar.h>#include<stdio.h>#include<tchar.h>#include<string>#include<stack>#include<codecvt>#include<vector>#defineFILE_NOT_IN_NODE-1classDirTreeNode{p......
  • 深度优先遍历例题(排列数字)
    给定一个整数n,将数字1~n排成—排,将会有很多种排列方法。现在,请你按照字典序将所有的排列方法输出。输入格式共一行,包含一个整数n。输出格式按字典序输出所有排列方案,每个方案占一行。数据范围1≤n≤7#include<iostream>usingnamespacestd;constintN=10;intn;int......
  • 【数学】以普通高中生的眼光深入牛顿迭代法
    Newton'smethodforfindingroots目录目录前言&前置知识基础应用:手动开方优化:牛顿下山法闲话前言&前置知识前置知识:导数的定义与基本运算如今whk确确实实讲了牛顿法,就是那个切线求导数近似解,效率是二分法的忘了多少倍。(不觉得这很酷吗)那么牛顿迭代到底有没有比课本......
  • leedcode 二叉树的中序遍历
    自己写的classSolution:def__init__(self):self.res_list=list()definorderTraversal(self,root):ifroot:ifroot==None:returnelse:self.inorderTraversal(root.left)......
  • 图的遍历
    /*反向考虑,反向建图,考虑从x号点出发,可以到达哪些点,我们从n~1开始枚举如果某一个点被更新到,呢么这个点一定不会被后面的点更新,就直接可以标记掉,从n号点出发可以到达5号点,呢么从n-1号点出发就可以直接跳过5号点,还有5号点能到达的点。复杂度是O(n),这样的想法很常见*/#include......