二叉树的非递归遍历算法

二叉树的非递归及层次遍历

1.前序遍历

遍历顺序:根节点→左孩子→右孩子

具体算法思想:将二叉树的根结点赋值给遍历的指针,由该指针进行遍历;若当前节点非空,则访问该节点并将该节点压栈(将该节点的地址压栈),继而遍历其左子树;循环执行,直到当前节点为空时,取栈顶元素并访问其右子树,再重复如上操作,直至遍历节点的指针为空且栈也为空;

具体遍历过程如图:
在这里插入图片描述
算法代码实现如下:

void preorder(BiTree T){
//二叉树的非递归前序遍历 
	stack<BiTree> s;
	while(T||!s.empty()){
	//当前结点或栈不为空时执行该循环 
		if(T!=NULL){//当前结点不为空时 
			cout<<T->data;//访问当前结点信息 
			s.push(T);//将该节点的地址压栈 
			T=T->lchild;//遍历左孩子 
		}
		else{//当前结点为空时 
			T=s.top();//取栈顶的元素 
			s.pop();//弹栈 
			T=T->rchild;//遍历右孩子 
		}
	}
}

2.中序遍历

遍历顺序:左孩子→根节点→右孩子

具体算法思想:将二叉树的根结点赋值给遍历的指针,由该指针进行遍历;若当前节点非空,则将该节点压栈并访问其左子树,循环执行,直至当前节点为空时,取栈顶元素访问并弹栈,然后访问其右子树,再重复如上操作,直至遍历节点的指针为空在且栈也为空。(中序遍历和前序遍历的不同在于:前序遍历是入栈的同时访问结点,而中序遍历是出栈的同时访问结点);

具体遍历过程如图:
在这里插入图片描述
算法代码实现如下:

void inorder(BiTree T){
//二叉树的非递归中序遍历 
	stack<BiTree> s;
	while(T||!s.empty()){
	//当前结点或栈不为空时执行该循环 
		if(T!=NULL){//当前结点不为空时
			s.push(T);//将该节点的地址压栈
			T=T->lchild;//遍历左孩子
		}
		else
		{
			T=s.top();//取栈顶的元素
			s.pop();//弹栈
			cout<<T->data;//访问当前结点信息
			T=T->rchild;//遍历右孩子			
		}
	}
}

3.后序遍历

遍历顺序:左孩子→右孩子→根节点

具体算法思想:将二叉树的根结点赋值给遍历的指针,由该指针进行遍历;若当前节点非空,则将该节点压栈并访问其左子树,循环执行,直至当前节点为空时,取栈顶元素,判断其右子树是否为空且是否已遍历,如果非空且为遍历则访问其右子树,再将其压栈遍历其左子树;如果右子树为空或已遍历则访问该结点并弹栈,同时设置标记指针记录遍历过的点(用于判断右子树是否已遍历),再将遍历指针置空(下次遍历直接取栈顶元素),直至遍历节点的指针为空且栈也为空。

算法代码实现如下:

void postorder(BiTree T){
//二叉树的非递归后序遍历 
	BiTree r=NULL;
	stack<BiTree> s;
	while(T||!s.empty()){
		if(T!=NULL){//当结点不为空时,该结点压栈并遍历其左子树 
			s.push(T);
			T=T->lchild;
		}
		else{//当左子树结点为空时,取栈顶元素进行右子树的遍历, 
			T=s.top();
			if(T->rchild!=NULL&&T->rchild!=r){
			//右子树不为空且右子树没有被遍历过 
				T=T->rchild;
				s.push(T);//将该结点压栈,遍历其左子树 
				T=T->lchild;
			}
			else{//右子树为空或已遍历则取栈顶元素访问该结点的信息 
				s.pop();
				cout<<T->data;
				r=T;//标记遍历过的点,用于判断右子树是否已遍历 
				T=NULL;//遍历结点的指针置空,下次遍历直接取栈中的值 
			}
		}
	}
}

4.层次遍历

具体算法思想:将根节点入队,访问队头元素,并将其左右孩子入队,循环直至队列为空结束。

