二叉树的非递归遍历-数据结构

二叉树的非递归遍历:先序、中序、后续、层序。

其中前三种用了栈来辅助存储结点,层序利用了队列来辅助存储结点。

后序较前面两种遍历稍微复杂点,因为根结点是最后输出的,所有根结点要访问到2次,在第二次访问时输出,需要做辅助标记。

为了简化问题,二叉树也简单的形同:ABC##DE###FG###    #代表空结点。

当然,为了和前面的知识点联系起来,stack和queue都是自己写的,没有用STL容器里的,当然换容器写的话就要简洁很多。

代码:

#include<stdio.h>
#include<string.h>
#include<malloc.h>

#define InitStackSize 100
#define MaxQueueSize 100
#define Increase 100

typedef char Elemtype;

typedef struct TNOde
{
	struct TNOde *lchild,*rchild;
	Elemtype data;
}TNOde,*BinTree;

typedef struct SqStack
{
	BinTree *base,*top;
	int stacksize;
	int length; 
}SqStack;

typedef struct SqQue
{
	BinTree *base;
	int front;
	int rear;
}SqQue;


//栈的操作 
void InitStack(SqStack &S)
{
	S.base=S.top=(BinTree*)malloc(InitStackSize*(sizeof(BinTree)));
	S.stacksize=InitStackSize;
	S.length=0;
}

void Push(SqStack &S,BinTree q)
{
	if(S.top-S.base>=S.stacksize)
	{
		S.base=(BinTree*)realloc(S.base,(Increase+S.stacksize)*sizeof(BinTree));
		S.top=S.base+S.stacksize;
		S.stacksize+=Increase;
	} 
	*S.top=q;
	S.top++;
	S.length++;
}

bool EmptyStack(SqStack S)
{
	if(S.base==S.top) return true;
	else return false;
}

BinTree StackTop(SqStack S)
{
	BinTree e;
	e=*--S.top;
	return e; 
}

void PopStack(SqStack &S)
{
	S.top--;
	S.length--;
}
///以上栈的操作 

///队列的操作 
void InitQue(SqQue &Q)
{
	Q.base=(BinTree*)malloc(MaxQueueSize*(sizeof(BinTree)));
	Q.front=Q.rear=0;
}

void PushQue(BinTree T,SqQue &Q)
{
	Q.base[Q.rear]=T;
	Q.rear=(Q.rear+1)%MaxQueueSize;
}

bool EmptyQue(SqQue Q)
{
	if(Q.front==Q.rear) return true;
	else return false;
}

BinTree PopQue(SqQue &Q)
{
	BinTree e;
	e=Q.base[Q.front];
	Q.front=(Q.front+1)%MaxQueueSize;
	return e;
}
///以上队列的操作 


以下二叉树操作 
void CreatTree(BinTree &T) //先序递归构造二叉树   形如ABC##DE###FG###
{
	Elemtype ch;
	scanf("%c",&ch);
	if(ch=='#') T=NULL;
	else
	{
		T=(TNOde*)malloc(sizeof(TNOde));
		T->data=ch;
		CreatTree(T->lchild);
		CreatTree(T->rchild);
	}
}

void PreOrTree(BinTree T)  //非递归先序遍历 
{
	SqStack s;
	BinTree p;
	p=T;
	InitStack(s); 	
	while(p || !EmptyStack(s))
	{
		if(p)    
		{
			printf("%c",p->data);  //访问根结点 
			Push(s,p); //根结点入栈 
			p=p->lchild; //访问左孩子 
		}
		else
		{
			p=StackTop(s);  //左孩子访问结束   根结点出栈 
			PopStack(s);  
			p=p->rchild;  //访问右结点 
		}
	}
	printf("\n");
}

void InOrTree(BinTree T) //中序非递归遍历 
{
	SqStack s;
	BinTree p;
	p=T;
	InitStack(s);
	while(p || !EmptyStack(s))
	{
		if(p)
		{
			Push(s,p);       //根结点存在,入栈 
			p=p->lchild;     //访问左孩子 
		}
		else
		{
			p=StackTop(s);   //左孩子访问过 输出根结点 
			PopStack(s);  //根结点出栈 
			printf("%c",p->data);
			p=p->rchild;    //访问右结点 
		}
	}
	printf("\n");
}

void PostOrTree(BinTree T)  //后续非递归遍历 
{
	BinTree p,q;
	SqStack s;
	int mark[InitStackSize]; //为了问题简便,假设初始栈容量够用,不然就要溢出了 
	memset(mark,0,sizeof(mark));
	p=T;
	InitStack(s);
	while(p || !EmptyStack(s))
	{
		if(p)  //从树(子树)根结点开始 一直访问左子树 找到左下角叶结点  途中所经过的结点  
		{
			Push(s,p);
			mark[s.length]=0;  //一直找左子树,右子树未访问 mark置0 
			p=p->lchild;
		}
		else  //左子树遍历完后 
		{
			if(mark[s.length]==0)     //栈顶右子树未访问,访问右子树 
			{
				mark[s.length]=1;   //第一次访问右子树  置1 
				p=StackTop(s);  //取栈顶元素  访问其右子树 
				p=p->rchild;
			}
			else                //mark已经是1  说明已经访问过右子树了    
			{
				q=StackTop(s);
				printf("%c",q->data);  //输出根结点 
				PopStack(s);  //栈中结点删除 
			} 
		}
	}
	printf("\n");
}

/*
层序遍历思路:
1.根结点非空,入队; 
2.队列非空,队头出队,输出队头,如果左孩子存在,左孩子入队,如果右孩子存在,右孩子入队; 
3.重复上述步骤,访问所有结点。 
*/
void LevelOrdTree(BinTree T)  //非递归层序遍历 
{
	BinTree p;
	SqQue que;
	InitQue(que);
	if(T)
	{
		PushQue(T,que);
	}
	while(!EmptyQue(que))
	{
		p=PopQue(que);   //为了方便,写元素直接出队,并返回该元素   省去先GetTop 然后元素Pop 
		printf("%c",p->data);
		if(p->lchild) PushQue(p->lchild,que); //左孩子不空  入队 
		if(p->rchild) PushQue(p->rchild,que); //右孩子不空  入队 
	}
	printf("\n");
}

int DepthTree(BinTree T)  //二叉树深度 
{
	int ldepth,rdepth;
	if(T==NULL) return 0;
	ldepth=DepthTree(T->lchild);
	rdepth=DepthTree(T->rchild);
	return (ldepth>rdepth?ldepth:rdepth)+1;
}

int LeavesNum(BinTree T)  //二叉树叶子结点数 
{
	if(T==NULL) return 0;
	if(T->lchild==NULL && T->rchild==NULL) return 1;
	return LeavesNum(T->lchild)+LeavesNum(T->rchild);
}  

int main()
{
	BinTree Tree;
	CreatTree(Tree);
	printf("PreOrder travel Tree:\n"); //非递归先序遍历 
	PreOrTree(Tree);
	printf("InOrder travel Tree:\n");//非递归中序遍历 
	InOrTree(Tree);
	printf("PostOrder travel Tree:\n");//非递归后序遍历 
	PostOrTree(Tree);
	printf("Level order treval Tree:\n"); //非递归层序遍历 
	LevelOrdTree(Tree);   
	printf("The depth of the Tree:%d\n",DepthTree(Tree));//二叉树深度
	printf("The leaves number:%d\n",LeavesNum(Tree)); //二叉树叶子结点数 
	
	
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值