C++实现二叉树非递归遍历

1、先序遍历​(根 -> 左 -> 右)

Step1: 初始化栈:将根节点压入栈中。

Step2: 循环处理栈​(直到栈为空)

  • 弹出栈顶节点并访问(如打印值)。
  • 先压右孩子​(如果存在):将当前节点的右孩子压入栈。
  • 再压左孩子​(如果存在):将当前节点的左孩子压入栈。

原理:先压右孩子,再压左孩子,保证弹出时先处理左孩子,符合先序遍历的顺序。

void preOrder(TreeNode* root)
{
	if (root == nullptr) return;
	stack<TreeNode*> stk;
	stk.push(root);
	while (!stk.empty())
	{
		TreeNode* cur = stk.top();
		cout << cur->val << " ";
		stk.pop();
		if (cur->right) stk.push(cur->right);
		if (cur->left) stk.push(cur->left);
	}
}

2、后序遍历​(左 -> 右 -> 根)

方法一:使用两个辅助栈

Step1: 初始化双栈

  • 主栈​(stk):处理节点遍历顺序,初始压入根节点。
  • 打印栈​(printStk):暂存最终要输出的节点。

Step2: ​循环处理主栈

  • 弹出主栈顶节点,并压入打印栈(此时打印栈顺序为:根→右→左)。
  • 先压左孩子​(如果存在):左孩子先压入主栈,后续会被后处理。
  • 再压右孩子​(如果存在):右孩子后压入主栈,成为下一次循环的栈顶。
  • 循环终止条件:主栈为空,所有节点已处理完毕。

Step3: ​逆序输出打印栈

  • 依次弹出打印栈中的节点并访问,得到 ​左→右→根 的后序结果。

原理:主栈负责生成根右左的逆序,打印栈负责最终顺序翻转。

void postOrder1(TreeNode* root)
{
	if (root == nullptr) return;
	stack<TreeNode*> stk;
	stack<TreeNode*> printStk;
	stk.push(root);
	while (!stk.empty())
	{
		TreeNode* cur = stk.top();
		printStk.push(cur);
		stk.pop();
		if (cur->left) stk.push(cur->left);
		if (cur->right) stk.push(cur->right);
	}
	while (!printStk.empty())
	{
		cout << printStk.top()->val << " ";
		printStk.pop();
	}
}
方法二:使用一个辅助栈

​Step1: 初始化栈和指针

  • 栈中压入根节点。
  • cur:指向当前处理的节点(初始为根节点)。
  • pre:记录上一个已访问的节点(初始为根节点,仅用于逻辑判断)。

Step2: ​循环处理栈顶节点

  • 循环条件:栈不为空。
  • 步骤分解
    a. ​左子树未处理:若当前节点的左子存在且未被访问(cur->left != pre),且右子也未被访问(cur->right != pre),则压入左子。
    b. ​右子树未处理:若左子树已处理,但右子存在且未被访问(cur->right != pre),则压入右子。
    c. ​访问根节点:若左右子树均已处理(或不存在),则弹出栈顶节点并访问,更新pre为当前节点。
原理:
  • pre指针的作用:标记最近访问的节点,避免重复处理子树。
    • pre == cur.left时,说明左子树已处理完。
    • pre == cur.right时,说明右子树已处理完。
void postOrder2(TreeNode* root)
{
	if (root == nullptr) return;
	stack<TreeNode*> stk;
	stk.push(root);
	TreeNode* pre = root; // 记录上一个打印的节点,最开始还没有打印时就放在root的位置,不干扰将左边界全部入栈的过程
	TreeNode* cur = root; // 处理的当前节点
	while (!stk.empty())
	{
		cur = stk.top();
		if (cur->left != nullptr && cur->left != pre && cur->right != pre) // 如果左子树还没有处理完,就处理左子树。(什么时候处理完)
		{
			stk.push(cur->left);
		}
		else if (cur->right != nullptr && cur->right != pre) // 如果右子树还没有处理完,就处理右子树
		{
			stk.push(cur->right);
		}
		else
		{

			cout << stk.top()->val << " ";
			pre = stk.top(); // 记录上次打印的节点
			stk.pop();
		}
	}
}

3、中序遍历​(左 -> 根 -> 右)

​Step1: 初始化栈和当前节点:当前节点 为根节点 root,准备一个空栈 stk

​Step2: 循环处理节点​(直到 root为空且栈为空)

  • 左子树处理到底
    • 若 root不为空,将 root压入栈,并更新 root为左子节点,直到左子节点为空。
  • 回溯访问根节点
    • 当 root为空时,弹出栈顶节点(即当前子树的根节点),访问该节点。
  • 转向右子树
    • 将 root更新为弹出节点的右子节点,继续处理右子树的左边界。
void inOrder(TreeNode* root)
{
	if (root == nullptr) return;
	stack<TreeNode*> stk;
	while (root != nullptr || !stk.empty())
	{
		if (root)
		{
			stk.push(root);
			root = root->left;
		}
		else
		{
			root = stk.top();
			stk.pop();
			cout << root->val << " ";
			root = root->right;
		}
	}
}

4、测试代码

以如下的二叉树为例,测试上面的函数:

int main()
{
	TreeNode* node1 = new TreeNode(1);
	TreeNode* node2 = new TreeNode(2);
	TreeNode* node3 = new TreeNode(3);
	TreeNode* root = new TreeNode(4);
	TreeNode* node5 = new TreeNode(5);
	TreeNode* node6 = new TreeNode(6);
	TreeNode* node7 = new TreeNode(7);

	root->left = node2;
	root->right = node6;
	node2->left = node1;
	node2->right = node3;
	node6->left = node5;
	node6->right = node7;

	preOrder(root);
	cout << endl;
	postOrder1(root);
	cout << endl;
	postOrder2(root);
	cout << endl;
	inOrder(root);
	
}

运行结果:

4 2 1 3 6 5 7
1 3 2 5 7 6 4
1 3 2 5 7 6 4
1 2 3 4 5 6 7
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是不是应该好好学习呢?

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值