一、要求:
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:
仅代表初识数据结构时思路。