算法代码实现如下:

void leveorder(BiTree T){
//层次遍历 
	deque<BiTree> d;
	if(T)//根结点不为空时入队 
	d.push_back(T); 
	while(!d.empty()){//当队不为空时循环 
		T=d.front();//取队头元素并访问该点信息 
		cout<<T->data;
		if(T->lchild)//将该结点的左孩子和右孩子纳入队中 
		d.push_back(T->lchild);
		if(T->rchild)
		d.push_back(T->rchild);
		d.pop_front();//队头元素出队
	}
} 

5.具体实现

#include <bits/stdc++.h>
#define INIT ios::sync_with_stdio(false)
using namespace std;
typedef struct BiTNode{
	int data;
	struct BiTNode *lchild,*rchild;
}BiNode,*BiTree;
void creat(BiTree &T){
	int n;
	cin>>n;
	if(n==0)//输入0时表示结点为空 
		T=NULL;
	else
	{
		T=new BiNode;
		T->data=n;
		creat(T->lchild);//创建左子树 
		creat(T->rchild);//创建右子树 
	}
}
void preorder(BiTree T){
//二叉树的非递归前序遍历 
	stack<BiTree> s;
	while(T||!s.empty()){
	//当前结点或栈不为空时执行该循环 
		if(T!=NULL){//当前结点不为空时 
			cout<<T->data;//访问当前结点信息 
			s.push(T);//将该节点的地址压栈 
			T=T->lchild;//遍历左孩子 
		}
		else{//当前结点为空时 
			T=s.top();//取栈顶的元素 
			s.pop();//弹栈 
			T=T->rchild;//遍历右孩子 
		}
	}
}
void inorder(BiTree T){
//二叉树的非递归中序遍历 
	stack<BiTree> s;
	while(T||!s.empty()){
	//当前结点或栈不为空时执行该循环 
		if(T!=NULL){//当前结点不为空时
			s.push(T);//将该节点的地址压栈
			T=T->lchild;//遍历左孩子
		}
		else
		{
			T=s.top();//取栈顶的元素
			s.pop();//弹栈
			cout<<T->data;//访问当前结点信息
			T=T->rchild;//遍历右孩子			
		}
	}
}
void postorder(BiTree T){
//二叉树的非递归后序遍历 
	BiTree r=NULL;
	stack<BiTree> s;
	while(T||!s.empty()){
		if(T!=NULL){//当结点不为空时,该结点压栈并遍历其左子树 
			s.push(T);
			T=T->lchild;
		}
		else{//当左子树结点为空时,取栈顶元素进行右子树的遍历, 
			T=s.top();
			if(T->rchild!=NULL&&T->rchild!=r){
			//右子树部位空且右子树没有被遍历过 
				T=T->rchild;
				s.push(T);//将该结点压栈,遍历其左子树 
				T=T->lchild;
			}
			else{//右子树为空或已遍历则取栈顶元素访问该结点的信息 
				s.pop();
				cout<<T->data;
				r=T;//标记遍历过的点,用于判断右子树是否已遍历 
				T=NULL;//遍历结点的指针置空,下次遍历直接取栈中的值 
			}
		}
	}
}
void leveorder(BiTree T){
//层次遍历 
	deque<BiTree> d;
	if(T)//根结点不为空时入队 
	d.push_back(T); 
	while(!d.empty()){//当队不为空时循环 
		T=d.front();//取队头元素并访问该点信息 
		cout<<T->data;
		if(T->lchild)//将该结点的左孩子和右孩子纳入队中 
		d.push_back(T->lchild);
		if(T->rchild)
		d.push_back(T->rchild);
		d.pop_front();//队头元素出队
	}
} 
int main() {
	INIT;
	BiTree T;
	creat(T);
	preorder(T);//先序 
	cout<<endl;
	
	inorder(T);//中序 
	cout<<endl;
	
	postorder(T);//后序 
	cout<<endl;
	
	leveorder(T);//层次 
	cout<<endl;
	return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值