数据结构二叉树创建及例题(上)

news2024/11/17 13:32:57

今天就带领大家来到树的世界,树无论是在考试上还是实际学习方面都是比较重点的,大家在这块知识要花时间搞懂.

文章目录

前言

一、树的二叉链表定义

二、二叉树三种遍历方式(递归方式)

1.先序遍历方式(根左右)

2.中序遍历方式(左根右)

 3.后序遍历方式(左右根)

三、二叉树的层次遍历方式(采用数组模拟队列)

四、已知一颗二叉树的先序遍历序列和中序遍历分别存在两个一维数组中试编写算法建立该二叉树的二叉链表

五、已知一颗二叉树的后序遍历序列和中序遍历分别存在两个一维数组中试编写算法建立该二叉树的二叉链表

六、已知一颗二叉树的层序遍历序列和中序遍历分别存在两个一维数组中试编写算法建立该二叉树的二叉链表

七、二叉树的基本操作

1.求一颗二叉树的节点个数

2.求一棵二叉树的叶子节点个数

 3.求一棵二叉树中度为1的节点个数

 4.查找二叉树中值为x的节点,若存在则返回存储位置,不存在则返回空值

5.求一棵二叉树的高度

6.求一棵二叉树中值为x的节点作为根节点的子树的深度.

7.交换一棵二叉树的左右子树

8.判断两棵树是否相似(长得一样)

9.判断一棵树是否为完全二叉树

10.设计算法利用叶子节点中的的空指针域将所有的叶子节点,链接成一个带头节点的双链表

 11.一个包含二元运算的算数表达式以二叉链表形式存在在二叉树T中,设计算法求解算数表达式

 12.求一棵二叉树的最大宽度

八、总代码与测试结果


前言

树这块的内容比较多,包括树的一些基本的定义以及一些计算,后面还有完全二叉树,排序二叉树,平衡二叉树,这些树可能在定义上不一样但思想都是一样的,平衡二叉树在考试中主要考的是操作,代码实现的话实际上是比较困难的,但在面试时可能会考到,再后面树以及森林等等,后续都会讲到.这节主要是树的基本操作.

一、树的二叉链表定义

typedef char Elemtype;
//树的数据结构二叉链表
typedef struct BiTNode {
	Elemtype data;
	struct BiTNode* lchild;
	struct BiTNode* rchild;
}BiTNode,*BiTree;

二、二叉树三种遍历方式(递归方式)

1.先序遍历方式(根左右)

//二叉树的先序遍历(根左右)
void preorderTraverse(BiTree T) {
	if (T != NULL) {
		printf("%c ", T->data);//先访问根节点
		preorderTraverse(T->lchild);//遍历左子树
		preorderTraverse(T->rchild);//遍历右子树
	}
}

2.中序遍历方式(左根右)

//二叉树的中序遍历(左根右)
void inorderTraverse(BiTree T) {
	if (T != NULL) {
		inorderTraverse(T->lchild);
		printf("%c ", T->data);
		inorderTraverse(T->rchild);
	}
}

 3.后序遍历方式(左右根)

//二叉树的后序遍历(左右根)
void postorderTraverse(BiTree T) {
	if (T != NULL) {
		postorderTraverse(T->lchild);
		postorderTraverse(T->rchild);
		printf("%c ", T->data);
	}
}

三、二叉树的层次遍历方式(采用数组模拟队列)

//二叉树的层次遍历算法
void levelTraverse(BiTree T) {//使用数组模拟队列注意分配长度
	BiTNode* Queue[80] = {NULL};//这里就分配了40注意
	int front = 0;
	int rear = 0;
	if (T != NULL) {
		Queue[++rear] = T;//根节点入队
	}
	while (front != rear) {
		BiTNode* p = Queue[++front];
		printf("%c ", p->data);
		if (p!=NULL && p->lchild != NULL) {
			Queue[++rear] = p->lchild;
		}
		if (p != NULL && p->rchild != NULL) {
			Queue[++rear] = p->rchild;
		}
	}
}

层次遍历序列为:ABCDEFG

算法思想:首先创建一个队列,将根节点先入队列,如果队列不为空循环操作

1.出队

2.有孩子将孩子入队

直到队列为空,遍历完成.

四、已知一颗二叉树的先序遍历序列和中序遍历分别存在两个一维数组中试编写算法建立该二叉树的二叉链表

这题也是建立二叉树的基本算法,自命题考试的时候容易考.

//已知一颗二叉树的先序遍历序列和中序遍历分别存在两个一维数组中试编写算法建立该二叉树的二叉链表
BiTNode* creatBitree1(char pre[], char in[], int l1, int h1, int l2, int h2) {
	//l代表第一个元素的位置,h代表最后一个元素的位置
	if (l1 > h1) {
		return NULL;
	}
	BiTNode* pNode = (BiTNode*)malloc(sizeof(BiTNode));
	assert(pNode);
	pNode->data = pre[l1];//在中序遍历中寻找根节点所在位置
	int p = l2;
	while (p <= h2) {
		if (in[p] == pre[l1]) {
			break;
		}
		p++;
	}
	//p为在数组中下标a减下标b表示a到b中有几个元素算a不算b
	pNode->lchild = creatBitree1(pre, in, l1 + 1, l1 + p - l2, l2, p - 1);
	pNode->rchild = creatBitree1(pre, in, l1 + p - l2 + 1, h1, p + 1, h2);
	return pNode;
}

