数据结构③:二叉树的操作

一、要求:

1)采用下列方法之一建立二叉树的二叉链表:

 ① 输入完全二叉树的先序序列,用#代表虚结点(空指针),如ABD###CE##F##,建立二叉树的二叉链表。
 ② 已知二叉树的先序遍历序列和中序遍历序列,或者已知二叉树的中序遍历序列和后序遍历序列,建立二叉树的二叉链表。
 ③ 将一棵二叉树的所有结点存储在一维数组中,虚结点用#表示,利用二叉树的性质5,建立二叉树的二叉链表。

2)写出对用二叉链表存储的二叉树进行先序、中序和后序遍历的递归和非递归算法。
3)写出对用二叉链表存储的二叉树进行层次遍历算法。
4)求二叉树的所有叶子及结点总数。
5)求二叉树的深度。

二、思路:

1)
①利用完全二叉树的先序序列建立二叉树的二叉链表,首先读入一个字符存入变量ch,若ch是“#”,则表示要建立的结点为空结点;否则,申请结点,把ch值赋给结点的data域,并将该结点作为二叉树的根结点,然后根据继续读入的字符依次建立该二叉树的左右子树。
②已知二叉树的先序遍历(或后序遍历,层次遍历)序列与中序遍历序列可确定唯一一棵二叉树,但知道先序遍历序列和后序遍历序列不能确定唯一一棵二叉树。

2)
①对用二叉链表存储的二叉树进行遍历的递归算法:
 先序算法:
  如果二叉树为空,则空操作;否则:
   1.访问根结点
   2.先序遍历左子树
   3.先序遍历右子树
 中序和后序算法只改变1.2.3.的顺序即可。

②非递归算法:利用栈消除递归。

3)层次遍历算法需利用队列的操作。需用队列存放所有未访问的结点,一旦结点出队列,则访问该结点,直到所有结点都访问为止。

4)若统计二叉树的叶子结点数,只要对二叉树进行某种遍历,在访问结点时,判断该结点的左右子树是否为空,若为空,则该结点必为叶子结点。

5)若二叉树为空,则深度未0;否则其深度为左右子树深度的较大者加1。因此可以对二叉树进行后续遍历,分别求出左右子树的深度depthL和depthR,较大者加1即可。

三、代码:

#include<stdio.h>
#include<stdlib.h>

#define StackInitSize 100  // 栈初始大小
#define StackIncrement 10 //栈存储空间增量

#define QMAXSIZE 100   //循环队列的初始大小

