树的遍历【递归、非递归实现】

一、实验目的
掌握二叉树遍历的基本操作,并对其进行简单应用。
二、实验内容
下图是一颗二叉树,树中的每一个结点都可以有左右两个分支。如果将其视为一张线路图,此时的每一个结点都是岔路口,可以在此选择往左或往右走。当然,如果该结点没有左右岔口,就认为这是一个死胡同。
在这里插入图片描述

现在把问题缩小,无论哪一个结点面对的都是往左或往右的选择,整个遍历过程可以简化成为持续的处理选择,直到没路可走。所以,给问题转化为对二叉树的递归遍历,由于递归函数的排列顺序不同,可以分为三种不同的遍历方式:

  1. 中序遍历
    沿着树的左方往下走,直到无法继续前进,记录结点的值,然后退回到父节点,再按照此法往右走,如果右方都无法前进,再往上一层退回。
    中序遍历的递归函数是inorder(),指针root是二叉树指针,递归操作步骤如下:
    Step 1: 检查是否可以继续前进,即指针root不等于NULL
    Step 2: 如果可以前进,处理方式如下:
    (1)递归调用inorder(root->left),往左走
    (2)处理目前的结点
    (3)递归调用inorder(root->right),往右走

  2. 先序遍历
    每遍历到一个结点,就立刻处理该结点。遍历的顺序是先向着树的左方走直到无法前进后,才转往右方走。
    先序遍历的递归函数是preorder(),指针root是二叉树指针,递归操作步骤如下:
    Step 1: 先检查是否已经到达叶结点,也就是指针root等于NULL
    Step 2: 如果不是叶子结点,表示可以继续走,处理方式如下:
    (1)处理目前结点
    (2)递归调用preorder(root->left),往左走
    (3)递归调用preorder(root->right),往右走

  3. 后序遍历
    后序遍历方式刚好和前序遍历的方式相反,它是等到结点的两个子结点都遍历过后才运行处理。后序遍历的递归函数是postorder(),输入的参数是树指针root,此时后序遍历的递归操作如下:
    Step 1: 先检查是否已经到达叶结点,也就是指针root等于NULL
    Step 2: 如果不是叶子结点,表示可以继续走,处理方式如下:
    (1)递归调用postorder(root->left),往左走
    (2)递归调用postorder(root->right),往右走
    (3)处理目前结点

3.实验准备:熟悉二叉树的特点及基本操作。

4.实验步骤:
(1)审清题意,分析并理出解决问题的基本思路。
(2) 根据基本思路,设计好程序的算法。
(3)根据算法编写源程序。(
4) 在计算机上编译程序,检验程序的可运行性

  1. 实验报告:
    (1)数据结构设计;
    (2)程序框图;
    (3)程序代码;
    (4)程序调试过程和结果;
    (5)总结
    三、实验步骤
//TreeNode
typedef struct TreeNode{
	int data;
	struct TreeNode *Left,*Right;
}TreeNode,*Tree;
 /   /前序顺序创建二叉树 
    void PlantTree(Tree &T){
    	int c;
    	cin>>c;
    	if(c==-1000){
    		T=NULL;
    	}else{
    		T=(TreeNode*)malloc(sizeof(TreeNode));
    		T->data=c;
    		PlantTree(T->Left);
    		PlantTree(T->Right);		
    	}	
    } 

//递归遍历部分*****************

void ProTraverseTree(Tree T){
	if(T){
		cout<<T->data<<" ";
		ProTraverseTree(T->Left);
		ProTraverseTree(T->Right);
	};
}
void MidTraverseTree(Tree T){
	if(T){		
		ProTraverseTree(T->Left);
		cout<<T->data<<" ";
		ProTraverseTree(T->Right);
	};
}
void PostTraverseTree(Tree T){
	if(T){		
		ProTraverseTree(T->Left);
		ProTraverseTree(T->Right);
		cout<<T->data<<" ";
	};
}

//非递归遍历部分*******************

struct Node{
	TreeNode* Data;//Data中放的是指针 
	struct Node* next;
	Node(TreeNode *e):Data(e),next(NULL){}
	Node(){next=NULL;}
};
//堆栈
struct Stack{
	Node* base;
	Stack(){base=new Node;/*头指针*/ }
	void Push(TreeNode* e){//每次放入的是Node中Data类型的元素 
		Node* t=new Node(e);
		t->next=base->next;
		base->next=t;
	}
	Node* Pop(){//Pop出的是Node* 
		Node* temp=base->next;
		base->next=temp->next;
		return temp;
	}
	bool IsStackEmpty(){
		if(base->next==NULL)
			return 1;//空返回1 
		return 0;
	}

};
//队列
struct Que{
	Node* front,*rear;
	Que(){front=new Node;rear=front;}
	void EnQue(TreeNode* e){
		Node* t=new Node(e);
		rear->next=t;
		rear=t;
	}
	Node* DeQue(){		
		Node* temp=front->next;//头结点 
		if(!temp){cout<<"出队失败,队列为空\n";exit(0);}
		if(temp->next)
			front->next=temp->next;
		if(temp->next==NULL)// TAT 
			front=rear;
		return temp;
	}
	
	bool IsQueEmpty(){
		if(front->next==NULL)
			return 1;//空返回1 
		return 0;
	}	
}; 

//主函数

int main(){
	Tree T;
	PlantTree(T);
	cout<<"前序创建二叉树完成!"<<endl;	
	//递归前序遍历 
	cout<<"递归前序遍历";ProTraverseTree(T);cout<<endl; 
	//递归中序遍历
	 cout<<"递归前中遍历";MidTraverseTree(T);cout<<endl; 
	//递归后序遍历 
	cout<<"递归前后遍历";PostTraverseTree(T);cout<<endl;
	
	/*非递归的前序遍历*/ cout<<"非递归前遍历";
	Stack S;
	S.Push(T);
	while(!S.IsStackEmpty()){//栈不空 
		TreeNode* t=S.Pop()->Data;
		cout<<t->data<<' ';
		if(t->Right)S.Push(t->Right);
		if(t->Left)S.Push(t->Left); 		
	}
	cout<<"\n---------------\n";
	
	/*非递归层序遍历*/cout<<"非递归层序遍历";
	Que Q;
	Q.EnQue(T);
	while(!Q.IsQueEmpty()){
		TreeNode* t=Q.DeQue()->Data;
		cout<<t->data<<' ';
		if(t->Left) Q.EnQue(t->Left);
		if(t->Right)Q.EnQue(t->Right);		
	}
	cout<<"\n---------------\n"; 
	return 0;
}

输入:
//5 4 2 1 -1000 -1000 3 -1000 -1000 -1000 6 -1000 8 7 -1000 -1000 9 -1000 -1000

输出:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值