算法思想:使用先序和中序序列构建二叉树,首先我们知道先序序列的第一个节点是跟节点,获得根节点后在中序遍历序列中找到根节点所在位置,那么就能确定左孩子和右孩子序列这样我们在根据先序遍历序列就又能递归的将树建立起来.

五、已知一颗二叉树的后序遍历序列和中序遍历分别存在两个一维数组中试编写算法建立该二叉树的二叉链表

//已知一颗二叉树的后序遍历序列和中序遍历分别存在两个一维数组中试编写算法建立该二叉树的二叉链表
BiTNode* creatBitree2(char post[], char in[], int l1, int h1, int l2, int h2) {
	if (l1 > h1) {
		return NULL;
	}
	BiTNode* pNode = (BiTNode*)malloc(sizeof(BiTNode));
	assert(pNode);
	pNode->data = post[h1];
	int p = l2;
	while (l2 <= h2) {
		if (in[p] == post[h1]) {
			break;
		}
		p++;
	}
	pNode->lchild = creatBitree2(post, in, l1, l1 + p - l2 - 1, l2, p - 1);
	pNode->rchild = creatBitree2(post, in, l1 + p - l2, h1 - 1, p + 1, h2);
	return pNode;
}

还是根据上图数据.

算法思想;使用后续遍历与中序遍历构建二叉树,首先我们知道后续遍历的最后的一个节点为根节点,这样我们在中序遍历中找到根节点所在位置,那么左子树右子树序列就知道了,再根据后续遍历的最后一个节点为根节点,就能够递归的建立二叉树了.

六、已知一颗二叉树的层序遍历序列和中序遍历分别存在两个一维数组中试编写算法建立该二叉树的二叉链表

//已知一颗二叉树的层序遍历序列和中序遍历分别存在两个一维数组中试编写算法建立该二叉树的二叉链表
BiTNode* creatBitree3(char level[], char in[], int l1, int h1, int l2, int h2) {
	if (l1 > h1) {
		return NULL;
	}
	BiTNode* pNode = (BiTNode*)malloc(sizeof(BiTNode));
	assert(pNode);
	pNode->data = level[l1];
	int p = l2;
	while (p <= h2) {
		if (in[p] == level[l1]) {
			break;
		}
		p++;
	}
	//寻找左子树和右子树在层次遍历中的顺序
	char lelflevel[5];
	char rightlevel[5];
	int lelflength = 0;
	int rightlength = 0;
	//左子树
	for (int i = l1 + 1; i <= h1; i++) {
		for (int j = l2; j < p; j++) {
			if (level[i] == in[j]) {
				lelflevel[lelflength] = level[i];
				lelflength++;
			}
		}
	}
	//右子树
	for (int i = l1 + 1; i <= h1; i++) {
		for (int j = p + 1; j <= h2; j++) {
			if (level[i] == in[j]) {
				rightlevel[rightlength] = level[i];
				rightlength++;
			}
		}
	}
	pNode->lchild = creatBitree3(lelflevel, in, 0, lelflength - 1, l2, p - 1);
	pNode->rchild = creatBitree3(rightlevel, in, 0, rightlength - 1, p + 1, h2);
	return pNode;
}

算法思想:使用层次遍历与中序遍历建立二叉树,首先我们知道先序遍历第一个节点为根节点,这样我们在中序遍历序列中找到根节点所在位置我们就能知道左子树和右子树的序列,但返回层次遍历序列在寻找左右子树序列时,与前两道题不同,由于层次遍历序列只能反映大概位置并不能直接反应左子树和右子树序列,所以我们需要寻找序列,在层次遍历中按顺序判断,该元素是否在左子树序列(或右子树序列)在就加入左子树(或右子树)层次遍历数组中这样我们就得到了,左子树和右子树的层次遍历序列,再根据中序遍历,这样就又能递归的建立二叉树了.

注意:这三种构建二叉树的方式不要先看代码,先不要研究这是怎么来的,先自己根据我所给的二叉树手推一遍,我愿成为上面二叉树的例子,是搞懂这几个算法之神.

七、二叉树的基本操作

1.求一颗二叉树的节点个数

//例1:求一颗二叉树的节点个数
int nodesInBitree(BiTree T) {//递归实现,采用先序遍历算法思想
	if (T == NULL) {
		return 0;
	}
	return 1 + nodesInBitree(T->lchild) + nodesInBitree(T->rchild);
}

2.求一棵二叉树的叶子节点个数

//例2:求一棵二叉树的叶子节点个数
int leafsInBitree(BiTree T) {//先序遍历的思想
	if (T == NULL) {
		return 0;
	}
	else if (T->lchild == NULL && T->rchild == NULL) {//叶子姐姐
		return 1;
	}
	return leafsInBitree(T->lchild) + leafsInBitree(T->rchild);
}

 3.求一棵二叉树中度为1的节点个数

