代码随想录算法训练营第11天|二叉树理论基础、二叉树的递归遍历、二叉树的迭代遍历、二叉树的层序遍历

二叉树理论基础

代码随想录视频内容简记

二叉树的种类

  1. 满二叉树

  2. 完全二叉树

  3. 二叉搜索树

  4. 平衡二叉搜索树

二叉树的存储方式

  1. 链式存储

  2. 线性存储

关于如何用代码“画”一个二叉树,其实就是用链表定义好左孩子和右孩子,之后返回这个链表的根节点即可

二叉树的遍历方式

和图论中的搜素方式一致,都大致可以分为两类

  1. 深度优先搜索

    1. 前序

    2. 中序

    3. 后序

  2. 广度优先搜索

    二叉树中就是层序遍历

而在二叉树的前中后序遍历中,每一种便利的代码实现都可以使用递归法迭代法两种来实现

二叉树的定义

二叉树的定义一定会要手写,应为在力扣中核心代码模式平常直接是定义好的,时间长不用就忘了

大致代码内容

关于二叉树代码的定义

struct TreeNode {
	int val;
	TreeNode* left;
	TreeNode* right;
	TreeNode(int x): val(x), left(NULL), right(NULL) {}
};

注意其写法

二叉树的递归遍历

二叉树的递归遍历方式,k哥称递归三部曲

  1. 递归函数的参数和初始条件

  2. 递归的终止条件

  3. 确定单层递归的逻辑

关于前序遍历的写法


void traversal(cur, vector) {
	if (cur == NULL) return;
	// 根节点
	push (cur, vector);
	// 左子树
	traversal(left);
	// 右子树
	traversal(right);
}

中序遍历就是


void traversal(cur, vector) {
	if (cur == NULL) return;
	// 左子树
	traversal(left);
	// 根节点
	push (cur, vector);
	// 右子树
	traversal(right);
}

后序遍历就是


void traversal(cur, vector) {
	if (cur == NULL) return;
	// 左子树
	traversal(left);
	// 右子树
	traversal(right);
	// 根节点
	push (cur, vector);
}

LeetCode144

2025-02-02 20:40:04 星期日

题目描述:力扣144
文档讲解:代码随想录(programmercarl)144. 二叉树的前序遍历

大致代码内容

在书写的时候注意要void traversal(TreeNode* root, vector<int>& vec)这行的&表示的是引用传递


void traversal(TreeNode* root, vector<int> vec) {
	if (!root) return;
	vec.push_back(root->val);
	traversal(root->left, vec);  // 复制 vec
	traversal(root->right, vec); // 复制 vec
}

表示没有引用传递,vec在函数内部被修改,但是外部的vec不会受到影响


void traversal(TreeNode* root, vector<int>& vec) {
	if (!root) return;
	vec.push_back(root->val);
	traversal(root->left, vec);  // 修改原始 vec
	traversal(root->right, vec); // 修改原始 vec
}

表示这里的vec是通过引用传递的,递归调用时修改的是同一个vec

LeetCode测试

