算法导论 练习10.4-5二叉树的遍历

本文介绍了一种在O(n)时间内非递归地遍历二叉树的方法,特别关注了如何在不使用额外存储空间的情况下实现这一目标。文章详细解释了三种遍历策略:递归版本、使用栈的非递归版本以及不使用栈的版本,并提供了相应的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

10.4-5 给定一个n结点的二叉树,写出一个 O ( n ) O(n) O(n)时间的非递归过程,将该树的每一个结点的关键字输出。要求除该树本身的存储空间外只能使用固定量的额外存储空间,且中过程中不得修改该树,即使是暂时的修改也不允许。

要完成 O ( 1 ) O(1) O(1)的空间内遍历该树,需要每个结点需要能访问其父节点进行回溯。

struct Tree
{
    Tree *parent;
    Tree *left;
    Tree *right;
    int key;
};

中序遍历:

  1. 访问左孩子
  2. 访问右孩子
  3. 从左孩子返回,访问根节点,进入右孩子访问
  4. 从右孩子返回,整棵树访问完成,回溯到上层,直到当前结点为根节点或该结点是父节点的左孩子

下面是测试代码:

#include<iostream>
#include<stack>
using namespace std;
#define NIL -1
struct Tree
{
	Tree* left;
	Tree* right;
	Tree* parent;
	int key;
	Tree():left(nullptr),right(nullptr),parent(nullptr){}
};
void print(const Tree* t)
{
	cout << t->key << " ";
}
void createTree(Tree *&t)
{
	int key;
	cin >> key;
	if(key==NIL){
		t=nullptr;
		return;
	}
	t=new Tree();
	t->key=key;
	createTree(t->left);
	createTree(t->right);
	//存在子结点,更细父指针
	if(t->left)
		t->left->parent=t;
	if(t->right)
		t->right->parent=t;
}
// 递归版本
void inorder_travel(Tree *h)
{
	if(h)
	{
		inorder_travel(h->left);
		print(h);
		inorder_travel(h->right);
	}
}

// 使用stack非递归版本,结点不需要parent指针
void inorder_byStack(Tree*h)
{
	stack<Tree*> sta;
	Tree *p=h;
	while(p || !sta.empty())
	{
		while(p)
		{
			sta.push(p);
			p=p->left;
		}
		p=sta.top();sta.pop();
		print(p);
		p=p->right;
	}
}
// 没有使用栈的版本,通过h和pre之间的关系进行遍历。
// 回溯需要parent指针。
void inorder_noStack(Tree* h)
{
	if(!h)return;
	//pre作为前驱,判断从左孩子还是右孩子返回
	Tree* pre=nullptr;
	while(true)
	{
		//找到左结点
		if(pre!=h->left)
		{
			while(h->left)
				h=h->left;
		}
		print(h);
		//存在右结点则进入
		if(h->right){
			h=h->right;
			continue;
		}
		//右孩子返回时,回溯直到根结点的父节点或是父节点的左孩子
		do{
			pre=h;
			h=h->parent;
			if(h==nullptr)
				return;
		}while(pre==h->right);
	}
}
int main()
{
	Tree* head;
	createTree(head);
	inorder_travel(head);
	cout << endl;
	inorder_byStack(head);
	cout << endl;
	inorder_noStack(head);
}

测试数据:
1 2 4 7 -1 -1 -1 5 8 -1 -1 -1 3 6 -1 9 -1 -1 -1

树的形状是:
在这里插入图片描述

中序遍历结果:
7 4 2 8 5 1 6 9 3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值