【二叉树】二叉数的递归遍历、非递归遍历

1. 二叉树的存储结构

#define MAXSIZE 100
typedef struct BiTNode{
	TElemType data;  
	struct BiTNode *left ,*right; 
}BiTNode, * BiTree;

2. 二叉树的递归遍历

2.1 先序递归遍历

【算法步骤】

 1. 访问根结点

 2. 先序遍历左子树 

 3. 先序遍历右子树

【算法描述】

------------先序遍历-----------
void PreOrderTraverse(BiTree T){
	if(T){
		cout << T -> data;   //访问根节点
		PreOrderTraverse(T -> left);
		PreOrderTraverse(T -> right); 
	}
} 

2.2 中序递归遍历

【算法步骤】

1. 中序遍历左子树 

2. 访问根结点 

3. 中序遍历右子树

【算法描述】

------------中序遍历-----------
void InOrderTraverse(BiTree T){
	if(T){  //当前树不空 
	   
	   InOrderTraverse(T -> left);  //中序遍历左子树
	   cout << T -> data;           //访问根节点
	   InOrderTraverse(T -> right);	
	}
} 

2.3 后序递归遍历

【算法步骤】

后序遍历的递归算法思路:
1. 后序遍历左子树
2. 后序遍历右子树
3. 访问根结点

【算法描述】

------------后序遍历-----------
void PostOrderTraverse(BiTree T){
	if(T){
		PostOrderTraverse(T -> left);   //后序遍历左子树
		PostOrderTraverse(T -> right);
		cout << T -> data; 
	}
} 

3. 二叉树的非递归遍历

Q1.为何用到栈?

A. 由于栈的特性 —— 后进先出

Q2. 利用顺序栈还是链栈?

A. 设计到频繁的插入和删除操作,因此用到链栈。

3.1 先序非递归遍历

【算法步骤】

1. 从根结点开始,先访问根结点,输出根结点的数据域的值

2. 将根结点压入栈,以便于后续弹栈遍历右子树

3. 遍历左子树且不断输出子树根结点,并将结点压入栈

4. 从栈顶弹出无左子树的结点,开始遍历右子树

【算法描述】

void PreOrderTraverse_S(BiTree T){
	LinkStack S = new LinkStack;   //创建链栈 
	InitStack(S);                  //初始化链栈 
	
	BiTNode p = T;    //指向根节点
	BiTNode q = new BiTNode;
	
	while(p || StackEmpty(S)){
		if(p){
			cout << p -> data;  //先访问根节点
			Push(S,p);          //便于后继遍历右子树 - 根节点入栈 
			p = p -> left;      //遍历左子树 
		}
		else{
			Pop(S,q);    //弹出栈顶元素,并置为 q;
			p = q -> right;    //遍历右子树 
		} 
	} 
}

3.2 中序非递归遍历

【算法步骤】

中序遍历的非递归算法思路:

1. 从根结点开始,遇到结点则将结点压栈

2. 当遇到无左子树的结点时,将此结点弹栈且访问它并遍历它的右子树

3. 若该结点为叶子结点,则继续弹栈,开始遍历它的父节点的右子树

【算法描述】

------------中序非递归遍历-----------
void InOrderTraverse_s(BiTree T){
	InitStack(S);  //创建一个空栈
	BiTNode * p = T;   //指向根结点
	
	BiTNode * q = new BiTNode;
	
	while(p || StackEmpty(s)){
		if(p){
			Push(S,p);
			p = p -> left;
		}
		else{
			Pop(S,q);
			cout << q -> data;   //当前遍历完左子树的根节点 
			p = q -> right;      //遍历右子树
		}
	} 
} 

3.3 后续非递归遍历

【算法步骤】

后序遍历的非递归算法思路:
1. 从根结点开始,沿其左子树一直往下搜索且压栈,直至出现没有左子树的结点
2. 将此结点的 visit 域置为true,表面该结点第一次出现在栈顶
3. 取栈顶元素并弹栈,若该栈顶元素第一次出现在栈顶则压栈,并将其 visit 域置为false,开始遍历右子树
4. 若该栈顶元素第二次出现在栈顶则访问该结点,并将 指针置空以便继续弹栈,操作其父节点。

【算法描述】

void PostOrderedTraverse_S(BiTree T){
	LinkStack S = new LinkStack;
	InitStack(S);
	
    BiTNode * p = T;              //指向根结点
	BiTNode * q = new BiTNode;    //取出栈顶元素
	BiTnode * t = new BiTNode;    //指向栈顶元素
	
	while(p || StackEmpty(S)){
		//首先把左子树遍历到底
		while(p){
			Push(S,p);
			p -> vist = true;
			p = p -> left;
		} 
		if(StackEmtpy(S)){
		   t = GetTop(S);               //指向栈顶元素 
		   Pop(S,q);                   //取出栈顶元素 
		   if(t -> vist == true) {    //如果栈顶元素是第一次访问的      
			  t -> vist = false;     //再次访问栈顶元素 - 为了访问右子树       
			  p = q -> right;       //访问该结点的右子树
		   	  Push(S,p);           //把右子树进栈 - 为了访问根节点
		   } 
		   else {                   //如果当前结点不是第一次访问过的,说明他已经访问完他的左右子树
		   	   cout << t -> data;  //访问根节点 
		   	   p = NULL;          //指针域置空 
		   } 
		}
	} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值