二叉树遍历

这篇博客详细介绍了二叉树的先序、中序、后序遍历以及层次遍历的递归和非递归算法实现。通过递归方法,分别展示了先序、中序和后序遍历的代码实现,同时利用栈和队列实现了非递归的层次遍历和先序遍历。非递归算法中,利用栈保存节点状态以完成后序遍历。所有代码均包含节点结构体定义和辅助数据结构如栈和队列的创建及操作方法。
摘要由CSDN通过智能技术生成

二叉树的遍历:
遍历二叉树根据根节点,左子树和右子树的访问顺序可分为先序遍历,中序遍历和后序遍历。

一:设计思想:
递归遍历:由二叉树的递归定义可知:二叉树是由3个基本单元组成的:根结点,左子树和右子树。因此,若是能依次遍历这三部分,便是访问了整个二叉树。其中左子树或右子树又是一棵新的具有根结点,左子树和右子树的二叉树。遍历左子树或右子树又是在重新遍历一棵新的二叉树。遍历二叉树时又在调用遍历二叉树方法本身,因而可以使用递归算法。

非递归算法:为了实现非递归遍历算法,我们需要一个栈或队列作为实现算法的辅助数据结构,栈用于存放在遍历过程中待处理的任务线索。二叉树是非线性数据结构,遍历过程中涉及的每一个结点,都可能有左、右两棵子树,任何时刻程序只能访问其中之一,所以程序必须保留以后继续访问另一棵子树的线索。这里使用堆栈来保留继续遍历的线索。

下面给出的是用递归算法实现二叉树先序遍历的源代码:

void PreorderRecursive(BinaryTree Binary)
{
	BinaryNode *p=Binary;
	if(p)
	{
		visit(p->date);
		PreorderRecursive(p->lchild);
		PreorderRecursive(p->rchild);
	}
}

下面给出的是用递归算法实现二叉树中序遍历的源代码:

void MidorderRecursive(BinaryTree Binary)
{
	BinaryNode *p=Binary;
	if(p)
	{
		PreorderRecursive(p->lchild);
		visit(p->date);
		PreorderRecursive(p->rchild);
	}
}

下面给出的是用递归算法实现二叉树后序遍历的源代码:

void PostorderRecursive(BinaryTree Binary)
{
	BinaryNode *p=Binary;
	if(p)
	{
		PreorderRecursive(p->lchild);
		PreorderRecursive(p->rchild);
		visit(p->date);
	}
}

下面给出的是用非递归算法实现二叉树层次遍历的源代码:

void  leveltra(BinaryTree Binary)
{
	QueueList *Q;
	Q=InitQueue();
	BinaryNode *p;
	p=InitBinaryNode();
	p=Binary;
	EnQueue(Q,p);
	while (!QueueEmpty(Q))
	{
		p=DeQueue(Q);
		visit(p->date);
		if(p->lchild)
		EnQueue(Q,p->lchild);
		if(p->rchild)
		EnQueue(Q,p->rchild);
	}
}

下面给出的是用非递归算法实现二叉树先序遍历的源代码:

void  Preorder(BinaryTree Binary)
{
	StackList L;
	L=InitStack();
	BinaryNode *p;
	p=Binary;
	do{
		//弹栈,找有右孩子的结点的右孩子
		if(!StackEmpty(L))							//这里if和while语句换位置是为了可以访问到最后一个元素 
			{
				p=Pop(L);				//现在p指向右孩子
			}
		while(p)
		{
			visit(p->date);
			if(p->rchild)		//这里判断了只有遍历的结点有右孩子才会进栈,所以后边弹栈的时							//候不需要用do while语句来找右孩子,省去遍历空结点 
			{
				Push(L,p->rchild);
			}
			p=p->lchild;
		}
			
	}while(!StackEmpty(L));
}

下面给出的是用非递归算法实现二叉树中序遍历的源代码:

void Midorder(BinaryTree Binary)		//左根右 ,将每棵树的根压入栈中,先去遍历左子树,直到为空,
{
	StackList L;
	L=InitStack();
	BinaryNode *p;
	p=Binary;
	
	do
	{
		while(p)
		{
			Push(L,p);
			p=p->lchild; 
		}
		p=Pop(L);
		visit(p->date);
		p=p->rchild; 
	}while(p|| !StackEmpty(L));	
}

下面给出的是用非递归算法实现二叉树后序遍历的源代码:

下面给出的是用非递归算法实现二叉树后序遍历的源代码:
void  Postorder(BinaryTree Binary)	//左右根
{
	StackList L;
	L=InitStack();
	BinaryNode *p;
	p=Binary;
	bool state=false;
	do
	{
		while(p) 
		{
			Push_state(L,p,state);//同中序遍历,将沿途根结点入栈,第一次入栈state为false 
			p=p->lchild;
		} 
		if(!StackEmpty(L))
		{
			p=Pop_state(L,state); 	//弹出根结点,并取得对应state 
			if(state==false) 		/
			{  
				state=true;			//所以此时将其压回栈,并访问右子树,
				Push_state(L,p,state);//这是需要将其对应state标志为true,
				p=p->rchild;
			}
			else{ 					//右子树访问完,可以visit 
				visit(p->date);
				p=NULL;			//目的是表示此子树访问完,强制弹栈使之回到上一个根结点 
			}
		}
	}
	while(!StackEmpty(L));
}