typedef struct BiTNode{     //二叉树
	char data;
	struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

typedef BiTree BT;

typedef struct{     //栈
	BT *base;       
	BT *top;               
	int stacksize;	
}SqStack;   

typedef struct{    //队列
	BT *base;
	int front,rear;
}CqQueue;              

//******栈操作*******//
void InitStack(SqStack &S){
	S.base = (BT*)malloc(StackInitSize*sizeof(BT));
	if(!S.base)
		return ;
	S.top = S.base;      
	S.stacksize = StackInitSize;     
}

int StackEmpty(SqStack S){
	if(S.top == S.base)
		return 1;
	return 0;
}

void Push(SqStack &S,BT e){
	if(S.top-S.base >= S.stacksize){
		S.base = (BT*)realloc(S.base,(S.stacksize+StackIncrement)*sizeof(BT));
		if(!S.base)
			return ;
		S.top = S.base + StackIncrement;
		S.stacksize += StackIncrement; 
	}
	*S.top++ = e;
}


void Pop(SqStack &S,BT &e){
	if(S.top== S.base)
		return ;
	e = *--S.top;
}

BT GetTop(SqStack S,BT &e){
	if(S.top == S.base)
		return NULL;
	e = *(S.top-1);
	return e;
}

//**********队列操作*********//
void InitQueue(CqQueue &Q){
	Q.base = (BT*)malloc(QMAXSIZE*sizeof(BT));
	if(!Q.base)
		return ;
	Q.front = Q.rear =0;
}

int QueueEmpty(CqQueue Q){
	if(Q.rear == Q.front)
		return 1;
	return 0;
}

void EnQueue(CqQueue &Q,BT e){
	if((Q.rear+1) % QMAXSIZE == Q.front )
		return ;
	Q.base[Q.rear] = e;
	Q.rear = (Q.rear+1)%QMAXSIZE;
}

void DeQueue(CqQueue &Q,BT &e){
	if(Q.front == Q.rear)
		return ;
	e = Q.base[Q.front];
	Q.front = (Q.front+1)%QMAXSIZE;
}

//*********************************//


void CreateBiTree_1(BiTree &bt){
	//输入完全二叉树的先序序列建立二叉树的二叉链表
	char ch;
ch = getchar();//或scanf("%c",&ch);
	if(ch == '#')
		bt = NULL;
	else{
		if(!(bt = (BiTNode*)malloc(sizeof(BiTNode))))
			return ;
		bt->data = ch;   //生成根结点
		CreateBiTree_1(bt->lchild);  //先序建立左子树
		CreateBiTree_1(bt->rchild);  //右子树
	}
}
/*************此处注释掉***********//
void CreateBiTree_2(BiTree &bt,char preArray[],char inArray[],int n){
	//已知先序遍历和中序遍历序列,建立二叉树的二叉链表
	int i,ln,rn,k;
	char preArray_L[20],inArray_L[20],preArray_R[20],inArray_R[20];
	if(n<1){        //空树
		bt = NULL;
		return ;
	}
	bt = (BiTree)malloc(sizeof(BiTNode));
	bt->data = preArray[0];
	i = 0;
	while(i<n && inArray[i] != preArray[0])  //在中序遍历序列中查找根结点
		i++;
	ln = i;
	rn = n-i-1;
	for(k=0;k<i;k++){         //处理左子树的先序和中序遍历序列
		preArray_L[k] = preArray[k+1];
		inArray_L[k] = inArray[k];
	}
	for(k=i+1;k<n;k++){    //处理右子树的先序和中序遍历序列
		preArray_R[k-i-1] = preArray[k];
		inArray_R[k-i-1] = inArray[k];
	}
	CreateBiTree_2(bt->lchild,preArray_L,inArray_L,ln);
	CreateBiTree_2(bt->rchild,preArray_R,inArray_R,rn);
}
/***********注释到此为止*************/
void visit(char s){   
	//访问结点
	printf("%c  ",s);
}

//*******递归算法遍历二叉树********//
void Rec_PreOrderTraverse(BiTree bt){
	//先序遍历
	if(bt){
		visit(bt->data);              //访问根结点
		Rec_PreOrderTraverse(bt->lchild);  //先序遍历左子树
		Rec_PreOrderTraverse(bt->rchild);  //先序遍历右子树
	}
}
void Rec_InOrderTraverse(BiTree bt){
	//中序遍历
	if(bt){
		Rec_InOrderTraverse(bt->lchild);  //先序遍历左子树
		visit(bt->data);              //访问根结点
		Rec_InOrderTraverse(bt->rchild);  //先序遍历右子树
	}
}
void Rec_PostOrderTraverse(BiTree bt){
	//后序遍历
	if(bt){
		Rec_PostOrderTraverse(bt->lchild);  //先序遍历左子树
		Rec_PostOrderTraverse(bt->rchild);  //先序遍历右子树
		visit(bt->data);              //访问根结点
	}
}
//*******非递归算法遍历二叉树********//
void NotRec_PreOrderTraverse(BiTree bt,SqStack S){
	//先序遍历
	BT p;
	if(bt){
		InitStack(S);
		Push(S,bt);         //根节点入栈
		while(!StackEmpty(S)){
			while(GetTop(S,p) && p){   //栈顶元素为非空值
				visit(p->data);
				Push(S,p->lchild);       //向左走到尽头
			}
			Pop(S,p);                   //空结点出栈
			if(!StackEmpty(S)){
				Pop(S,p);
				Push(S,p->rchild);
			}
		}//while
	}//if
}
void NotRec_InOrderTraverse(BiTree bt,SqStack S){	
	//中序遍历    仅将先序遍历中的visit函数调用 放在Pop函数后面即可
	BT p;
	if(bt){
		InitStack(S);
		Push(S,bt);
		while(!StackEmpty(S)){
			while(GetTop(S,p) && p){
				Push(S,p->lchild);
			}
			Pop(S,p);
			if(!StackEmpty(S)){
				Pop(S,p);
				visit(p->data);
				Push(S,p->rchild);
			}
		}//while
	}//if
}
void NotRec_PostOrderTraverse(BiTree bt,SqStack S){
	//后序遍历
	BT p,q;
	if(bt){
		InitStack(S);
		Push(S,bt);
		while(!StackEmpty(S)){
			while(GetTop(S,p) && p)    //遍历左子树
				Push(S,p->lchild); 
			Pop(S,p);                  //空结点出栈
			if(!StackEmpty(S)){        //遍历右子树
				GetTop(S,p);
				if(p->rchild)            //右子树非空
					Push(S,p->rchild);         //右子树根结点出栈
				else{                    //左右子树遍历结束,访问根结点
					Pop(S,p);
					visit(p->data);
					while(!StackEmpty(S) && GetTop(S,q) && q->rchild ==p){            //若访问的结点为其双亲结点的左右孩子,则双亲结点出栈
						Pop(S,p);
						visit(p->data);
					}//while
					if(!StackEmpty(S)){     //是栈顶结点的右孩子出栈
						GetTop(S,p);
						Push(S,p->rchild);
					}//if
				}//else
			}//if
		}//while
	}//if
}
//***********层次遍历**********//
void LevelOrderTraverse(BiTree bt,CqQueue Q){
	if(bt){
		BT p;
		InitQueue(Q);
		EnQueue(Q,bt);    //根结点入队列
		while(!QueueEmpty(Q)){
			DeQueue(Q,p);    //队头元素出队列
			visit(p->data);
			if(p->lchild) 
				EnQueue(Q,p->lchild);     //非空左孩子入队列
			if(p->rchild) 
				EnQueue(Q,p->rchild);        //非空右孩子入队列
		}//while
	}//if
}

void CountLeaf(BiTree bt,int &leaves){
	//计算叶子结点数
	if(bt){
		CountLeaf(bt->lchild,leaves);    //遍历左子树
		if(!bt->lchild && !bt->rchild)    //计算叶子结点数
			leaves++;
		CountLeaf(bt->rchild,leaves);      //遍历右子树
	}
}
int BiTreeDepth(BiTree bt){
	//计算二叉树的深度
	int depthL,depthR;
	if(bt == NULL)
		return 0;
	else{
		depthL = BiTreeDepth(bt->lchild);
		depthR = BiTreeDepth(bt->rchild);
		if(depthL >= depthR)
			return depthL+1;
		else
			return depthR+1;
	}
}

void main(){
	int b,leaves;
	leaves = 0;  //叶子节点数
	SqStack S;    //栈
	InitStack(S);
	CqQueue Q;	  //队列
	InitQueue(Q);
	BiTree bt;    //二叉树
	printf("请输入完全二叉树的二先序序列:\n");
	CreateBiTree_1(bt);
	printf("递归算法遍历二叉树:\n");
	printf("先序遍历:");
	Rec_PreOrderTraverse(bt);
	printf("\n");
	printf("中序遍历:");
	Rec_InOrderTraverse(bt);
	printf("\n");
	printf("后序遍历:");
	Rec_PostOrderTraverse(bt);
	printf("\n");
	printf("非递归算法遍历二叉树:\n");
	printf("先序遍历:");
	NotRec_PreOrderTraverse(bt,S);
	printf("\n");
	printf("中序遍历:");
	NotRec_InOrderTraverse(bt,S);
	printf("\n");
	printf("后序遍历:");
	NotRec_PostOrderTraverse(bt,S);
	printf("\n");
	printf("层次遍历二叉树:");
	LevelOrderTraverse(bt,Q);
	printf("\n");
	printf("叶子节点数为:");
	CountLeaf(bt,leaves);
	printf("%d\n",leaves);
	printf("二叉树的深度为:");
	b=BiTreeDepth(bt);
	printf("%d\n",b);
}

结果:
在这里插入图片描述
在这里插入图片描述


Directions:

 仅代表初识数据结构时思路。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cloudcodes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值