点击查看代码
/**
 * 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 traversal(TreeNode* root, vector<int>& vec) {
        if (root == NULL) return;
        vec.push_back(root->val);
        traversal(root->left, vec);
        traversal(root->right, vec);
    }

    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        traversal(root, result);
        return result;
    }
};

LeetCode145

题目描述:力扣145
文档讲解:代码随想录(programmercarl)145.二叉树的后序遍历

LeetCode测试

代码很简单

点击查看代码
/**
 * 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 traversal(TreeNode* cur, vector<int>& vec) {
        if (cur == NULL) return;
        traversal(cur->left, vec);
        traversal(cur->right, vec);
        vec.push_back(cur->val);
    }
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> vec;
        traversal(root, vec);
        return vec;
    }
};

LeetCode94

题目描述:力扣94
文档讲解:代码随想录(programmercarl)94.二叉树的中序遍历

LeetCode测试

点击查看代码
/**
 * 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 traversal(TreeNode* cur, vector<int>& vec) {
        if (cur == NULL) return;
        traversal(cur->left, vec);
        vec.push_back(cur->val);
        traversal(cur->right, vec);
    }

    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        traversal(root, result);
        return result;
    }
};

二叉树的迭代遍历

视频讲解:写出二叉树的非递归遍历很难么?这次让你不再害怕非递归!|二叉树的非递归遍历 | 二叉树的遍历迭代法 | 前序与中序

前序遍历

二叉树的迭代遍历中,遍历处理结点是两个不同的概念。

其次,在二叉树的迭代法书写中,要用到这种数据结构

梳理

  1. 首先要传入一棵二叉树,只需要传入他的根节点就可以了

  2. 首先将根节点存入栈中

  3. 不断循环遍历,将栈顶元素弹出放入数组

  4. 之后先存入右子树,再存入左子树,将树按照先右后左的顺序放入栈中,弹出的时候才能是先左后右

大致代码内容

  1. 首先定义一个栈和一个数组,stack<TreeNode*> stvector<int> vec栈用于存放二叉树的结点,数组用于存放前序或者后序的结果(注意不能是中序,因为中序的遍历和处理顺序不一致)

  2. 进入遍历,定义获取的node结点为栈顶部结点,TreeNode* node = st.top()while (st!= NULL),之后判断存放的结点是不是空结点,若不是,则存放到数组if (node != NULL) vec.push_back(node->val) else continue;若是,则continue

  3. 对前序遍历,先存放右子树,st.push(node->right),后左子树,st.push(node->left)

后序遍历

梳理

后序遍历的顺序是LRN

在前序的迭代法中,处理的顺序是按照NLR,在基础之上,只需要反转右子树和左子树的压入顺序,先变成NRL,之后再反转最后的处理数组变成LRN即可

中序遍历

梳理

  1. 定义指针来遍历这棵树

  2. 定义一个栈来对树中元素进行记录

  3. 如果指针不为空,则首先遍历他的左子树,并将遍历到的所有元素入栈

  4. 如果指针为空,则弹出栈顶元素的同时,需要遍历右子树

大致代码内容

  1. while (cur != NULL || !stack.empty())首先进入循环。注意这里的连接符号是||,只要一个条件成立,循环继续,只有cur为空且stack为空才会终止

  2. if (cur != NULL)cur = cur->left

  3. cur = stack.top(),首先给当前指针赋值栈顶元素,表示指针的回退,stack.pop(),之后这个栈顶元素弹出,并加入数组,vec.push_back(cur->val),最后再进行cur = cur->right

LeetCode测试

前序遍历

注意每次获取完了栈顶部的结点之后要进行弹出

点击查看代码
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> vec;
        stack<TreeNode*> st;
        st.push(root);
        while (!st.empty()) {
            // 获取顶部元素
            TreeNode* node = st.top();
            // 弹出
            st.pop();
            // 若结点有值,则压入数组
            if (node != NULL) vec.push_back(node->val);
            else continue;
            // 遍历右子树和左子树
            st.push(node->right);
            st.push(node->left);
        }
        return vec;
    }
};

后序遍历

点击查看代码
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> vec;
        stack<TreeNode*> st;
        st.push(root);
        while(!st.empty()) {
            TreeNode* node = st.top();
            st.pop();
            if (node != NULL) vec.push_back(node->val);
            else continue;
            st.push(node->left);
            st.push(node->right);
        }
        reverse(vec.begin(), vec.end());
        return vec;
    }
};

中序遍历

点击查看代码
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> vec;
        TreeNode* cur = root;
        while (cur != NULL || !st.empty()) {
            if (cur != NULL) {
                st.push(cur);
                cur = cur->left;
            } else {
                cur = st.top();
                st.pop();
                vec.push_back(cur->val);
                cur = cur->right;
            }
        }
        return vec;
    }
};

二叉树的层序遍历

LeetCode102

题目描述:力扣102
文档讲解:代码随想录(programmercarl)102.二叉树的层序遍历
视频讲解:《代码随想录》算法视频公开课:讲透二叉树的层序遍历 | 广度优先搜索 | LeetCode:102.二叉树的层序遍历

代码随想录视频内容简记

实现层序遍历的关键一是要用到队列,而是需要用到一个size对每一层的元素数量进行控制

大致代码内容

  1. 定义一个队列que,一个vec数组。之后把根节点入队,之后进入循环

  2. 要在循环Ⅰ开始时获取队列的长度size

  3. 再来一个循环Ⅱ,对while(size--),获取队头元素,之后弹出,分别遍历到左子树和右子树的下一层

  4. 循环Ⅱ结束,将vec数组添加到一个二维result数组中

LeetCode测试

这个有一些细节需要注意

在循环每次添加的vec数组,需要定义到循环内部,这样每次添加的元素才会不重复

错误代码


vector<int> vec;
while (!que.empty()) {
	while (size--) {
		...
	}
}

会出现下面的这种

正确的应该是

while (!que.empty()) {
	vector<int> vec;
	while (size--) {
		...
	}
}
点击查看代码
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> que;
        vector<vector<int>> result;
        if(root != NULL) que.push(root);
        while (!que.empty()) {
            int size = que.size();
            // 在循环中每次都定义一个新的vec来进行添加
            vector<int> vec;
            while (size--) {
                TreeNode* cur = que.front();
                // 操作数组
                vec.push_back(cur->val);
                // 队列弹出
                que.pop();
                if (cur->left != NULL) que.push(cur->left);
                if (cur->right != NULL) que.push(cur->right);
            }
            result.push_back(vec);
        }
        return result;
    }
};
posted on   bnbncch  阅读(1567)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示