1.实验目的
1、掌握二叉树的动态存储结构及表示算法
2、掌握二叉树的前序、中序、后序遍历的递归和非递归算法
3、运用二叉树的3种遍历算法求解基于二叉树的相关问题
2.实验内容
1、二叉树的建立
2、二叉树的前中后序遍历及层次遍历
3、查找结点,返回结点的指针或双亲
4、统计n度结点的个数
5、返回前中后序的首点和尾点
3.设计思路
类似于树的创建,只不过分为左子树和右子树,前中后序遍历和树的也大致相同,层次遍历要用到队列,计算树的高度的策略是子树的最大高度+1,统计不同度数结点的个数就要先判断根结点是几度结点,再去看左子树和右子树该度数结点的个数。查找算法先判断树是否为空,若为空,返回NULL,在判断如果根是要找的,返回根,否则先到左边找,返回左边找的值,再到右边找,返回右边找到的值。树不空,前序首点即根,前序尾点即最右叶子,后序首点即最左叶子,后序尾点即根。
4.关键代码
#include <stdio.h>
#include <stdlib.h>
#define MAX 20
typedef struct k {
char data;
struct k* left, * right;
}btree;
typedef struct {
btree* data[MAX];//后面需要使用到出队元素的孩子,所有存储的只能是tree*类型
int f, r;//f是队首指针,r是队尾指针
}queue;
typedef struct {
btree* a[100];
int top;
}stack;
btree* Create() {//二叉树的建立,类似于树的建立
btree* t;
char c = getchar();
if (c == '#') return NULL;//输入#号代表空
t = (btree*)malloc(sizeof(btree));//造根
t->data = c;//给根赋值
t->left = Create();//造一棵树给t的左孩子t->left
t->right = Create();//造一棵树给t的右孩子t->right
return t;//最后返回t
}
//队列的操作
void init1(queue* q) { q->f = 0; q->r = 0; }//初始化队列
int isEmpty1(queue* q)//判空
{
if (q->f == q->r) return 1;//为空返回1,否则返回0
else return 0;
}
void enQueue(queue* q, btree* x) { q->data[q->r] = x; q->r = (q->r + 1) % MAX; }//入队,从尾入
btree* outQueue(queue* q)//出队,从头出
{
btree* x;
x = q->data[q->f];//将头部的值标记出来
q->f = (q->f + 1) % MAX;//防止溢出,所以要对MAX求余
return x;
}
//栈的操作
void init2(stack* s) //初始化栈
{
s->top = 0;
}
int isEmpty2(stack* s) //判断栈是否为空
{
return (s->top == 0) ? 1 : 0;
}
void push(stack* s, btree* x)//入栈
{
s->a[s->top] = x; s->top++;
}
btree* pop(stack* s) //出栈
{
s->top--; return s->a[s->top];
}
btree* top(stack* s) //返回栈顶元素,但不出栈
{
return s->a[s->top - 1];
}
void pre(btree* t) {//前序遍历
if (t == NULL) return;
printf("%c ", t->data);//先根
pre(t->left);//后子树
pre(t->right);
}//Images\background.png
void in(btree* t) {//中序遍历
if (t == NULL) return;
in(t->left);
printf("%c ", t->data);
in(t->right);
}
void post(btree* t) {//后序遍历
if (t == NULL) return;
post(t->left);//先子树
post(t->right);
printf("%c ", t->data);//后根
}
//void level(btree* t) {//层次遍历
// btree* p;
// if (t == NULL) return;
// queue q; init1(&q); //创建并初始化队列
// enQueue(&q, t); //根入队
// while (isEmpty1(&q) == 0) //当队列不为空时
// {
// p = outQueue(&q); //p=出队元素
// printf("%c ", p->data); //访问p
// if (p->left != NULL)
// enQueue(&q, p->left); //p->left入队
// if (p->right != NULL)
// enQueue(&q, p->right); //p->right入队
// }
//}
void level(btree* t) {
btree* p; queue q;
if (t == NULL) return;
init1(&q);
enQueue(&q, t);//根入队
while (isEmpty1(&q) != 1)
{
p = outQueue(&q);
printf("%c ", p->data);
if (p->left != NULL)
enQueue(&q, p->left);
if (p->right != NULL)
enQueue(&q, p->right);
}
}
btree* findX(btree* t, char x) {//基于前序遍历查找
if (t == NULL) return NULL;//如果没有元素返回空
if (t->data == x) return t;//如果根就是要找的,返回根;
if (findX(t->left, x) != NULL)//先找左子树,如果找到则返回找到的结果
return findX(t->left, x);
//走至此处说明左子树中没有找到
return findX(t->right, x); //以右子树结果为结果:无论是否找到
}
btree* locate(btree* t, char x) {
if (t == NULL) return NULL;
if ((t->left != NULL && t->left->data == x) || (t->right != NULL && t->right->data == x))
return t;
if (locate(t->left, x) != NULL)
return locate(t->left, x);
return locate(t->right, x);
}
int count_0(btree* t) {
if (t == NULL) return 0;
if (t->left == NULL && t->right == NULL)
return 1;
return count_0(t->left) + count_0(t->right);
}
int count_1(btree* t) {
int c = 0;
if (t == NULL) return 0;
if ((t->left != NULL && t->right == NULL) || (t->left == NULL && t->right != NULL))
c = 1;
return count_1(t->left) + count_1(t->right);
}
int count_2(btree* t) {//统计2度结点个数
int c = 0;
if (t == NULL)
return 0;
if ((t->left != NULL) && (t->right != NULL))
c = 1;
return count_2(t->left) + count_2(t->right) + c;
}
int high(btree* t) {//计算树的高度
int max, maxC1, maxC2;
max = 0; maxC1 = 0; maxC2 = 0;
if (t == NULL) return 0;//如果t为空,说明树高为0;
//策略:最高子树的树高+1
maxC1 = high(t->left);//即左边子树的树高
maxC2 = high(t->right);//即右边子树的树高
if (maxC1 < maxC2) max = maxC2;
else { max = maxC1; }
//max即子树中树高最高的值
return max + 1;//还要加上根的高度
}
int depth(btree* t, char x) {
if (t == NULL) return 0;
if (t->data == x) return 1;
if (depth(t->left, x) > 0)
return depth(t->left, x);
if (depth(t->right, x) > 0)
return depth(t->right, x);
return 0;
}
void convert(btree* t) {//二叉树的左右子树互换
btree* temp;
if (t == NULL) return;
temp = t->left; t->left = t->right; t->right = temp;
convert(t->left);
convert(t->right);
}
void preKN(btree* t) //非递归 将二叉树以k叉树形式前序遍历
{
stack s;
init2(&s);
while (t != NULL || isEmpty2(&s) != 1)//当t不空或栈不空
{
if (t != NULL)//如果t不空,则表示左子树还没打印完
{
printf("%c", t->data);//打印
push(&s, t);//进栈保留回溯点
t = t->left;
}
else //如果t空,栈不空
{
t = pop(&s);//出栈找到右子树
t = t->right;
}
}
}
btree* midfindX(btree* t, char x) //中序非递归遍历,查找值为x的元素
{
stack s;
init2(&s);
while (t != NULL || isEmpty2(&s) != 1)//当t不空或栈不空
{
if (t != NULL)//如果t不空,则表示左子树还没打印完
{
push(&s, t);//进栈保留回溯点
t = t->left;
}
else//如果t空,栈不空
{
t = pop(&s);//出栈找到右子树
if (t->data == x)
return t;
t = t->right;
}
}
return NULL;//出循环表示没找到
}
btree* InFirstNode(btree* t) {
btree* p;
if (t == NULL) return NULL;
p = t;
while (p->left != NULL)
p = p->left;
return p;
}
btree* InLastNode(btree* t) {
btree* p;
if (t == NULL) return NULL;
p = t;
while (p->right != NULL)
{
p = p->right;
}
return p;
}
btree* preFirstNode(btree* t) {//返回前序首点
if (t == NULL) return NULL;
return t;//树不空,前序首点即根
}
btree* preLastNode(btree* t) {//返回前序尾点,前序尾点即最右叶子
btree* p;
if (t == NULL) return NULL;
p = t;
while (p->left != NULL || p->right != NULL)//当两个都为空时说明是叶子
if (p->right != NULL) p = p->right;//左右都不为空则先访问右子树
else
p = p->left;
return p;
}
btree* postFirstNode(btree* t) {//返回后序首点,后序首点即最左叶子
btree* p;
if (t == NULL) return NULL;
p = t;
while (p->left != NULL || p->right != NULL)//当两个都为空时说明是叶子
if (p->left != NULL) p = p->left;//左右都不为空则先访问左子树
else
p = p->right;
return p;
}
btree* postLastNode(btree* t) {//返回后序尾点,后序尾点即根
if (t == NULL) return NULL;
return t;
}
int main()
{
btree* t, * p, * r;
int x, y;
printf("请输入结点,#代表空");
t = Create();
printf(" pre="); pre(t);
printf("\n in="); in(t);
printf("\npost="); post(t);
printf("\n层次遍历结果为:\n"); level(t);
printf("\npreKN="); preKN(t);
printf("\n中序非递归查找结点A,结果为:");
p = midfindX(t, 'A');
if (p == NULL) printf("NULL "); else printf("%c ", p->data);
printf("\n找结点A、C、Z,结果为:");
p = findX(t, 'A');
if (p == NULL) printf("NULL "); else printf("%c ", p->data);
p = findX(t, 'C');
if (p == NULL) printf("NULL "); else printf("%c ", p->data);
p = findX(t, 'Z');
if (p == NULL) printf("NULL "); else printf("%c ", p->data);
printf("\nB的双亲为:");
p = locate(t, 'B'); printf("%c ", p->data);
printf("\nC的双亲为:");
p = locate(t, 'C'); printf("%c ", p->data);
printf("\n0度结点的个数为:"); x = count_0(t); printf("%d ", x);
printf("\n1度结点的个数为:"); x = count_1(t); printf("%d ", x);
printf("\n2度结点的个数为:"); x = count_2(t); printf("%d ", x);
printf("\n树高为:"); y = high(t); printf("%d", y);
printf("\n左右子树互换:");
convert(t); pre(t);
printf("\n中序首点为:");
r = InFirstNode(t);//返回中序首点
printf("%c ", r->data);
printf("\n中序尾点为:");
r = InLastNode(t);//返回中序尾点
printf("%c ", r->data);
printf("\n前序首点为:");
r = preFirstNode(t);//返回前序首点
printf("%c ", r->data);
printf("\n前序尾点为:");
r = preLastNode(t);//返回前序尾点
printf("%c ", r->data);
printf("\n后序首点为:");
r = postFirstNode(t);//返回后序首点
printf("%c ", r->data);
printf("\n后序尾点为:");
r = postLastNode(t);//返回后序尾点
printf("%c ", r->data);
}
5.运行结果
6.实验总结(含心得体会)
通过本次实验,我们学习了二叉树的建立、二叉树的前中后序遍历及层次遍历、查找结点,返回结点的指针或双亲、统计n度结点的个数、返回前中后序的首点和尾点,通过本次实验,出现了一些问题,但是在老师的耐心指导下,一个个问题得到了解决,同时,自己的对代码的调试能力和理解能力也得到了提高。