//例3:求一棵二叉树中度为1的节点个数
int getsinglenodes(BiTree T) {//先序遍历的思想
	if (T == NULL) {
		return 0;
	}
	else if (T->lchild != NULL && T->rchild == NULL) {//左子树不为空继续搜索
		return 1 + getsinglenodes(T->lchild);
	}
	else if (T->lchild == NULL && T->rchild != NULL) {//右子树不为空继续搜索
		return 1 + getsinglenodes(T->rchild);
	}
	else {
		return getsinglenodes(T->lchild) + getsinglenodes(T->rchild);
	}
}

 4.查找二叉树中值为x的节点,若存在则返回存储位置,不存在则返回空值

//例4:查找二叉树中值为x的节点,若存在则返回存储位置,不存在则返回空值
BiTNode* seekElemNode(BiTree T,char x) {
	if (T == NULL) {
		return NULL;
	}
	else if (x == T->data) {
		return T;
	}
	else {
		BiTNode* tmp = seekElemNode(T->lchild,x);//搜左子树
		if (tmp != NULL) {
			return tmp;
		}
		else {//左子树没有
			return seekElemNode(T->rchild,x);//搜右子树
		}
	}
}

5.求一棵二叉树的高度

这个算法一定要熟悉,单独考它不多但它经常处理一些复杂算法中起到作用

//例5:求一棵二叉树的高度
int getBitreehigh(BiTree T) {//递归思想
	if (T == NULL) {
		return 0;
	}
	else {
		int lelfhigh = getBitreehigh(T->lchild);
		int righthigh = getBitreehigh(T->rchild);
		return lelfhigh > righthigh ? lelfhigh + 1 : righthigh + 1;
	}
}

6.求一棵二叉树中值为x的节点作为根节点的子树的深度.

算法思想就是例4和例5结合,先找到值为x的节点,在根据此节点求二叉树的高度

7.交换一棵二叉树的左右子树

//例7:交换一棵二叉树的左右子树
void switchLRchild(BiTree T) {
	if (T != NULL) {
		BiTNode* tmp = T->lchild;
		T->lchild = T->rchild;
		T->rchild = tmp;
		switchLRchild(T->lchild);
		switchLRchild(T->rchild);
	}
}

8.判断两棵树是否相似(长得一样)

//例8:判断两棵树是否相似(长得一样)
bool issimilarBitree(BiTree T1, BiTree T2) {
	if (T1 == NULL && T2 == NULL) {
		return true;
	}
	else if (T1 == NULL && T2 != NULL || T1 != NULL && T2 == NULL) {
		return false;
	}
	else {
		return issimilarBitree(T1->lchild, T2->lchild) && issimilarBitree(T1->rchild, T2->rchild);
	}
}

9.判断一棵树是否为完全二叉树

//例9:判断一棵树是否为完全二叉树
//算法思想:层序遍历树(将空孩子也入队)如果出队的节点为空,是完全二叉树那么队列中的结点都为空,如果有不为空的节点那么就不是完全二叉树
bool isCompleteBitree(BiTree T) {
	//应用数组模拟队列
	BiTNode* Queue[30];//注意这里数组队列的空间
	int front = 0;
	int rear = 0;
	if (T != NULL) {
		Queue[++rear] = T;
	}
	while (front != rear) {//层次遍历
		BiTNode* tmp = Queue[++front];
		if (tmp == NULL) {//遇到第一个空姐点退出循环
			break;
		}
		Queue[++rear] = tmp->lchild;
		Queue[++rear] = tmp->rchild;
	}
	while (front != rear) {//判断后续节点是否为空
		BiTNode *tmp = Queue[++front];
		if (tmp != NULL) {//有节点不为空说明不是完全二叉树
			return 0;
		}
	}
	return 1;
}

算法思想:层序遍历树(将空孩子也入队)如果出队的节点为空,是完全二叉树那么队列中的结点都为空,如果有不为空的节点那么就不是完全二叉树

10.设计算法利用叶子节点中的的空指针域将所有的叶子节点,链接成一个带头节点的双链表

//例10:设计算法利用叶子节点中的的空指针域将所有的叶子节点,链接成一个带头节点的双链表
void Linkleafs(BiTree T, BiTNode*& pTail) {//采用尾插法这样就不用判断插入的节点是否是第一个节点
	if (T != NULL) {
		if (T->lchild == NULL && T->rchild == NULL) {//叶子节点
			T->lchild = pTail;
			pTail->rchild = T;
			pTail = T;
		}
		else {
			Linkleafs(T->lchild,pTail);//处理左子树
			Linkleafs(T->rchild, pTail);//处理右子树
		}
	}
}
BiTNode* operatFunc(BiTree T) {
	BiTNode* L = NULL;
	L = (BiTNode*)malloc(sizeof(BiTNode));
	assert(L);
	L->lchild = NULL;
	L->rchild = NULL;
	BiTNode* pTail = L;
	Linkleafs(T, pTail);
	return L;
}
//打印双链表函数(数据类型char)
void print(BiTNode *L) {
	BiTNode* p = L->rchild;
	while (p) {
		printf("%c ", p->data);
		p = p->rchild;
	}
	printf("\n");
}

 11.一个包含二元运算的算数表达式以二叉链表形式存在在二叉树T中,设计算法求解算数表达式