以下为二叉树结点结构体类型的声明:

typedef struct BinaryNode{
	char date;
	struct BinaryNode *lchild;
	struct BinaryNode *rchild; 
}BinaryNode,*BinaryTree;
BinaryNode *InitBinaryNode(){
	BinaryNode *b;
	b=(BinaryNode *)malloc(sizeof(BinaryNode));
	b->lchild=NULL;
	b->rchild=NULL;
	return b; 
}

BinaryNode *CreateBiTree(BinaryNode *Binary){
	char ch;
	ch=getchar();
	if(ch=='#') return NULL;	//binary=NULL; 
	else{
		Binary=InitBinaryNode();
		Binary->date=ch;
  		Binary->lchild=CreateBiTree(Binary->lchild);
		Binary->rchild=CreateBiTree(Binary->rchild); 
	}		
	return Binary;
} 

以下为实现非递归算法所需要的栈和队列的相关代码:

void visit(char ch)
{
	printf("%c  ",ch);
}

/*-------------------------------------------------------------------------------栈的定义和相关方法-------*/ 
//定义栈	这里的栈存取的是二叉树节点,注意返回和输入的类型 
typedef struct StackNode{
	bool state;							//后序遍历需要一个指示状态的bool 
	BinaryNode *date;
	struct StackNode *next;
} StackNode,*StackList;
//栈的相关方法:

StackNode *InitStack()
{
	StackNode *L;
	L=(StackNode *)malloc(sizeof(StackNode));
	if(!L)
	{
		exit (-1);
	}
	L->state=false;
	L->next=NULL;
	L->date=NULL;
	return L;
}


BinaryNode *Pop(StackList L)
{
	BinaryNode *b;
	StackNode *p;
	b=InitBinaryNode();
	p=InitStack();
	p=L->next;
	b=p->date;
	L->next=p->next;
	free(p);
	return b;
} 

void Push(StackList L,BinaryNode *b)
{
	StackNode *p;
	p=InitStack();
	p->date=b;
	p->next=L->next;
	L->next=p;
}

BinaryNode *Pop_state(StackList L,bool &state)
{
	BinaryNode *b;
	StackNode *p;
	b=InitBinaryNode();
	p=InitStack();
	p=L->next;
	b=p->date;
	state=p->state;
	L->next=p->next;
	free(p);
	return b;
}
void Push_state(StackList L,BinaryNode *b,bool state)
{
	StackNode *p;
	p=InitStack();
	p->date=b;
	p->next=L->next;
	p->state=state;
	L->next=p;
}

bool StackEmpty(StackList L)
{
	if(L->next==NULL)
	return true;
	else
	return false;	
}

/*-------------------------------------------------------------------------------栈的定义和相关方法-------*/ 

/*-------------------------------------------------------------------------------队列的定义和相关方法-------*/ 
//队列	这里队列存的也是二叉树节点  注意参数控制 
typedef struct QueueNode
{
	BinaryNode *date;
	struct QueueNode *next;
	
}QueueNode;

typedef struct QueueList{
	QueueNode *front;
	QueueNode *rear;
}QueueList;
//初始化 	此处写的队列也带头结点 
QueueList *InitQueue()
{
	QueueNode *Q;
	QueueList *QL;
	Q=(QueueNode *)malloc(sizeof(QueueNode));
	QL=(QueueList *)malloc(sizeof(QueueList));
	if((!Q)||!(QL))
 		exit (-1);
	Q->date=NULL;
	Q->next=NULL;
	QL->front=QL->rear=Q;	//开始让头尾都指向头结点 
	return QL;
}
//判空:
bool QueueEmpty(QueueList *Q)
{
	if(Q->front==Q->rear)
	return true;
	else return false;
} 
//入队
void EnQueue(QueueList *Q,BinaryNode *b)
{
	QueueNode *q=(QueueNode *)malloc(sizeof(QueueNode));
	q->date=b;
	q->next=NULL;
	Q->rear->next=q;
	Q->rear=q;
} 
//出队
BinaryNode *DeQueue(QueueList *Q)
{
	if(!QueueEmpty(Q)){
		QueueNode *q;
		BinaryNode *b;
		q=(QueueNode *)malloc(sizeof(QueueNode));
		b=InitBinaryNode();
		q=Q->front->next;
		b=q->date;
		Q->front->next=q->next;
		if(Q->rear==q)
			Q->rear=Q->front;	
		free(q);
		return b;
	}else exit(-1);	
} 
/*-------------------------------------------------------------------------------队列的定义和相关方法-------*/ 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值