首页 > 其他分享 >大一计算机的自学总结:二叉树三种序的非递归遍历

大一计算机的自学总结:二叉树三种序的非递归遍历

时间:2025-01-17 21:29:29浏览次数:3  
标签:head 遍历 二叉树 大一 push NULL 节点

前言

二叉树的递归遍历在我上一篇“二叉树及其三种序的递归遍历”里有。其中用到的“BinaryTree”也在链接文章的“二叉树的创建”里。大一计算机的自学总结:二叉树及其三种序的递归遍历

而非递归遍历是借助栈的特性,会更难更复杂。TvT......

一、先序遍历

#include<bits/stdc++.h>
#include"BinaryTree.h"
using namespace std;

//非递归先序遍历二叉树
void preOrder(TreeNode* head)
{
	if(head!=NULL)
	{
		stack<TreeNode*>s;
		s.push(head);
		while(!s.empty())
		{
			head=s.top();
			cout<<head->value<<" ";
			s.pop();
			if(head->right!=NULL)
			{
				s.push(head->right);
			}
			if(head->left!=NULL)
			{
				s.push(head->left);
			}
		}
	}
} 

int main()
{
	TreeNode* head=NULL;
	
	addTree(head);
	
	//非递归先序遍历二叉树
	cout<<"preorder:"<<endl;
	preOrder(head);
	
	return 0;
}

 因为先序遍历的顺序是“中、左、右”,根据栈的特性,先入右孩子再入左孩子就行。

先将头节点入栈,然后只要栈不为空,就让head指针指向栈顶元素,然后输出栈顶节点的数值,

之后出栈顶。此时输出的即为“中”节点,之后只要按照先入右孩子再入左孩子的顺序入栈即可。

二、中序遍历

#include<bits/stdc++.h>
#include"BinaryTree.h"
using namespace std;

//非递归中序遍历二叉树
void inOrder(TreeNode* head)
{
	if(head!=NULL)
	{
		stack<TreeNode*>s;
		while(!s.empty()||head!=NULL)
		{
			if(head!=NULL)
			{
				s.push(head);
				head=head->left;	
			}
			else
			{
				head=s.top();
				cout<<head->value<<" ";
				s.pop();
				head=head->right; 
			}
		}	
	}	
} 

int main()
{
	TreeNode* head;
	
	addTree(head);
	
	//非递归中序遍历二叉树
	cout<<"inorder:"<<endl;
	inOrder(head); 
	
	return 0;
}

 根据中序“左、中、右”的顺序,思路是先一直入左孩子直到进完,然后弹出一个,之后去到弹出节点的右孩子并重复上述过程直到没有子树且栈为空

当不满足没有子树且栈为空时,若有子树,则将节点入栈并移向左孩子;若没有子树了,则输出栈顶节点的数,然后出栈顶并移向右孩子。

三、后序遍历

1.两个栈实现

#include<bits/stdc++.h>
#include"BinaryTree.h"
using namespace std;

//非递归后序遍历二叉树——两个栈实现
void postOrderTwoStacks(TreeNode* head)
{
	if(head!=NULL)
	{
		stack<TreeNode*>data;
		stack<TreeNode*>s;
		data.push(head);
		while(!data.empty())
		{
			head=data.top();
			s.push(head);//反转
			data.pop();
			if(head->left!=NULL)
			{
				data.push(head->left);	
			} 
			if(head->right!=NULL)
			{
				data.push(head->right);
			}
		}
		while(!s.empty())
		{
			head=s.top();
			cout<<head->value<<" ";
			s.pop();
		}
	}
} 

int main()
{
	TreeNode* head=NULL;
	
	addTree(head);
	
	//非递归后序遍历二叉树
	cout<<"postorder:"<<endl;
	postOrderTwoStacks(head); 
	
	return 0;
}

 第一个思路,观察先序遍历“中、左、右”和后序遍历“左、右、中”的顺序,可以发现,若将先序遍历代码中先入右孩子再入左孩子的顺序调换,再将整个顺序反转就能得到“左、右、中”的顺序。

于是准备两个栈,一个先存放数据,另一个负责反转后输出。

先往data栈中压入节点,当栈不为空时,先向反转栈中压入栈顶元素再弹出,然后调换先序遍历的代码,先入左孩子再入右孩子。

当data栈的数据全部倒完后,只需按顺序输出s栈的栈顶元素即可。

2.一个栈实现

#include<bits/stdc++.h>
#include"BinaryTree.h"
using namespace std;

//非递归后序遍历二叉树——一个栈实现
void postOrderOneStack(TreeNode* head)
{
	if(head!=NULL)
	{
		stack<TreeNode*>s;
		s.push(head);
		while(!s.empty())
		{
			TreeNode* p=s.top();
			
			//有左树且左树没处理过 
			if(p->left!=NULL&&head!=p->left&&head!=p->right)
			{
				s.push(p->left); 
			}
			
			//有右树且右树没处理过
			else if(p->right!=NULL&&head!=p->right)
			{
				s.push(p->right);
			} 
			
			//都没有或都处理过了 
			else
			{
				cout<<p->value<<" ";
				head=s.top();
				s.pop();
			}
		}
	}
} 