//例11:一个包含二元运算的算数表达式以二叉链表形式存在在二叉树T中,设计算法求解算数表达式
int compute(char oprt, int leftnum, int rightnum) {//计算函数
	switch (oprt) {
	case'+':return leftnum + rightnum; break;
	case'-':return leftnum - rightnum; break;
	case'*':return leftnum * rightnum; break;
	case'/':return leftnum / rightnum; break;
	}
}
int getnum(BiTree T) {
	if (T == NULL) {//树为空
		return 0;
	}
	else if (T->lchild != NULL && T->rchild != NULL) {//操作符节点
		char oprt = T->data;
		int leftnum = getnum(T->lchild);
		int rightnum = getnum(T->rchild);
		return compute(oprt, leftnum, rightnum);//递归求值
	}
	else {//操作树节点
		return T->data - '0';
	}

}
//创建一棵算数表达式树
BiTNode* creatoprtBitree() {
	char pre[7] = { '-','+','2','1','/','4','2' };
	char in[7] = { '2','+','1','-','4','/','2' };
	return creatBitree1(pre, in, 0, 6, 0, 6);
}

 12.求一棵二叉树的最大宽度

//例12:求一棵二叉树的最大宽度
//这里直接用了一个数组直接存储每层的宽度
void getWidthBitree(BiTree T, int level,int wid[],int &max) {
	if (T == NULL) return;
	wid[level]++;
	if (wid[level] > max) max = wid[level];
	getWidthBitree(T->lchild, level + 1,wid,max);
	getWidthBitree(T->rchild, level + 1,wid,max);
}

