数据结构实验报告(八)

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度结点的个数、返回前中后序的首点和尾点,通过本次实验,出现了一些问题,但是在老师的耐心指导下,一个个问题得到了解决,同时,自己的对代码的调试能力和理解能力也得到了提高。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值