【实验目的】
- 熟练掌握树的基本概念、二叉树的基本操作及在链式存储结构上的实现。
- 重点掌握二叉树的生成、遍历及求深度等算法。
- 掌握二叉树的线索化及线索二叉树的遍历算法;掌握赫夫曼树的含义及其应用。
- 掌握运用递归方式描述算法及编写递归C程序的方法,提高算法分析和程序设计能力。
【问题描述】
二叉树采用二叉链表作存储结构,试编程实现二叉树的如下基本操作: - 按先序序列构造一棵二叉链表表示的二叉树T;
- 对这棵二叉树进行遍历:先序、中序、后序以及层次遍历序列,分别输出结点的遍历序列;
- 求二叉树的深度。
4.求叶子结点的个数。 - 将二叉树每个结点的左右子树交换位置。
要求设计一漂亮、实用的功能菜单,每个功能用一函数表示。
【测试数据】 - 输入:#↙,建立一棵空树,
先序、中序、后序遍历和层次遍历没有输出,树的深度输出为0;
叶子结点个数为;0。 - 输入:A↙
先序、中序、后序遍历和层次遍历输出均为A;
深度输出为:1 ;
叶子结点个数为:1 - 输入:ABC##DE#G##F###↙,
先序输出为: A B C D E G F
中序序列为: C B E G D F A
后序序列为: C G E F D B A
层次遍历输出为:A B C D E F G
深度输出为: 5
叶子结点个数为:3 - 输入: ABD#GJ##K##E##C#FH##IL###↙,
先序遍历输出为:A B D G J K E C F H I L
层次遍历输出为:A B C D E F G H I J K L
中序序列为: D J G K B E A C H F L I
后序序列为: J K G D E B H L I F C A
深度输出为: 5
叶子结点个数为:5
【说明】 - 按先序次序输入二叉树中结点的值,用’#'表示空树,对每一个结点应当确定其左右子树的值(为空时必须用特定的空字符占位),故执行此程序时,最好先在纸上画出你想建立的二叉树,每个结点的左右子树必须确定,若为空,则用特定字符标出,然后再按先序输入这棵二叉树的字符序列;
- 为了简化程序的书写量,以及程序的清晰性,对结点的访问以一条输出语句表示,若有更复杂的或多种访问,可以将结点的访问编写成函数,然后通过函数指针进行函数的调用。读者若有兴趣,可自行编写。
- C语言函数参数传递,都是“传值”的方式,故在设计函数时,必须注意参数的传递,若想通过函数修改实际参数的值,必须对指针变量作参数。具体设计时,读者一定要把指针变量、指针变量指向的值等概念弄清楚;
- 对于其他算法,请读者思考,自行编程完成,以加深学习体会。
【提高题】
有能力的同学,可以继续完成下面2道题。 - 按中序顺序建立一棵二叉树;
- 用非递归方式遍历二叉树(先序、中序或后序),输出遍历序列。
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 100
/*二叉树的二叉链表存储结构*/
typedef char dataType;
typedef struct node
{
dataType data;
struct node *lchild, *rchild; /**左右孩子指针**/
} *BinTree,BinNode; /**结点类型**/
typedef BinTree QelemType;
typedef struct
{
QelemType num[MaxSize];
int front;
int rear;
} Queue;
Queue Q;
void initilize() ///初始化队列
{
Q.front = 0;
Q.rear = 0;
}
int Push(BinNode *T) ///入队
{
if((Q.rear+1)==Q.front)
return 0;
else
Q.num[++Q.rear] = T;
return 1;
}
BinNode *Pop() ///出队
{
if(Q.front==Q.rear)
return 0;
return Q.num[++Q.front];
}
int Empty() ///判断对列是否为空
{
if(Q.front==Q.rear)
return 1;
else
return 0;
}
///建立二叉树
int CreateBiTree(BinTree &T)///输入字符序列,先序遍历建立二叉链表
{
char ch;
ch = getchar(); ///输入一个字符
if(ch == '#')
{
T = NULL;
}
else ///如果结点不为空
{
T = (BinNode*)malloc(sizeof(BinNode)); ///申请一个结点空间
if(!T)
{
return 0;
}
T->data = ch;
CreateBiTree(T->lchild);///创建左子树
CreateBiTree(T->rchild);///创建右子树
}
return 1;
}
///中序遍历
void inOder(BinTree T)
{
if(!T)
return ;
if(T)
{
inOder(T->lchild);
printf("%c ", T->data);
inOder(T->rchild);
}
}
///先序遍历
void PreOder(BinTree T)
{
if(!T)
return ;
if(T)
{
printf("%c ", T->data);
PreOder(T->lchild);
PreOder(T->rchild);
}
}
///后序遍历
void PostOder(BinTree T)
{
if(!T)
return ;
if(T)
{
PostOder(T->lchild);
PostOder(T->rchild);
printf("%c ", T->data);
}
}
///二叉树的层次遍历
void LevelOrder(BinTree T)
{
BinNode *temp;
if(!T)
return;
Push(T);
while (!Empty())
{
temp = Pop();
printf("%c ", temp->data); ///输出队首结点
if(temp->lchild) ///把Pop掉的结点的左子结点加入队列
Push(temp->lchild);
if(temp->rchild) ///把Pop掉的结点的右子结点加入队列
Push(temp->rchild);
}
}
///二叉树的深度
int Depth(BinTree T)
{
int hl, hr;
if(!T)
return 0;
else
{
hl = Depth(T->lchild);
hr = Depth(T->rchild);
if(hl >= hr)
return hl + 1;
else
return hr + 1;
}
}
///求叶子节点的个数
void CountLeaf(BinTree T,int &cnt)
{
if(T)
{
if((!T->lchild) && (!T->rchild))
cnt++;
CountLeaf(T->lchild,cnt);
CountLeaf(T->rchild,cnt);
}
}
///交换左右子树
int exchange(BinTree &T)
{
BinNode *temp;
if(!T)
return 0;
if(T->lchild == NULL && T->rchild == NULL)
return 0;
else
{
temp = T->lchild;
T->lchild = T->rchild;
T->rchild = temp;
}
if(T->lchild)
exchange(T->lchild);
if(T->rchild)
exchange(T->rchild);
return 1;
}
void menu()
{
printf("--------------------二叉树的建立与应用-------------------------\n");
printf("\t1.二叉树的中序遍历\n");
printf("\t2.二叉树的前序遍历\n");
printf("\t3.二叉树的后序遍历\n");
printf("\t4.二叉树的层次遍历\n");
printf("\t5.二叉树的深度\n");
printf("\t6.二叉树叶子结点的个数\n");
printf("\t7.二叉树每个结点的左右子树交换位置\n");
printf("\t8.退出系统\n");
printf("----------------------------------------------------------------\n");
}
int main()
{
BinTree T;
int m,cnt=0;
menu();
printf("按先序序列创建一个二叉树:\n");
if(CreateBiTree(T)==1)
printf("创建成功!\n");
while(1)
{
scanf("%d", &m);
if(m == 1)
{
printf("中序遍历为:\n");
inOder(T);
printf("\n");
}
else if(m == 2)
{
printf("先序遍历为:\n");
PreOder(T);
printf("\n");
}
else if(m == 3)
{
printf("后序遍历为:\n");
PostOder(T);
printf("\n");
}
else if(m == 4)
{
printf("层次遍历为:\n");
initilize();
LevelOrder(T);
printf("\n");
}
else if(m == 5)
{
printf("二叉树深度为:\n");
printf("%d\n", Depth(T));
}
else if(m == 6)
{
printf("二叉树叶子结点数为:\n");
CountLeaf(T,cnt);
printf("%d\n",cnt);
}
else if(m == 7)
{
printf("左右子树进行交换:\n");
if(exchange(T)==1)
printf("交换完成!\n");
printf("交换后中序遍历为:\n");
inOder(T);
printf("\n");
printf("交换后先序遍历为:\n");
PreOder(T);
printf("\n");
printf("交换后后序遍历为:\n");
PostOder(T);
printf("\n");
printf("交换后层次遍历为:\n");
initilize();
LevelOrder(T);
printf("\n");
}
else
break;
}
return 0;
}