int main()
{
	TreeNode* head;
	
	addTree(head);
	
	//非递归后序遍历二叉树
	cout<<"postorder:"<<endl;
	postOrderOneStack(head); 
	
	return 0;
}

 为了用一个栈实现,可以将head的更新条件改为更新成上一个输出过的节点

压入节点后,当栈不为空时,设置指针p来指向当前节点,之后,若有左树且左树没处理过,则压入当前节点的左孩子;否则若有右树且右树没处理过,则压入当前节点的右孩子;否则,即没有子树或都处理过了,就输出当前节点的数,并将head指针更新成此时节点,表示已经处理过了。

只看代码的话会比较抽象很难理解,只有模拟一遍全过程才能理解这个思路的巧妙。

总结

二叉树三种序的非递归遍历也很重要,特别是后序遍历中两个栈优化成一个栈,重设head更新条件的思路。

END

标签:head,遍历,二叉树,大一,push,NULL,节点
From: https://blog.csdn.net/2402_89326161/article/details/145194305

相关文章

  • 【vjudge训练记录】大一寒假专项训练——字符串
    训练情况A题第十届中国大学生程序设计竞赛(济南)-(CCPC2024-Jinan)签到题我们取第一行第一个和后面的进行比较,如果不同的次数超过1次,就说明第一行第一个是不同的那个,如果不同的次数刚好为1次,比较的那个字符串是不同的那个。#include<bits/stdc++.h>#defineintlonglong#defi......
  • 【二叉树】已知前序中序、中序后序遍历构造二叉树
    105.从前序与中序遍历序列构造二叉树-力扣(LeetCode)/***Definitionforabinarytreenode.*structTreeNode{*intval;*TreeNode*left;*TreeNode*right;*TreeNode():val(0),left(nullptr),right(nullptr){}*TreeNode(intx......
  • 【嵌入式人生】1.2025应届生四处碰壁的思考:若回到大一,我将这么干
    803.001 若笔者回到大一,将会按照如下方式过,根据一路以来找工作最后成功上岸的经验简单的总结为以下几点(以就业为标准,以走嵌入式道路为标准),想到还会继续更新  1.门门都要学好,争做好学生?大学学习的知识不足以让你达到社会上的就业标准,若不选择保研,与其花100%的精力让自......
  • 如何遍历整个列表
    想对大家说的话:大家好呀,我是耶耶在这里,我会将Python代码像拆解精密玩具一样,一步步剖析,确保每一步的来龙去脉都清晰可见。我会详细解释为什么选择特定的关键字和结构,通过对比不同类型的代码片段,让你不仅知其然,更知其所以然!!!拜托大家给我点一个关注!让我们一起进步吧!!!上期本期......
  • 【vjudge训练记录】大一寒假专项训练——栈
    训练记录今天洛谷崩了,先不统计了A题栈的模板题,pop出栈并输出栈顶,top输出栈顶,记得输出前判断一下栈内非空#include<bits/stdc++.h>//#defineintlonglong#defineendl'\n'usingnamespacestd;stack<int>q;voidsolve(){strings;cin>>s;if(s=="pus......
  • 数据结构—《二叉树的定义与特性》
    目录1.二叉树的定义2.特殊的二叉树1)满二叉树2)完全二叉树3)二叉排序树。4)平衡二又树。5)正则二文树3.二叉树的性质4.二叉树的存储结构1)顺序存储结构2)链式存储结构1.二叉树的定义二叉树是一种特殊的树形结构,其特点是每个结点至多只有两棵子树(即二叉树中不存在度大......
  • 数据结构之链式二叉树
    前言:前面我们学习了树相关的概念及堆的实现,今天来看看二叉树的实现。正式实现二叉树前,我们先了解一些基础知识。对于二叉树基础知识不清楚的可以观看数据结构------树这篇文章,回顾一下知识,有助于理解二叉树。二叉树的遍历方式都有哪些呢?.前序遍历:按照根节点,左节点,右节......
  • Java学习,集合遍历
    Java遍历集合(如List, Set, Map等)通常有多种方法。遍历集合的方式,包括传统for循环、增强的for循环(也称"for-each"循环)、迭代器(Iterator)以及流(Stream)API。示例:for循环遍历List:List<String>list=Arrays.asList("Apple","Banana","Cherry");for(inti=0;i<......
  • 代码随想录:最大二叉树
    白送/***Definitionforabinarytreenode.*structTreeNode{*intval;*TreeNode*left;*TreeNode*right;*TreeNode():val(0),left(nullptr),right(nullptr){}*TreeNode(intx):val(x),left(nullptr),right(nullptr){}......
  • 代码随想录:从中序与后序遍历序列构造二叉树
    /**Definitionforabinarytreenode.structTreeNode{intval;TreeNode*left;TreeNode*right;TreeNode():val(0),left(nullptr),right(nullptr){}TreeNode(intx):val(x),left(nullptr),right(nullptr){}TreeNode(intx,TreeNo......