C++详解 二叉树的三种遍历方式

上一篇文章,讲了二叉树的创建——C++实现 链表存储二叉树
接下来讲解二叉树的三种遍历方式:先序(前序)遍历、中序遍历、后序遍历,三种方式都是DFS(Depth First Search)深度优先搜索,核心思想都是函数的递归(栈),如果你能理解上面这篇文章中创建二叉树的具体过程,那么遍历就轻而易举

1.先序遍历

void Former_Order_Traversel(BinTree_Node* p)
{
    if(p)
    {
        cout<<p->data;
        Former_Order_Traversal(p->left);
        Former_Order_Traversal(p->right);
    }
}

下面分析具体过程,以上一篇文章创建的二叉树为例,圆圈中的数字为data。从上到下,从左到右给结点编号,遍历顺序为ABDECFG,根-左-右
在这里插入图片描述
整个递归过程其实是靠函数栈来实现的,先访问再入栈

  • 1.把根结点指针传进来,判断结点不为空,访问根结点数据,然后将根结点A入栈

  • 2.把根结点的left指针(B结点)传进来,判断结点不为空,访问B结点数据,将B结点入栈

  • 3.把B结点的left指针(D结点)传进来,判断结点不为空,访问D结点数据,D结点入栈
    在这里插入图片描述

  • 4.把D结点的left指针传进来,指针为空,从栈顶抛出一个元素D,处理右子树

  • 在这里插入图片描述

  • 5.把D的right指针传进来,指针为空,从栈顶抛出一个元素B,处理右子树
    在这里插入图片描述

  • 6.把B的right指针(E结点)传进来,判断不为空,访问E结点数据,E结点入栈
    在这里插入图片描述

  • 7.把E结点的left指针传进来,指针为空,从栈顶抛出一个元素E,处理右子树

  • 8.把E结点的right指针传进来,指针为空,从栈顶抛出一个元素A,然后同理

搞清楚函数栈的实现过程后,我们可以利用stl中的stack模拟出栈和入栈

void Former_Order_Stack(Bintree_Node* p)
{
    if(!p) return;//如果是空树,就直接返回
	Bintree_Node* temp = p;
	stack<Bintree_Node*>s;//创建一个数据栈
	while (temp != NULL || !s.empty())//当temp为空指针且栈空时,遍历就结束了
	{
		while (temp != NULL)//判断结点是否为空
		{
			cout << temp->data << endl;//访问数据
			s.push(temp);//该结点入栈
			temp = temp->left;//将指针指向左子树
		}
		temp = s.top();//抛出前,获得栈顶元素的引用,也就是出栈结点的引用
		s.pop();
		temp = temp->right;//将指针指向出栈结点的右子树,准备处理
	}
}

2.中序遍历

void Middle_Order_Stack(Bintree_Node* p)
{
	if(p)
	{
    	Middle_Order_Traversal(p->left);
    	cout<<p->data;
    	Middle_Order_Traversal(p->right);
    }
}

在这里插入图片描述
遍历顺序为DBEAFCG,左-根-右,具体过程如下

  • 1.根结点指针传进来,判断不为空,根结点A入栈
  • 2.把根结点的left指针(B结点)传进来,判断不为空,B结点入栈
  • 3.把B结点的left指针(D结点)传进来,判断不为空,D结点入栈
    在这里插入图片描述
  • 4.把D结点的left指针传进来,判断为空,抛出栈顶元素D,输出D结点数据
    在这里插入图片描述
  • 5.把指针指向D结点的right指针,判断为空
  • 6.抛出栈顶元素B,输出B结点数据
    在这里插入图片描述
  • 7.把指针指向B结点right指针(E结点),判断不为空,E结点入栈
    在这里插入图片描述
  • 8.把指针指向E结点的left指针,判断为空,抛出栈顶E结点,输出结点E数据
  • 9.把指针指向E结点的right指针,判断为空,抛出栈顶A结点,输出A结点数据
    …右子树同理

弄清楚上述过程后,用stack模拟

void Middle_Order_Stack(Bintree_Node* p)
{
    if(!p) return;//如果是空树,就直接返回
	Bintree_Node* temp = p;
	stack<Bintree_Node*>s;
	while (temp != NULL || !s.empty())
	{
		while (temp != NULL)
		{
			s.push(temp);
			temp = temp->left;
		}
		temp = s.top();
		cout << temp->data << endl;
		s.pop();
		temp = temp->right;
	}
}

3.后序遍历

void Last_Order_Traversal(Bintree_Node* p)
{
	if (p)
	{
		Last_Order_Traversal(p->left);
		Last_Order_Traversal(p->right);
		cout << p->data << endl;
	}
}

在这里插入图片描述
遍历顺序为:DEBFGCA ,左-右-根,因为要记录当前结点的遍历情况,后序遍历会稍微复杂

stack模拟如下

void postorderTraversalNew(Bintree_Node *root)
{
	stack<pair<Bintree_Node*,bool>> s;
	s.push(make_pair(root,false));
	while (!s.empty())
	{
		Bintree_Node* root = s.top().first;
		bool flag = s.top().second;
		s.pop();//先出队
		if (root == NULL)
			continue;
		if (flag == true)//遍历过的就直接输出
			cout << root->data << endl;
		else//如果没遍历过的点,要再次入队
		{
			s.push(make_pair(root, true));//第二次入队,改为true
			s.push(make_pair(root->right, false));
			s.push(make_pair(root->left, false));
		}
	}
}
  • 8
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值