实 验 报 告
实验名称 二叉树相关操作的实现
一、实验目的和要求
1.理解二叉树二叉链表的存储结构。
2.以二叉树二叉链表的存储结构,实现二叉树的基本操作。
3.掌握二叉树二叉链表存储结构下,相关递归算法的实现。
二、实验内容:
(一)完成二叉树二叉链表结构的定义
(二)实现二叉链表创建二叉树,并实现先序、中序和后序遍历算法。
(三)实现二叉树求结点个数,求树的高度,求叶子结点数、交换二叉树左右子树的算法。
三、实验环境(实验设备)
Visual Studio等
Visual Studio 2019
实 验 报 告
四、实验过程描述与结果分析
代码实现:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
//二叉树的结点类型;
typedef struct tree
{
char ch;
struct tree* lchild;
struct tree* rchild;
}BitTree;
//创建树;
BitTree* CreateTree()
{
BitTree* bt;
char str;
scanf("%c", &str);
if (str == '#')
return NULL;
else
{
bt = (BitTree*)malloc(sizeof(BitTree));
bt->ch = str;
bt->lchild = CreateTree();
bt->rchild = CreateTree();
return bt;
}
}
//交换左右二叉树;
void Exchange(BitTree* bt)
{
if (bt->lchild == NULL && bt->rchild == NULL)
;
else //三种情况,1.都不为空,2.左为空,3.右为空;
{
//交换左右子树;
BitTree* temp = bt->lchild;
bt->lchild = bt->rchild;
bt->rchild = temp;
}
//如果交换后的这个结点左子树不为空,则继续向下寻找可以交换的结点;
if (bt->lchild)
Exchange(bt->lchild);
if (bt->rchild)
Exchange(bt->rchild);
}
//先序输出交换后的二叉树;
void PreOrder(BitTree* bt)
{
if (bt != NULL)
{
printf("%c ", bt->ch);
PreOrder(bt->lchild);
PreOrder(bt->rchild);
}
}
//中序输出交换后的二叉树;
void InOrder(BitTree* bt)
{
if (bt != NULL)
{
InOrder(bt->lchild);
printf("%c ", bt->ch);
InOrder(bt->rchild);
}
}
//后序输出交换后的二叉树;
void PostOrder(BitTree* bt)
{
if (bt != NULL)
{
PostOrder(bt->lchild);
PostOrder(bt->rchild);
printf("%c ", bt->ch);
}
}
//二叉树求叶子数
int leaves(BitTree* bt)
{
if (bt == NULL)
{
return 0;
}
else if (bt->lchild == NULL && bt->rchild == NULL)
{
return 1;
}
else
{
return leaves(bt->lchild) + leaves(bt->rchild);
}
}
//求树深度的递归算法
int deep(BitTree* bt)
{
int lnum, rnum;
if (bt == NULL)
{
return 0;
}
else
{
lnum = deep(bt->lchild);
rnum = deep(bt->rchild);
return (lnum > rnum ? lnum : rnum) + 1;
}
}
//求二叉树中以某值为根的子树深度(递归)
void x_deep(BitTree* bt, char x)
{
int lnum = 0, rnum = 0;
if (bt == NULL)
{
printf("空树深度为0\n");
}
if (bt->ch == x)
{
printf("%d\n", deep(bt));
}
else
{
if (bt->lchild)
{
x_deep(bt->lchild, x);
}
if (bt->rchild)
{
x_deep(bt->rchild, x);
}
}
}
//二叉树求指定结点的层数
int floor(BitTree* bt, char x)
{
int lnum, rnum, fnum;
if (bt == NULL)
{
fnum = 0;
}
else if (bt->ch == x)
{
fnum = 1;
}
else
{
lnum = floor(bt->lchild, x);
rnum = floor(bt->rchild, x);
if (lnum == 0 && rnum == 0)//查找失败
{
/*printf("查找结束\n");*/
fnum = 0;
}
else
{
fnum = ((lnum > rnum) ? lnum : rnum) + 1;
}
}
return fnum;
}
//统计数中结点个数
int nodenum(BitTree* bt)
{
if (bt == NULL)
{
return 0;
}
else
{
return(nodenum(bt->lchild) + nodenum(bt->rchild)) + 1;
}
}
int main()
{
BitTree* bt;
printf("请以先序序列输入需要创建的二叉树:\n");
bt = CreateTree();
int temp;
while (1)
{
printf("<---------------------------二叉树综合实验----------------------------->\n");
printf("<---------------------------1.二叉树先序遍历--------------------------->\n");
printf("<---------------------------2.二叉树中序遍历--------------------------->\n");
printf("<---------------------------3.二叉树后序遍历--------------------------->\n");
printf("<---------------------------4.求二叉树深度(递归----------------------->\n");
printf("<---------------------------5.二叉树求叶子数--------------------------->\n");
printf("<---------------------------6.二叉树求结点数--------------------------->\n");
printf("<---------------------------7.交换左右子树----------------------------->\n");
printf("<---------------------------0.退出exit--------------------------------->\n");
printf("<---------------------------------------------------------------------->\n");
printf("输入你的选项:");
scanf_s("%d", &temp);
if (temp == 0)
{
printf("程序退出》》》");
break;
}
switch (temp)
{
case 1:
printf("二叉树前序遍历(递归)为:\n");
PreOrder(bt);
printf("\n");
break;
case 2:
printf("二叉树中序遍历(递归)为:\n");
InOrder(bt);
printf("\n");
break;
case 3:
printf("二叉树后序遍历(递归)为:\n");
PostOrder(bt);
printf("\n");
break;
case 4:
printf("二叉树的深度为%d层\n", deep(bt));
break;
case 5:
printf("二叉树中含有%d个叶子结点\n", leaves(bt));
break;
case 6:
printf("二叉树共有%d个结点\n", nodenum(bt));
break;
case 7:
printf("交换左右子树\n");
Exchange(bt);
break;
default:
printf("error");
break;
}
}
return 0;
}
运行结果:一开始用前序遍历创建二叉树 然后分别前序 中序 后序遍历输出 再输出树得深度 叶子树
结点数 然后交换左右子树 最后前序遍历检验 按0结束程序
五、实验小结(包括问题和解决方法、心得体会、意见与建议等)
- 树本身是一种非线性结构,二叉树基本操作的算法中基本上都用到了递归的思想
- 本次实验是对之前所学栈,队列,递归的具体实现及综合应用,熟练掌握栈先进后出,队列先进先出的特性可以解决很多类似问题。、
- 利用栈实现先序,中序遍历时,需要注意在定义栈的存储结构时,其头指针,尾指针的数据类型为指向根结点的指针的指针,队列实现层序遍历同理;
- 因为C语言中的scanf等一些函数是不安全的函数,所以在用使用Visual Studio 2019的时候会报错,这个则需要添加一个申明加入#define _CRT_SECURE_NO_WARNINGS就可以编译成功了
- 真正自己动手写代码的时候,一定要有耐心和细心,不细心可能一个错误能让你让浪费更多的时间去排除错误,没有耐心你就解决不了问题。