课程设计题目
求二叉树中的结点个数、叶子结点个数以及某结点的层次和二叉树的宽度
课程设计目的
掌握二叉树遍历算法的应用,熟练使用先序、中序、后序 3 种递归遍历算法和层次遍历算法进行二叉树问题的求解。
问题描述
编写一个程序 exp7-6.cpp 实现以下功能
(1) 输出二叉树b的结点个数。
(2) 输出二叉树b的叶子结点个数。
(3) 求二叉树 b中指定结点值(假设所有结点值不同)的结点的层次
(4) 利用层次遍历求二叉树 b 的宽度。
数据结构及算法设计
二叉树是一种非线性的数据结构,它由节点和连接节点的边组成。每个节点都有一个值,通常称为键或关键字。二叉树可以是空的,也可以有一个根节点和两个子节点(左子树和右子树)。
1. 输出二叉树b的结点个数:可以使用递归的方法遍历整个二叉树,每遍历一个节点就将计数器加1,直到遍历完整个二叉树。
2. 输出二叉树b的叶子结点个数:同样使用递归的方法遍历整个二叉树,当遇到叶子节点时(即左右子树都为空),将计数器加1。
3. 求二叉树 b 中指定结点值的结点的层次:首先找到指定值的节点,然后从根节点开始进行层次遍历,记录遍历到该节点的层数。
4. 利用层次遍历求二叉树 b 的宽度:使用队列来实现层次遍历,每次遍历一层时,记录当前层的节点数,最后取最大值作为二叉树的宽度。
源程序
//二叉树的基本运算算法
#include <stdio.h>
#include <malloc.h>
#define MaxSize 100
typedef char ElemType;
typedef struct node
{
ElemType data; //数据元素
struct node *lchild; //指向左孩子结点
struct node *rchild; //指向右孩子结点
} BTNode;
void CreateBTree(BTNode * &b,char *str) //创建二叉树
{
BTNode *St[MaxSize],*p=NULL;
int top=-1,k,j=0;
char ch;
b=NULL; //建立的二叉树初始时为空
ch=str[j];
while (ch!='\0') //str未扫描完时循环
{
switch(ch)
{
case '(':top++;St[top]=p;k=1; break; //为左孩子结点
case ')':top--;break;
case ',':k=2; break; //为孩子结点右结点
default:p=(BTNode *)malloc(sizeof(BTNode));
p->data=ch;p->lchild=p->rchild=NULL;
if (b==NULL) //*p为二叉树的根结点
b=p;
else //已建立二叉树根结点
{
switch(k)
{
case 1:St[top]->lchild=p;break;
case 2:St[top]->rchild=p;break;
}
}
}
j++;
ch=str[j];
}
}
void DestroyBTree(BTNode *&b) //销毁二叉树
{ if (b!=NULL)
{ DestroyBTree(b->lchild);
DestroyBTree(b->rchild);
free(b);
}
}
BTNode *FindNode(BTNode *b,ElemType x) //查找值为x的结点
{
BTNode *p;
if (b==NULL)
return NULL;
else if (b->data==x)
return b;
else
{
p=FindNode(b->lchild,x);
if (p!=NULL)
return p;
else
return FindNode(b->rchild,x);
}
}
BTNode *LchildNode(BTNode *p)
{
return p->lchild;
}
BTNode *RchildNode(BTNode *p)
{
return p->rchild;
}
int BTHeight(BTNode *b) //求二叉树b的高度
{
int lchildh,rchildh;
if (b==NULL) return(0); //空树的高度为0
else
{
lchildh=BTHeight(b->lchild); //求左子树的高度为lchildh
rchildh=BTHeight(b->rchild); //求右子树的高度为rchildh
return (lchildh>rchildh)? (lchildh+1):(rchildh+1);
}
}
void DispBTree(BTNode *b) //以括号表示法输出二叉树
{
if (b!=NULL)
{ printf("%c",b->data);
if (b->lchild!=NULL || b->rchild!=NULL)
{ printf("("); //有孩子结点时才输出(
DispBTree(b->lchild); //递归处理左子树
if (b->rchild!=NULL) printf(","); //有右孩子结点时才输出,
DispBTree(b->rchild); //递归处理右子树
printf(")"); //有孩子结点时才输出)
}
}
}
int Nodes(BTNode *b) //求二叉树b的结点个数
{
int num1,num2;
if (b==NULL) // 如果当前节点为空,返回0
return 0;
else if (b->lchild==NULL && b->rchild==NULL) // 如果当前节点是叶子节点,返回1
return 1;
else // 否则,递归计算左子树和右子树的结点个数,并加上当前节点(即1)
{
num1=Nodes(b->lchild); // 计算左子树的结点个数
num2=Nodes(b->rchild); // 计算右子树的结点个数
return (num1+num2+1); // 返回总的结点个数
}
}
int LeafNodes(BTNode *b) //求二叉树b的叶子结点个数
{
int num1,num2;
if (b==NULL) // 如果当前节点为空,返回0
return 0;
else if (b->lchild==NULL && b->rchild==NULL) // 如果当前节点是叶子节点,返回1
return 1;
else // 否则,递归计算左子树和右子树的叶子结点个数,并加上当前节点(即1)
{
num1=LeafNodes(b->lchild); // 计算左子树的叶子结点个数
num2=LeafNodes(b->rchild); // 计算右子树的叶子结点个数
return (num1+num2); // 返回总的叶子结点个数
}
}
int Level(BTNode *b,ElemType x,int h) //求二叉树b中结点值为x的结点的层次
{ int l;
if (b==NULL) // 如果当前节点为空,返回0
return(0);
else if (b->data==x) // 如果当前节点的值等于x,返回当前层次h
return(h);
else // 否则,递归在左子树中查找,如果未找到,再在右子树中查找
{ l=Level(b->lchild,x,h+1); //在左子树中查找
if (l!=0) // 如果找到了,返回结果
return(l);
else //在左子树中未找到,再在右子树中查找
return(Level(b->rchild,x,h+1));
}
}
int BTWidth(BTNode *b) //求二叉树b的宽度
{
struct
{
int lno; //结点的层次
BTNode *p; //结点指针
} Qu[MaxSize]; //定义非环形队列
int front,rear; //定义队首和队尾指针
int lnum,max,i,n;
front=rear=0; //置队列为空队
if (b!=NULL)
{
rear++;
Qu[rear].p=b; //根结点进队
Qu[rear].lno=1; //根结点的层次为1
while (rear!=front) //队不空时循环
{
front++;
b=Qu[front].p; //出队结点p
lnum=Qu[front].lno;
if (b->lchild!=NULL) //有左孩子,将其进队
{
rear++;
Qu[rear].p=b->lchild;
Qu[rear].lno=lnum+1;
}
if (b->rchild!=NULL) //有右孩子,将其进队
{
rear++;
Qu[rear].p=b->rchild;
Qu[rear].lno=lnum+1;
}
}
max=0;lnum=1;i=1; //max存放宽度
while (i<=rear)
{
n=0;
while (i<=rear && Qu[i].lno==lnum) //i扫描队列中所有结点
{
n++; //n累计一层中的结点个数
i++;
}
lnum=Qu[i].lno;
if (n>max) max=n;
}
return max;
}
else return 0;
}
int main()
{
ElemType x='K';
BTNode *b,*p,*lp,*rp;
CreateBTree(b,"A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))");
printf("输出二叉树b:");DispBTree(b);printf("\n");
printf("二叉树b的结点个数:%d\n",Nodes(b));
printf("二叉树b的叶子结点个数:%d\n",LeafNodes(b));
printf("二叉树b中值为%c结点的层次:%d\n",x,Level(b,x,1));
printf("二叉树b的宽度:%d\n",BTWidth(b));
DestroyBTree(b);
return 1;
}
数据及结果分析
在实验中,通过构建二叉树并使用不同的遍历算法,得到了二叉树的结点个数、叶子结点个数、指定结点的层次和二叉树的宽度。
体会
通过实验求二叉树中的结点个数、叶子结点个数以及某结点的层次和二叉树的宽度,可以帮助我们更好地理解二叉树的性质和操作方法。
1. 理解二叉树的基本概念:在进行实验之前,我们需要充分理解二叉树的基本概念,如根节点、叶子节点、度、深度等。这些概念是求解问题的基础,只有对它们有了清晰的认识,才能更好地进行实验。
2. 掌握二叉树的基本操作:实验中涉及到的操作主要包括创建二叉树、遍历二叉树、查找结点等。我们需要熟练掌握这些基本操作,以便在实验中使用。
3. 递归思想的运用:在求解二叉树中的结点个数、叶子结点个数以及某结点的层次时,我们通常会使用递归思想。通过递归调用函数,可以简化代码实现,提高代码的可读性。
4. 注意边界条件的处理:在进行实验时,我们需要注意处理一些边界条件,如空树、只有一个结点的树等。这些特殊情况需要单独处理,不能简单地套用公式或算法。
5. 二叉树宽度的计算:在计算二叉树的宽度时,我们需要找到最宽的一层。这可以通过遍历二叉树的所有层来实现。在遍历过程中,我们需要记录每一层的最大宽度,最后得到的结果即为所求的二叉树宽度。
6. 结果输出与分析:实验完成后,我们需要对结果进行输出和分析。通过对结果的分析,我们可以了解二叉树的一些性质,如高度、结点个数与叶子结点个数的关系等。这有助于我们更深入地理解二叉树。
总之,通过做这个实验,我不仅巩固了二叉树的基本知识,还提高了自己的编程能力和分析问题的能力。在今后的学习中,我将继续努力,探索更多关于数据结构的知识。