八、总代码与测试结果

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<malloc.h>
#include<assert.h>
#define MAX 20
typedef char Elemtype;
//树的数据结构二叉链表
typedef struct BiTNode {
	Elemtype data;
	struct BiTNode* lchild;
	struct BiTNode* rchild;
}BiTNode,*BiTree;
//二叉树的先序遍历(根左右)
void preorderTraverse(BiTree T) {
	if (T != NULL) {
		printf("%c ", T->data);
		preorderTraverse(T->lchild);
		preorderTraverse(T->rchild);
	}
}
//二叉树的中序遍历(左根右)
void inorderTraverse(BiTree T) {
	if (T != NULL) {
		inorderTraverse(T->lchild);
		printf("%c ", T->data);
		inorderTraverse(T->rchild);
	}
}
//二叉树的后序遍历(左右根)
void postorderTraverse(BiTree T) {
	if (T != NULL) {
		postorderTraverse(T->lchild);
		postorderTraverse(T->rchild);
		printf("%c ", T->data);
	}
}
//二叉树的层次遍历算法
void levelTraverse(BiTree T) {//使用数组模拟队列
	BiTNode* Queue[80] = {NULL};//这里就分配了40注意
	int front = 0;
	int rear = 0;
	if (T != NULL) {
		Queue[++rear] = T;//根节点入队
	}
	while (front != rear) {
		BiTNode* p = Queue[++front];
		printf("%c ", p->data);
		if (p!=NULL && p->lchild != NULL) {
			Queue[++rear] = p->lchild;
		}
		if (p != NULL && p->rchild != NULL) {
			Queue[++rear] = p->rchild;
		}
	}
}
//已知一颗二叉树的先序遍历序列和中序遍历分别存在两个一维数组中试编写算法建立该二叉树的二叉链表
BiTNode* creatBitree1(char pre[], char in[], int l1, int h1, int l2, int h2) {
	//l代表第一个元素的位置,h代表最后一个元素的位置
	if (l1 > h1) {
		return NULL;
	}
	BiTNode* pNode = (BiTNode*)malloc(sizeof(BiTNode));
	assert(pNode);
	pNode->data = pre[l1];
	int p = l2;
	while (p <= h2) {
		if (in[p] == pre[l1]) {
			break;
		}
		p++;
	}
	//在数组中下标a减下标b表示a到b中有几个元素算a不算b
	pNode->lchild = creatBitree1(pre, in, l1 + 1, l1 + p - l2, l2, p - 1);
	pNode->rchild = creatBitree1(pre, in, l1 + p - l2 + 1, h1, p + 1, h2);
	return pNode;
}
//已知一颗二叉树的后序遍历序列和中序遍历分别存在两个一维数组中试编写算法建立该二叉树的二叉链表
BiTNode* creatBitree2(char post[], char in[], int l1, int h1, int l2, int h2) {
	if (l1 > h1) {
		return NULL;
	}
	BiTNode* pNode = (BiTNode*)malloc(sizeof(BiTNode));
	assert(pNode);
	pNode->data = post[h1];
	int p = l2;
	while (l2 <= h2) {
		if (in[p] == post[h1]) {
			break;
		}
		p++;
	}
	pNode->lchild = creatBitree2(post, in, l1, l1 + p - l2 - 1, l2, p - 1);
	pNode->rchild = creatBitree2(post, in, l1 + p - l2, h1 - 1, p + 1, h2);
	return pNode;
}
//已知一颗二叉树的层序遍历序列和中序遍历分别存在两个一维数组中试编写算法建立该二叉树的二叉链表
BiTNode* creatBitree3(char level[], char in[], int l1, int h1, int l2, int h2) {
	if (l1 > h1) {
		return NULL;
	}
	BiTNode* pNode = (BiTNode*)malloc(sizeof(BiTNode));
	assert(pNode);
	pNode->data = level[l1];
	int p = l2;
	while (p <= h2) {
		if (in[p] == level[l1]) {
			break;
		}
		p++;
	}
	//寻找左子树和右子树在层次遍历中的顺序
	char lelflevel[5];
	char rightlevel[5];
	int lelflength = 0;
	int rightlength = 0;
	//左子树
	for (int i = l1 + 1; i <= h1; i++) {
		for (int j = l2; j < p; j++) {
			if (level[i] == in[j]) {
				lelflevel[lelflength] = level[i];
				lelflength++;
			}
		}
	}
	//右子树
	for (int i = l1 + 1; i <= h1; i++) {
		for (int j = p + 1; j <= h2; j++) {
			if (level[i] == in[j]) {
				rightlevel[rightlength] = level[i];
				rightlength++;
			}
		}
	}
	pNode->lchild = creatBitree3(lelflevel, in, 0, lelflength - 1, l2, p - 1);
	pNode->rchild = creatBitree3(rightlevel, in, 0, rightlength - 1, p + 1, h2);
	return pNode;
}
//二叉树的基本操作
//例1:求一颗二叉树的节点个数
int nodesInBitree(BiTree T) {
	if (T == NULL) {
		return 0;
	}
	return 1 + nodesInBitree(T->lchild) + nodesInBitree(T->rchild);
}
//例2:求一棵二叉树的叶子节点个数
int leafsInBitree(BiTree T) {
	if (T == NULL) {
		return 0;
	}
	else if (T->lchild == NULL && T->rchild == NULL) {//叶子姐姐
		return 1;
	}
	return leafsInBitree(T->lchild) + leafsInBitree(T->rchild);
}
//例3:求一棵二叉树中度为1的节点个数
int getsinglenodes(BiTree T) {
	if (T == NULL) {
		return 0;
	}
	else if (T->lchild != NULL && T->rchild == NULL) {//左子树不为空继续搜索
		return 1 + getsinglenodes(T->lchild);
	}
	else if (T->lchild == NULL && T->rchild != NULL) {//右子树不为空继续搜索
		return 1 + getsinglenodes(T->rchild);
	}
	else {
		return getsinglenodes(T->lchild) + getsinglenodes(T->rchild);
	}
}
//例4:查找二叉树中值为x的节点,若存在则返回存储位置,不存在则返回空值
BiTNode* seekElemNode(BiTree T,char x) {
	if (T == NULL) {
		return NULL;
	}
	else if (x == T->data) {
		return T;
	}
	else {
		BiTNode* tmp = seekElemNode(T->lchild,x);//搜左子树
		if (tmp != NULL) {
			return tmp;
		}
		else {//左子树没有
			return seekElemNode(T->rchild,x);//搜右子树
		}
	}
}
//例5:求一棵二叉树的高度
int getBitreehigh(BiTree T) {
	if (T == NULL) {
		return 0;
	}
	else {
		int lelfhigh = getBitreehigh(T->lchild);
		int righthigh = getBitreehigh(T->rchild);
		return lelfhigh > righthigh ? lelfhigh + 1 : righthigh + 1;
	}
}
//例6:求一棵二叉树中值为x的节点作为根节点的子树的深度
//算法思想就是例4和例5结合,先找到值为x的节点,在根据此节点求二叉树的高度



