LeetCode 二叉树的前中后序遍历

LeetCode 二叉树的遍历:前中后(链表实现)
一、前序遍历(Preorder Traversal)

zAvJ56.jpg

  • 先根节点 -> 左节点 -> 右节点
    • 思路:每次出栈栈顶元素(一定是某一棵子树的根节点),再将其右孩子和左孩子依次入栈
  • 步骤如下:
    1. 先将root压栈
    2. while循环(退出条件:栈非空stack.empty()==0)
    3. 将栈顶元素出栈pop(stack.top())
    4. 将栈顶元素储存到vector<int>中,vector<int>.push_back()
    5. 依次将出栈元素的右孩子和左孩子节点压栈
      1. p->right != nullptr -> stack.push(p->right)
      2. p->left != nullptr -> stack.push(p->left)

代码如下:

#include<iostream>
#include<vector>
#include<stack>
using namespace std;

// 首先定义二叉树结构体
struct Binary_Tree {
	Binary_Tree* left_child;
	Binary_Tree* right_child;
	int data;
	// 构造函数
	Binary_Tree(int x) :data(x), left_child(nullptr), right_child(nullptr) {};
};

class Binary_Tree_Preorder_Traversal {
	vector<int> Preorder_Traserval(Binary_Tree* root) {
		vector<int> result; // 定义向量接收遍历结果
		stack<const Binary_Tree*> s; // 定义栈进行二叉树的遍历
		if(root != nullptr)s.push(root);
		while (!s.empty()) {
			const Binary_Tree* p = s.top();
			s.pop();
			result.push_back(p->data);
			if (p->right_child != nullptr) s.push(p->right_child);
			if (p->left_child != nullptr) s.push(p->left_child);
		}
		return result;
	}
};
二、中序遍历

zAvtPK.jpg

  • 先左孩子 -> 根节点 -> 右孩子
    • 先沿着左结点一直遍历到底,再不断出栈
    • 如果有右孩子,则在沿着右孩子的左孩子继续遍历
    • 如果没有右孩子,则继续出栈
  • 步骤如下:
  1. 首先从root结点开始一路遍历左孩子left_child,条件判断if p != nullptr
    1. 并将途经的所有结点压栈:s.push(p);p = p -> left;
    2. 遍历到不能遍历了,跳出条件判断
  2. else开始出栈,并且开始对每个结点的右孩子right_child进行考察
    1. 出栈并且将数据存储到vector中:p = s.top(); s.pop(); result.push_back(p->val);
    2. 进一步考察结点的右孩子p = p -> right

代码如下:

#include<iostream>
#include<vector>
#include<stack>
using namespace std;

struct TreeNode {
	TreeNode* left; // 左孩子
	TreeNode* right; // 右孩子
	int val; // 数据
	TreeNode(int x) :val(x), left(nullptr), right(nullptr) {};
};

class Binary_Tree_Inorder_Traversal {
	vector<int> Inorder_Traversal(TreeNode* root) {
		vector<int> result;
		stack<const TreeNode*> s;
		const TreeNode* p = root; // 一开始不能直接将root结点push到栈中,否则就push了两次,结果有问题
		while (!s.empty() || p != nullptr) {
			if (p != nullptr) {
				s.push(p); // 将一路向左途经的每一个结点都压栈
				p = p->left; // 继续向左遍历
			}
			else { // 向左遍历到头了,开始出栈+向右遍历
				p = s.top();
				s.pop();
				result.push_back(p->val);
				p = p->right; // 准备向右遍历,向右遍历之后再向左一路遍历
			}
		}
		return result;
	}
};
三、后序遍历

zAvN8O.jpg

  • 先左节点 -> 右节点 -> 根节点
    • 思路:每次在出栈栈顶之前都需要判断此元素的右孩子是否呗访问&存在
    • 关键点:将nullptr也看成一个结点(空结点)
  • 步骤如下:
  1. 首先,用两个指针分别记录此刻和上一刻访问的结点const TreeNode* p = root,q = nullptr;
    1. 注意:在进行前向遍历的时候,是不需要用到q指针的
    2. 在反向出栈的时候,才需要记录上一时刻出栈的结点q = last_push
  2. root结点开始,一直向左遍历结点到底,判断条件if(p != nullptr)
  3. 需要将q赋值为空指针
  4. 进入while(!=s.empty())循环开始出栈,先不进行判断将p = s.top(); s.pop();
    1. 在判断出栈是否合理(即右节点是否存在且没有被访问过):
    2. if(p->right == q)说明右结点不存在(为nullptr)或者右结点已经被访问,此时出栈合理,可以保存p->val,即result.push_back(p->val); q = p;
    3. elsep->right != q说明右结点存在且未被访问(即使是nullptr也认为存在),此时出栈不合理,应该重新将p入栈,再分析其右孩子,s.push(p); p = p->right; break;

代码如下:

#include<iostream>
#include<vector>
#include<stack>
using namespace std;

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

class Binary_Tree_PostOrder_Traserval {
	vector<int> PostOrder_Traserval(TreeNode* root) {
		vector<int> result;
		stack<const TreeNode*> s;
		const TreeNode* p = root;
		const TreeNode* q = nullptr;
		do {
			while (p != nullptr) { // 当p还指向结点的时候,一直向下探索
				s.push(p);
				p = p->left;
			}
			q = nullptr;
			while (!s.empty()) {
				p = s.top();
				s.pop();
				// 若q指向与p->right指向相同,说明右结点已经完成访问,此时根节点可以直接出栈
				if (p->right == q) {
					result.push_back(p->val);
					q = p;
				} // 若q的指向与p->right的指向不同,说明右节点还没有完成访问,不能直接将根节点出栈
				else {
					s.push(p);
					p = p->right;
					break;
				}
			}
		} while (!s.empty());
		return result;
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值