//例7:交换一棵二叉树的左右子树
void switchLRchild(BiTree T) {
	if (T != NULL) {
		BiTNode* tmp = T->lchild;
		T->lchild = T->rchild;
		T->rchild = tmp;
		switchLRchild(T->lchild);
		switchLRchild(T->rchild);
	}
}
//定义三种遍历函数
void Traverse(BiTree T) {
	printf("先序遍历结果:");
	preorderTraverse(T);
	printf("\n");
	printf("中序遍历结果:");
	inorderTraverse(T);
	printf("\n");
	printf("后序遍历结果:");
	postorderTraverse(T);
	printf("\n");
	printf("层序遍历结果:");
	levelTraverse(T);
	printf("\n");
}
//例8:判断两棵树是否相似(长得一样)
bool issimilarBitree(BiTree T1, BiTree T2) {
	if (T1 == NULL && T2 == NULL) {
		return true;
	}
	else if (T1 == NULL && T2 != NULL || T1 != NULL && T2 == NULL) {
		return false;
	}
	else {
		return issimilarBitree(T1->lchild, T2->lchild) && issimilarBitree(T1->rchild, T2->rchild);
	}
}
//例9:判断一棵树是否为完全二叉树
//算法思想:层序遍历树(将空孩子也入队)如果出队的节点为空,是完全二叉树那么队列中的结点都为空,如果有不为空的节点那么就不是完全二
//叉树
bool isCompleteBitree(BiTree T) {
	//应用数组模拟队列
	BiTNode* Queue[30];//注意这里数组队列的空间
	int front = 0;
	int rear = 0;
	if (T != NULL) {
		Queue[++rear] = T;
	}
	while (front != rear) {//层次遍历
		BiTNode* tmp = Queue[++front];
		if (tmp == NULL) {//遇到第一个空姐点退出循环
			break;
		}
		Queue[++rear] = tmp->lchild;
		Queue[++rear] = tmp->rchild;
	}
	while (front != rear) {//判断后续节点是否为空
		BiTNode *tmp = Queue[++front];
		if (tmp != NULL) {//有节点不为空说明不是完全二叉树
			return 0;
		}
	}
	return 1;
}
//创建一棵完全二叉树
BiTNode* creatCompleteBitree() {
	char pre[7] = { 'A','B','D','E','C','F','G'};//先
	char in[7] = { 'D','B','E','A','F','C','G'};//中
	return creatBitree1(pre, in, 0, 6, 0, 6);
}
//例10:设计算法利用叶子节点中的的空指针域将所有的叶子节点,链接成一个带头节点的双链表
void Linkleafs(BiTree T, BiTNode*& pTail) {//采用尾插法这样就不用判断插入的节点是否是第一个节点
	if (T != NULL) {
		if (T->lchild == NULL && T->rchild == NULL) {//叶子节点
			T->lchild = pTail;
			pTail->rchild = T;
			pTail = T;
		}
		else {
			Linkleafs(T->lchild,pTail);//处理左子树
			Linkleafs(T->rchild, pTail);//处理右子树
		}
	}
}
BiTNode* operatFunc(BiTree T) {
	BiTNode* L = NULL;
	L = (BiTNode*)malloc(sizeof(BiTNode));
	assert(L);
	L->lchild = NULL;
	L->rchild = NULL;
	BiTNode* pTail = L;
	Linkleafs(T, pTail);
	return L;
}
//打印双链表函数(数据类型char)
void print(BiTNode *L) {
	BiTNode* p = L->rchild;
	while (p) {
		printf("%c ", p->data);
		p = p->rchild;
	}
	printf("\n");
}
//例11:一个包含二元运算的算数表达式以二叉链表形式存在在二叉树T中,设计算法求解算数表达式
int compute(char oprt, int leftnum, int rightnum) {//计算函数
	switch (oprt) {
	case'+':return leftnum + rightnum; break;
	case'-':return leftnum - rightnum; break;
	case'*':return leftnum * rightnum; break;
	case'/':return leftnum / rightnum; break;
	}
}
int getnum(BiTree T) {
	if (T == NULL) {//树为空
		return 0;
	}
	else if (T->lchild != NULL && T->rchild != NULL) {//操作符节点
		char oprt = T->data;
		int leftnum = getnum(T->lchild);
		int rightnum = getnum(T->rchild);
		return compute(oprt, leftnum, rightnum);//递归求值
	}
	else {//操作树节点
		return T->data - '0';
	}

}
//创建一棵算数表达式树
BiTNode* creatoprtBitree() {
	char pre[7] = { '-','+','2','1','/','4','2' };
	char in[7] = { '2','+','1','-','4','/','2' };
	return creatBitree1(pre, in, 0, 6, 0, 6);
}
//例12:求一棵二叉树的最大宽度

void getWidthBitree(BiTree T, int level,int wid[],int &max) {
	if (T == NULL) return;
	wid[level]++;
	if (wid[level] > max) max = wid[level];
	getWidthBitree(T->lchild, level + 1,wid,max);
	getWidthBitree(T->rchild, level + 1,wid,max);
}
int main() {
	char pre[5] = { 'A','B','D','C','E' };//先
	char in[5] = { 'D','B','A','C','E' };//中
	char post[5] = { 'D','B','E','C','A' };//后
	char level[5] = { 'A','B','C','D','E' };//层
	int prelength = sizeof(pre) / sizeof(pre[0]);
	int postlength = sizeof(post) / sizeof(post[0]);
	int levellength = sizeof(level) / sizeof(level[0]);
	int inlength = sizeof(in) / sizeof(in[0]);
	//BiTree T = creatBitree1(pre, in, 0, prelength - 1, 0, inlength - 1);//先序和中序
	//BiTree T = creatBitree2(post, in, 0, postlength - 1, 0, inlength - 1);//后序和中序
	BiTree T = creatBitree3(level, in, 0, levellength - 1, 0, inlength - 1);//层序和中序
	BiTree Ttest = creatBitree3(level, in, 0, levellength - 1, 0, inlength - 1);//层序和中序
	Traverse(T);
	printf("该二叉树的节点个数为:%d\n", nodesInBitree(T));
	printf("该二叉树的叶子节点个数为:%d\n", leafsInBitree(T));
	printf("该二叉树的度为1节点个数为:%d\n", getsinglenodes(T));
	printf("查找的节点为:%c\n", seekElemNode(T, 'C')->data);
	printf("该二叉树的高度为:%d\n", getBitreehigh(T));
	printf("以B为根的子树的高度为:%d\n", getBitreehigh(seekElemNode(T, 'B')));
	printf("++++++++++++++++++++++++++++++++++++\n");
	printf("交换左右子树\n");
	printf("交换子树前\n");
	Traverse(Ttest);
	switchLRchild(Ttest);
	printf("交换子树后\n");
	Traverse(Ttest);
	printf("判断T与Ttest两棵树是否相似(相似返回1,不相似返回0):%d\n", issimilarBitree(T, Ttest));
	printf("判断二叉树T是否为一棵完全二叉树(是返回1,不是返回0):%d\n", isCompleteBitree(T));
	printf("创建一棵完全二叉树\n");
	BiTree TC = creatCompleteBitree();
	Traverse(TC);
	printf("判断二叉树TC是否为一棵完全二叉树(是返回1,不是返回0):%d\n", isCompleteBitree(TC));
	printf("++++++++++++++++++++++++++++++++++++\n");
	printf("利用叶子节点中的的空指针域将所有的叶子节点,链接成一个带头节点的双链表\n");
	BiTNode* L = operatFunc(TC);
	print(L);
	printf("++++++++++++++++++++++++++++++++++++\n");
	printf("创建一棵算数表达式树\n");
	BiTNode* TO = creatoprtBitree();
	Traverse(TO);
	printf("该算数表达式的值为:%d\n", getnum(TO));
	int wid[20] = { 0 };
	int max = 0;
	getWidthBitree(T, 1,wid,max);
	printf("二叉树TC的最大宽度为:%d\n", max);
	printf("注意后续不要在使用TC,因为TC已经将叶子节点转变为双链表!!!!!!!!\n");
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1377396.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智能小程序小部件(Widget)开发详解

Widget 代表应用的一个小部件&#xff0c;负责小部件的展示和交互。 小部件(Widget) 的开发在智能小程序的基础上增加一个目录即可&#xff0c;用于存放小部件(Widget)的代码。并在 project.tuya.json 中增加一个声明。 创建小部件(Widget)项目 在 Tuya MiniApp Tools 中&…

强化学习应用(一):基于Q-learning的无人机物流路径规划研究(提供Python代码)

一、Q-learning简介 Q-learning是一种强化学习算法&#xff0c;用于解决基于马尔可夫决策过程&#xff08;MDP&#xff09;的问题。它通过学习一个价值函数来指导智能体在环境中做出决策&#xff0c;以最大化累积奖励。 Q-learning算法的核心思想是通过不断更新一个称为Q值的…

在windows11系统上利用docker搭建linux记录

我的windows11系统上&#xff0c;之前已经安装好了window版本的docker&#xff0c;没有安装的小伙伴需要去安装一下。 下面直接记录安装linux的步骤&#xff1a; 一、创建linux容器 1、拉取镜像 docker pull ubuntu 2、查看镜像 docker images 3、创建容器 docker run --…

Ubuntu 22.04 编译安装 Qt mysql驱动

参考自 Ubuntu20.04.3 QT5.15.2 MySQL驱动编译 Ubuntu 18.04 编译安装 Qt mysql驱动 下边这篇博客不是主要参考的, 但是似乎解决了我的难题(找不到 libmysqlclient.so) ubuntu18.04.2 LTS 系统关于Qt5.12.3 无法加载mysql驱动&#xff0c;需要重新编译MYSQL数据库驱动的问题以…

代码随想录算法训练营第六天|哈希表理论基础,242.有效的字母异位词,349. 两个数组的交集,202. 快乐数,1. 两数之和

刷题建议 刷题建议与debug 代码随想录目前基本都有了视频讲解&#xff0c;一定要先看视频&#xff0c;事半功倍。写博客&#xff0c;将自己的感悟沉淀下来&#xff0c;不然会忘大家提问的时候&#xff0c;记得要把问题描述清楚&#xff0c;自己在哪一步遇到了问题&#xff0c…

虚幻UE 材质-材质图层、材质图层混合

学习材质图层和材质图层混合的使用&#xff0c;便于节点扫盲。 文章目录 前言一、材质图层混合二、使用步骤总结 前言 材质混合我们之前用Bridge的插件进行混合过 而此次我们的材质混合使用UE自带的材质图层和材质图层混合来实现 一、材质图层混合 材质图层混合是一种允许将…

数据结构初阶之插入排序与希尔排序详解

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言程序设计————KTV C语言小游戏 C语言进阶 C语言刷题 数据结构初阶 Linux 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力,共赴大厂。 目录 一.前言 二.插入排序 …

jmeter分布式服务搭建

目录 一、环境准备 二、 安装包下载 三 、安装jdk 四 、控制机安装 4.1 解压压缩包 4.2 修改 bin/jmeter.properties 4.3 修改 bin/system.properties 五、执行机安装 5.1 解压安装包 5.2 修改 bin/jmeter.properties 5.3 修改 bin/system.properties 5.4 启动执行机 …

常见的AdX程序化广告交易模式有哪些?媒体如何选择恰当的交易模式?

程序化广告的核心目的是&#xff1a;让需求方能自由地选择流量与出价&#xff0c;程序化广告在数字广告投放中的主导地位日益巩固。 程序化广告“交易模式”有哪些&#xff1f;以下是详细解读&#xff0c;帮助媒体选择恰当的交易方式&#xff0c;从而实现广告价值的最大化。 …

python netCDF4

NetCDF简介 NetCDF 即 network Common Data Form&#xff08;网络通用数据格式&#xff09;&#xff0c;是一种面向数组型并适于网络共享的数据的描述和编码标准。文件的后缀是 .nc。nc 在气象领域应用很广&#xff0c;因为它可以存储不同波段的长时间观测结果。 NetCDF 文件…

全志V853 NPU开发之工具安装

V853支持最高1T NPU算力&#xff0c;在进行NPU相关开发前&#xff0c;需要先配置NPU开发环境。 Linux系统准备 NPU开发环境依赖于Linux系统&#xff0c;需要先准备 Linux 开发环境。 经测试NPU 工具支持下列 Linux 发行版&#xff1a; Ubuntu 20.04 其他部分 Linux 发行版…

基于python的室内老人实时摔倒智能监测系统(康复训练检测+代码)

概述 导入所需的库&#xff0c;包括cv2、和numpy。 定义了一个用于计算角度的函数calculate_angle(a, b, c)&#xff0c;其中a、b和c是三个关键点的坐标。 初始化姿态检测和绘图工具。 打开并读取视频文件。 -摔倒检测&#xff08;fallen&#xff09; 循环遍历视频的每一帧…

用友BI方案是干嘛的?能起到什么作用?

用友BI是一套用于无缝对接用友系统&#xff0c;让BI从用友系统中直接取数、分析&#xff0c;完成对企业数据的全面剖析&#xff0c;并为决策提供必不可少的支持的标准化方案。 为什么会有用友BI方案&#xff1f; 因为用友ERP和BI&#xff08;商业智能&#xff09;系统虽然都是…

uniapp开发安卓应用微信开放平台创建应用如何获取签名

微信开放平台创建应用时需要应用的签名 比如我们开发了一个应用叫 “滴滴拉屎” 包名&#xff1a;uni.DIDILASHI #mermaid-svg-BUKbltDr30J93dUs {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-BUKbltDr30J93dUs .…

Elasticsearch 快速入门指南【总结记录】

本文将介绍一些基本概念&#xff0c;帮助您快速入门使用Elasticsearch。 一、概述 ES用来解决什么问题&#xff1f;Elasticsearch是解决海量数据&#xff08;已经存在的数据&#xff09;全文检索的不二只选。 Elasticsearch是一个基于Java语言开发&#xff0c;建立在开源搜索…

代码随想录算法训练营第三天 | 203.移除链表元素、707.设计链表、206.反转链表

代码随想录算法训练营第三天 | 203.移除链表元素、707.设计链表、206.反转链表 文章目录 代码随想录算法训练营第三天 | 203.移除链表元素、707.设计链表、206.反转链表1 链表理论基础1.1 链表的定义1.2 链表的类型1.3 链表的存储方式1.4 链表的操作性能分析1.5 链表和数组的区…

电脑上不安装Oracle,但是虚拟机装了Oracle,怎么连接到虚拟机里的Oracle数据库呢?

1、准备工作 1.1、确定数据库版本信息 注&#xff1a;如果知道数据库的版本信息&#xff0c;这个步骤可以跳过。 比较简单的方法&#xff0c;直接看数据库的安装位置&#xff0c;也就是数字&#xff08;但是这个方法确定就是&#xff0c;不好确定是多少位的数据库&#xff09;…

高性能mysql 第三版 读书笔记

MySQL中的tmp_table_size和max_heap_table_size|极客笔记 mysql占用内存过高调优方法_tmp_table_size过大阻塞-CSDN博客 查看mysql分配的内存 mysql查看内存利用状态_mob6454cc6d81c9的技术博客_51CTO博客 https://www.cnblogs.com/stronger-xsw/p/13632505.html

企业信息化规划该如何落地?以制造型企业为例

企业信息化规划如何落地&#xff1f; 规划做好了&#xff0c;蓝图也画好了&#xff0c;人手一块大饼也已经揣好了&#xff0c;那么该怎么落地呢&#xff0c;这才是最关键的。 我将企业信息化规划落地分为4个周期&#xff0c;以最典型的制造行业为例&#xff0c;以简道云这个企…

JRT界面打开器

开发BS界面时候有个问题&#xff0c;如果新做页面还没挂菜单&#xff0c;那么测试新页面有两个办法&#xff0c;一是把菜单挂上用&#xff0c;一是手输URL。而我在开发阶段两个事都不想干&#xff0c;那么怎么解决呢&#xff1f; 以前WebLoader启动时候会启动C#写的URL辅助器 …