数据结构——二叉树(续集)


♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥

♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥

♥♥♥我们一起努力成为更好的自己~♥♥♥

♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥

♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥



✨✨✨✨✨✨个人主页✨✨✨✨✨✨


在上一篇博客我们说到了树的基本概念,以及顺序结构二叉树的实现及运用,我们知道二叉树还可以通过链式结构来实现,这一篇博客带着大家一起继续在二叉树的世界里面遨游~(提前透露一下~这一篇博客更多的是体会递归的暴力美学~)

目录

实现链式结构二叉树

结构

手动创建二叉树

二叉树的遍历

遍历方式

前序遍历

中序遍历

后序遍历

二叉树操作

二叉树结点个数

二叉树叶子结点的个数

二叉树第k层结点个数

二叉树的深度/高度

二叉树查找值为x的结点

二叉树销毁

常见问题

层序遍历

思路

代码

判断完全二叉树

画图分析思路

代码

总代码

BTree.h

BTree.c

test.c


实现链式结构二叉树

既然是链式结构的二叉树,结合我们前面的经验那肯定离不开链表了~首先来看看链式结构二叉树的结构~

结构

用链表来表示⼀棵二叉树,即用链来指示元素之间逻辑关系。 通常的方法是链表中每个结点由三个域组 数据域和左、右指针域 ,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。
结构代码:
//定义二叉树结点结构
typedef char BTDataType;//保存的数据类型
typedef struct BinaryTreeNode
{BTDataType data;//保存的数据struct BinaryTreeNode* left;//左孩子结点的地址struct BinaryTreeNode* right;//右孩子结点的地址
}BTNode;
有了一个结点的结点代码,但是因为二叉树的创建方式比较复杂,所以我们这里手动创建一个二叉树进行实现~

手动创建二叉树

这里呢,我们创建一个比较复杂的二叉树,既然二叉树也是由一个个结点组成的,那么我们创建二叉树就需要创建一个个结点再进行连接起来,我们可以看到,上面的二叉树一共有6个结点,所以我们需要创建6个结点再进行连接~注意:这里我们保存的是字符,所以保存数据类型改为char 

代码:

#include"Btree.h"//创建一个结点代码
BTNode* BuyNode(BTDataType x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL){perror("malloc fail");exit(1);//创建失败,退出程序}//创建成功node->data = x;node->left = node->right = NULL;//返回创建的结点地址return node;
}
//创建二叉树
BTNode* BTreeCreate()
{BTNode* n1 = BuyNode('A');BTNode* n2 = BuyNode('B');BTNode* n3 = BuyNode('C');BTNode* n4 = BuyNode('D');BTNode* n5 = BuyNode('E');BTNode* n6 = BuyNode('F');//通过逻辑关系连接结点n1->left = n2;n1->right = n3;n2->left = n4;n3->left = n5;n3->right = n6;//返回头结点return n1;
}
void test1()
{//手动创建一个二叉树BTNode* head = BTreeCreate();
}

手动创建的二叉树也就完成了,接下来我们想一想怎么对这个二叉树进行操作呢?每一颗子树的末尾都会走到空,显然,我们这里不能像单链表那样进行遍历,那我们应该怎么样遍历二叉树呢?

二叉树的遍历

遍历方式

二叉树的遍历方式有三种:

前序/中序/后序的递归结构遍历:

1.前序遍历(Preorder Traversal 亦称先序遍历):
访问根结点的操作发生在遍历其左右子树之前
访问顺序为:根结点、左子树、右子树
2.中序遍历(Inorder Traversal):
访问根结点的操作发生在遍历其左右子树之中(间)
访问顺序为:左子树、根结点、右子树
3.后序遍历(Postorder Traversal):
访问根结点的操作发生在遍历其左右子树之后
访问顺序为:左子树、右子树、根结点

我们可以发现,二叉树不同的遍历方式最大的区别就是访问根结点的顺序不同最开始访问根结点就是前序遍历,中间访问根结点就是中序遍历,最后访问根结点就是后序遍历

知道了这三种遍历方式,那么我们来看看这个二叉树不同遍历方式下有什么结果呢?

前序遍历:

A B D NULL NULL NULL C E NULL NULL F NULL NULL

中序遍历:

NULL D NULL B NULL A NULL E NULL C NULL F NULL

后序遍历:

NULL NULL D NULL B NULL NULL E NULL NULL F C A

不知道你的答案有没有正确呢?这种遍历有一种方式就是先全局再局部进行遍历,往下走就是子树也按照规定顺序进行遍历就可以了。

比如举中序遍历的例子:

首先我们知道根结点在中间,那么我们首先就可以确定整体的样子,再在子数中操作


(B子树)A(C子树)


(……B……)A (……C……)


(…D…B NULL)A (…E…C…F…)


NULL D NULL B NULL A NULL E NULL C NULL F NULL

最后我们就可以得到中序遍历的结果:NULL D NULL B NULL A NULL E NULL C NULL F NULL

其他的遍历方式操作方法类似,当然也可以画图来理解遍历的过程~

知道了这三种遍历方式,我们怎么用代码实现呢?

这里就要开始我们递归的暴力美学了~我们可以发现二叉树是一层层往下面递进的~相当于有一个递归的过程~

前序遍历

//前序遍历
void PreOrder(BTNode* root)
{if (root == NULL){//如果为空,直接打印返回printf("NULL ");return;}//递归遍历,最开始打印根结点数据printf("%c ", root->data);PreOrder(root->left);PreOrder(root->right);
}

看看打印结果~

我们可以发现和我们前面分析的结果是一模一样的,是不是很神奇~这里我们来看看这里的递归是如何达到我们想要的效果的~

解释:如果根结点为空就打印NULL,如果根结点不为空就打印根结点,然后再同样的方式遍历左孩子结点和右孩子结点(左孩子结点和右孩子结点也就是子树的根结点),这里的递归也就是先往下面一层层递归然后再回退~画图分析~

怎么样~有没有体会到递归的暴力美学呢?有了这一个基础,接下来我们的中序遍历和后序遍历相信就简单了~

中序遍历

//中序遍历
void InOrder(BTNode* root)
{if (root == NULL){//如果为空,直接打印返回printf("NULL ");return;}//根结点在中间打印InOrder(root->left);printf("%c ", root->data);InOrder(root->right);
}

后序遍历

//后序遍历
void LasOrder(BTNode* root)
{if (root == NULL){//如果为空,直接打印返回printf("NULL ");return;}//根结点最后打印LasOrder(root->left);LasOrder(root->right);printf("%c ", root->data);
}

这里三种遍历相信问题不大,递归的魅力有没有体会到呢?接下来我们继续使用递归对二叉树进行操作~

二叉树操作

还是以这一个二叉树为例

二叉树结点个数

这里我们来巧妙的使用递归方法求结点个数~

原理:

总结点个数 = 1 + 左子树结点个数 +右子树结点个数(根结点为空返回0)

代码:

// 二叉树结点个数
int BinaryTreeSize(BTNode* root)
{if (root == NULL){return 0;}return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}

二叉树叶子结点的个数

1.什么是叶子结点?

度为0,左孩子结点和右孩子结点都为NULL

2.原理

叶子结点总个数=左子树叶子结点个数 +右子树叶子结点个数

代码:

// 二叉树叶子结点个数
int BinaryTreeLeafSize(BTNode* root)
{//root不为空,避免对空指针解引用//左孩子结点和右孩子结点都为NULL是叶子结点if (root != NULL && root->left == NULL && root->right == NULL){return 1;}//如果root为NULL,返回0if (root == NULL){return 0;}//叶子结点总个数=左子树叶子结点个数 +右子树叶子结点个数return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

二叉树第k层结点个数

原理:

二叉树第k层结点个数 =  左子树第k层结点个数 +右子树第k层结点个数

代码:

// 二叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{//如果为空,没有结点,返回0if (root == NULL){return 0;}//root不为空,并且走到第k层//后面传参k-1,到第k层也就是k=1//例:求第三层,从第一层向下走2层就可以到第三层if (k == 1){return 1;}//二叉树第k层结点个数 =  左子树第k层结点个数 +右子树第k层结点个数return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

二叉树的深度/高度

思路:

二叉树的深度/高度 = 1 + Max(左子树深度/高度、右子树深度/高度最大值)

(如果为空返回0)

代码:

// 二叉树的深度/高度
int BinaryTreeDepth(BTNode* root)
{//如果root为空返回0if (root == NULL){return 0;}//求左子树深度/高度int DepLeft = BinaryTreeDepth(root->left);// 求右子树深度/高度int DepRight = BinaryTreeDepth(root->right);//返回1+左子树深度/高度、右子树深度/高度最大值return 1 + (DepLeft > DepRight ? DepLeft : DepRight);
}

二叉树查找值为x的结点

既然需要查找结点,那么这里肯定离不开遍历二叉树了~

思路:

判断根结点root是否为要找的结点,如果是直接返回root,如果root为空就返回NULL,然后在左子树里面找,最后在右子树里面找,都没有找到就返回NULL。

代码:

// 二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{//判断根结点if (root == NULL){return NULL;}if (root->data == x){return root;}//在左子树里面找BTNode* leftFind = BinaryTreeFind(root->left, x);//左子树找到结果不为空,返回if (leftFind){return leftFind;}//在右子树里面找BTNode* rightFind = BinaryTreeFind(root->left, x);//右子树找到结果不为空,返回if (rightFind){return rightFind;}//最后没有找到return NULL;
}

测试:

二叉树销毁

接下来就是二叉树的销毁了~

这里有一个需要注意的点是我们前面对二叉树操作并没有更改头结点,但是二叉树销毁,是每一个结点都需要销毁的,所以我们要传二级指针~

思路:遍历二叉树销毁,root为NULL直接返回,这里我们需要使用后序遍历(如果前面就把root置为空之后,我们是不能对空指针进行解引用的~就找不到左右孩子结点了~)

代码:(后序遍历销毁)

// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{//为空直接返回,不需要销毁了if (*root == NULL){return;}//后序遍历销毁——左右根//注意:二级指针传地址BinaryTreeDestory(&((*root)->left));BinaryTreeDestory(&((*root)->right));free(*root);*root = NULL;
}

我们可以看到二叉树销毁成功~

常见问题

这里二叉树的大部分操作已经完成了~接下来看一些常见问题~

1.不同函数特殊情况处理操作中为什么有的return NULL;有的return 0;有的直接return;

答:这就与函数的返回值有关了,我们可以看到有的函数返回值是int类型,有的是BTNode*类型,有的是void类型,这里返回的与返回值类型保持一致~

例:

int类型

BTNode*类型

void类型:

层序遍历

前面讲解了二叉树的三种遍历方式——前中后序遍历~除此之外,二叉树还有一种遍历方式也就是层序遍历~听这个名字是不是就是一层层的进行遍历呢?答案是的~

比如下面这个二叉树遍历结果为:A B C D E F

思路

那么我们怎么通过代码来实现这个过程呢?

这里就需要我们前面学到的数据结构知识——队列(不清楚的可以看看前面的文章:数据结构——栈和队列)

这里我们给出思路:

首先让根结点入队列,循环判断队列是否为空,如果队列不为空就取队头并且出队头,如果结点的左右孩子不为空就让结点的左右孩子入队列,如此循环

画图理解:

1.让根结点入队列(队尾入,队头出)

2.判断队列是否为空,队列不为空就取队头并且出队头,然后让结点的左右孩子入队列

当队列为空,这个循环就结束,我们可以看到这就是层序遍历的结果~

注意:

1.这里是结点入队列,所以队列保存的数据类型是struct BinaryTreeNode*!

有人可能会说不是将struct BinaryTreeNode重定义为BTNode了吗?是不是也可以写成

typedef BTNode* QueueDataType,答案是不可以这样写的,我们必须告诉操作系统这一个类型是struct这样一个结构,如果这样使用同样要在前面加上struct。

正确使用:

方法一:

typedef struct BinaryTreeNode* QueueDataType;

方法二:

typedef struct BTNode* QueueDataType;

这样看起来,我们还是推荐使用方法一~

2.在前面,我们已经实现过队列,有相应的头文件和源文件这里我们只需要包含头文件使用就可以了~

代码

知道了思路,接下来就是我们的代码实现了~

// 层序遍历
void LevelOrder(BTNode* root)
{if (root == NULL){return;}//定义一个队列结构Queue Qu;//初始化QueueInit(&Qu);//让根结点入队列QueuePush(&Qu, root);//队列不为空,取队头打印数据,并且出队头while (!QueueEmpty(&Qu)){BTNode* top = QueueFront(&Qu);printf("%c ", top->data);//队头出队列QueuePop(&Qu);//如果左右孩子结点不为空入队列if (top->left){QueuePush(&Qu, top->left);}if (top->right){QueuePush(&Qu, top->right);}}//销毁QueueDestroy(&Qu);
}

我们可以看到达到了我们想要的效果~

如果我们也想要像前面打印NULL,代码就会有一些小变化~打印NULL,那么NULL也需要入队列~如果取队头为NULL,就直接打印,然后使用continue语句继续执行循环~

// 层序遍历2
//为空也入队列
void LevelOrder2(BTNode* root)
{//定义一个队列结构Queue Qu;//初始化QueueInit(&Qu);//让根结点入队列//为空也入队列,不需要判断QueuePush(&Qu, root);//队列不为空,取队头打印数据,并且出队头while (!QueueEmpty(&Qu)){BTNode* top = QueueFront(&Qu);//队头为空打印NULL并且NULL出队列if (top == NULL){printf("NULL ");QueuePop(&Qu);continue;//继续执行循环}else{printf("%c ", top->data);}//队头出队列QueuePop(&Qu);//左右孩子结点入队列QueuePush(&Qu, top->left);QueuePush(&Qu, top->right);}//销毁QueueDestroy(&Qu);
}

这里的层序遍历就巧妙地将二叉树和队列结合在一起~

判断完全二叉树

画图分析思路

前面我们说到完全二叉树的特点是最后一层结点个数不一定达到最大~但是结点从左向右依次排列~

这里我们需要判断一个二叉树是不是完全二叉树应该怎么办呢?这里同样需要使用队列~这里我们来画图找完全二叉树和非完全二叉树的区别~

完全二叉树

1.根结点入队列

2.队列不为空,取队头出队头,将左右孩子结点入队列(这里结点为空也入,方便后面判断),如此循环,到取到top为NULL第一层循环结束,第二次循环条件依然是队列不为空,取剩下的队列元素

3.第二层循环取队头出队头

我们可以发现完全二叉树剩下的队列元素都是空~

接下来我们看看非完全二叉树进行同样的操作~

1.根结点入队列

2.队列不为空,取队头出队头,将左右孩子结点入队列(这里结点为空也入,方便后面判断),如此循环,到取到top为NULL第一层循环结束,第二次循环条件依然是队列不为空,取剩下的队列元素

3.第二层循环取队头出队头

我们可以看到非完全二叉树第二次循环取队头元素有不为空的结点~这就是它们之间的区别~

思路:首先让根结点入队列,第一次循环队列不为空,取队头出队头,将左右孩子结点入队列(这里结点为空也入,方便后面判断),如此循环,到取到top为NULL第一层循环结束,第二次循环条件依然是队列不为空,取剩下的队列元素,剩下的队列元素有不为空的说明是非完全二叉树~

代码

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{//借助队列Queue Qu;//初始化QueueInit(&Qu);//根结点入队列QueuePush(&Qu, root);while (!QueueEmpty(&Qu)){//取队头元素BTNode* top = QueueFront(&Qu);//出队列QueuePop(&Qu);//为空第一层循环结束if (top == NULL){break;}//让左右孩子结点入队列QueuePush(&Qu, top->left);QueuePush(&Qu, top->right);}//第二层循环,队列不为空//继续取队头出队头,如果有不为NULL的说明是非完全二叉树while (!QueueEmpty(&Qu)){//取队头元素BTNode* top = QueueFront(&Qu);//出队列QueuePop(&Qu);if (top != NULL){//返回前销毁队列!!!QueueDestroy(&Qu);return false;}}//剩下的全部为NULL,是完全二叉树return true;//销毁QueueDestroy(&Qu);
}

我们的代码达到了我们想要的效果~

总代码

BTree.h


//需要的头文件
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include"Queue.h"//定义二叉树结点结构
typedef char BTDataType;//保存的数据类型
typedef struct BinaryTreeNode
{BTDataType data;//保存的数据struct BinaryTreeNode* left;//左孩子结点的地址struct BinaryTreeNode* right;//右孩子结点的地址
}BTNode;//前序遍历
void PreOrder(BTNode* root);//中序遍历
void InOrder(BTNode* root);//后序遍历
void LasOrder(BTNode* root);// 二叉树结点个数
int BinaryTreeSize(BTNode* root);// 二叉树叶子结点个数
int BinaryTreeLeafSize(BTNode* root);// 二叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k);// 二叉树的深度/高度
int BinaryTreeDepth(BTNode* root);// 二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);// 二叉树销毁
void BinaryTreeDestory(BTNode** root);// 层序遍历1
void LevelOrder1(BTNode* root);
// 层序遍历2
void LevelOrder2(BTNode* root);// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root);

BTree.c


#include"Btree.h"//前序遍历
void PreOrder(BTNode* root)
{if (root == NULL){//如果为空,直接打印返回printf("NULL ");return;}//递归遍历,最开始打印根结点数据printf("%c ", root->data);PreOrder(root->left);PreOrder(root->right);
}//中序遍历
void InOrder(BTNode* root)
{if (root == NULL){//如果为空,直接打印返回printf("NULL ");return;}//根结点在中间打印InOrder(root->left);printf("%c ", root->data);InOrder(root->right);
}//后序遍历
void LasOrder(BTNode* root)
{if (root == NULL){//如果为空,直接打印返回printf("NULL ");return;}//根结点最后打印LasOrder(root->left);LasOrder(root->right);printf("%c ", root->data);
}// 二叉树结点个数
int BinaryTreeSize(BTNode* root)
{if (root == NULL){return 0;}return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}// 二叉树叶子结点个数
int BinaryTreeLeafSize(BTNode* root)
{//root不为空,避免对空指针解引用//左孩子结点和右孩子结点都为NULL是叶子结点if (root != NULL && root->left == NULL && root->right == NULL){return 1;}//如果root为NULL,返回0if (root == NULL){return 0;}//叶子结点总个数=左子树叶子结点个数 +右子树叶子结点个数return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}// 二叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{//如果为空,没有结点,返回0if (root == NULL){return 0;}//root不为空,并且走到第k层//后面传参k-1,到第k层也就是k=1//例:求第三层,从第一层向下走2层就可以到第三层if (k == 1){return 1;}//二叉树第k层结点个数 =  左子树第k层结点个数 +右子树第k层结点个数return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}// 二叉树的深度/高度
int BinaryTreeDepth(BTNode* root)
{//如果root为空返回0if (root == NULL){return 0;}//求左子树深度/高度int DepLeft = BinaryTreeDepth(root->left);// 求右子树深度/高度int DepRight = BinaryTreeDepth(root->right);//返回1+左子树深度/高度、右子树深度/高度最大值return 1 + (DepLeft > DepRight ? DepLeft : DepRight);
}// 二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{//判断根结点if (root == NULL){return NULL;}if (root->data == x){return root;}//在左子树里面找BTNode* leftFind = BinaryTreeFind(root->left, x);//左子树找到结果不为空,返回if (leftFind){return leftFind;}//在右子树里面找BTNode* rightFind = BinaryTreeFind(root->left, x);//右子树找到结果不为空,返回if (rightFind){return rightFind;}//最后没有找到return NULL;
}// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{//为空直接返回,不需要销毁了if (*root == NULL){return;}//后序遍历销毁——左右根//注意:二级指针传地址BinaryTreeDestory(&((*root)->left));BinaryTreeDestory(&((*root)->right));free(*root);*root = NULL;//中序遍历销毁//err/*BinaryTreeDestory(&((*root)->left));free(*root);*root = NULL;BinaryTreeDestory(&((*root)->right));*/
}// 层序遍历
void LevelOrder1(BTNode* root)
{if (root == NULL){return;}//定义一个队列结构Queue Qu;//初始化QueueInit(&Qu);//让根结点入队列QueuePush(&Qu, root);//队列不为空,取队头打印数据,并且出队头while (!QueueEmpty(&Qu)){BTNode* top = QueueFront(&Qu);printf("%c ", top->data);//队头出队列QueuePop(&Qu);//如果左右孩子结点不为空入队列if (top->left){QueuePush(&Qu, top->left);}if (top->right){QueuePush(&Qu, top->right);}}//销毁QueueDestroy(&Qu);
}// 层序遍历2
//为空也入队列
void LevelOrder2(BTNode* root)
{//定义一个队列结构Queue Qu;//初始化QueueInit(&Qu);//让根结点入队列//为空也入队列,不需要判断QueuePush(&Qu, root);//队列不为空,取队头打印数据,并且出队头while (!QueueEmpty(&Qu)){BTNode* top = QueueFront(&Qu);//队头为空打印NULL并且NULL出队列if (top == NULL){printf("NULL ");QueuePop(&Qu);continue;//继续执行循环}else{printf("%c ", top->data);}//队头出队列QueuePop(&Qu);//左右孩子结点入队列QueuePush(&Qu, top->left);QueuePush(&Qu, top->right);}//销毁QueueDestroy(&Qu);
}// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{//借助队列Queue Qu;//初始化QueueInit(&Qu);//根结点入队列QueuePush(&Qu, root);while (!QueueEmpty(&Qu)){//取队头元素BTNode* top = QueueFront(&Qu);//出队列QueuePop(&Qu);//为空第一层循环结束if (top == NULL){break;}//让左右孩子结点入队列QueuePush(&Qu, top->left);QueuePush(&Qu, top->right);}//第二层循环,队列不为空//继续取队头出队头,如果有不为NULL的说明是非完全二叉树while (!QueueEmpty(&Qu)){//取队头元素BTNode* top = QueueFront(&Qu);//出队列QueuePop(&Qu);if (top != NULL){//返回前销毁队列!!!QueueDestroy(&Qu);return false;}}//剩下的全部为NULL,是完全二叉树return true;//销毁QueueDestroy(&Qu);
}

test.c


#include"Btree.h"//创建一个结点代码
BTNode* BuyNode(BTDataType x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL){perror("malloc fail");exit(1);//创建失败,退出程序}//创建成功node->data = x;node->left = node->right = NULL;//返回创建的结点地址return node;
}
//创建二叉树
BTNode* BTreeCreate()
{BTNode* n1 = BuyNode('A');BTNode* n2 = BuyNode('B');BTNode* n3 = BuyNode('C');BTNode* n4 = BuyNode('D');BTNode* n5 = BuyNode('E');BTNode* n6 = BuyNode('F');//通过逻辑关系连接结点n1->left = n2;n1->right = n3;n2->left = n4;n3->left = n5;n3->right = n6;//返回头结点return n1;
}
void test1()
{//手动创建一个二叉树BTNode* head = BTreeCreate();//前序遍历printf("前序遍历:");PreOrder(head);printf("\n");//中序遍历printf("中序遍历:");InOrder(head);printf("\n");//后序遍历printf("后序遍历:");LasOrder(head);printf("\n");
}void test2()
{//手动创建一个二叉树BTNode* head = BTreeCreate();//二叉树结点个数printf("二叉树结点个数:%d\n", BinaryTreeSize(head));printf("二叉树叶子结点个数:%d\n", BinaryTreeLeafSize(head));/*printf("二叉树第%d层结点个数:%d\n", 1, BinaryTreeLevelKSize(head, 1));printf("二叉树第%d层结点个数:%d\n", 3, BinaryTreeLevelKSize(head, 3));printf("二叉树第%d层结点个数:%d\n", 4, BinaryTreeLevelKSize(head, 4));*/printf("二叉树的深度/高度:%d\n", BinaryTreeDepth(head));/*BTNode* find = BinaryTreeFind(head, 'B');if (find){printf("找到了!\n");}else{printf("没有找到!\n");}*///二级指针传地址//BinaryTreeDestory(&head);
}void test3()
{//手动创建一个二叉树BTNode* head = BTreeCreate();//层序遍历printf("LevelOrder1:\n");LevelOrder1(head);printf("\n");printf("LevelOrder2:\n");LevelOrder2(head);//判断完全二叉树/*if (BinaryTreeComplete(head)){printf("是完全二叉树!\n");}else{printf("不是完全二叉树!\n");}*/
}int main()
{//test1();//test2();test3();return 0;
}

♥♥♥本篇博客内容结束,期待与各位未来的优秀程序员交流,有什么问题请私信♥♥♥

♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥


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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL性能测试方案设计

在现代互联网系统中&#xff0c;数据库性能直接影响到整体应用的速度和用户体验。而MySQL作为广泛使用的关系型数据库&#xff0c;随着数据量和并发请求的增长&#xff0c;其性能问题也日益突出。今天我们将深入探讨如何设计一套高效的MySQL性能测试方案&#xff0c;帮助你精准…

cv::intersectConvexConvex返回其中一个输入点集,两个点集不相交

问题&#xff1a;cv::intersectConvexConvex返回其中一个输入点集&#xff0c;但两个点集并不相交 版本&#xff1a;opencv 3.1.0 git上也有人反馈了intersectConvexConvex sometimes returning one of the input polygons in case of empty intersection #10044 是凸包嵌套判…

【学习笔记】SAP ABAP——内表

内表定义 ​ 内表是SAP ABAP中最具有影响力且最重要的功能之一&#xff0c;简而言之&#xff0c;用一句话概括内表的定义就是&#xff1a;***内表是可以在程序内部定义并且使用的表&#xff0c;属于本地表。***如下图展示出了参照数据库表sflight定义的内表的结构 内表与数据库…

MinerU容器构建教程

一、介绍 MinerU作为一款智能数据提取工具&#xff0c;其核心功能之一是处理PDF文档和网页内容&#xff0c;将其中的文本、图像、表格、公式等信息提取出来&#xff0c;并转换为易于阅读和编辑的格式&#xff08;如Markdown&#xff09;。在这个过程中&#xff0c;MinerU需要利…

[产品管理-66]:七步法创新工具:SCAMPER法,也被称为奔驰法,一种创新思考工具,帮助我们基于现有的产品找到产品创新突破的方向

SCAMPER法&#xff0c;也被称为奔驰法&#xff0c;是一种创新思考工具&#xff0c;由美国心理学家罗伯特艾伯尔&#xff08;也有说法是教育家和创新思考专家鲁伯特普里斯科特&#xff09;提出。这种检核表主要藉几个字的代号或缩写&#xff0c;代表七种改进或改变的方向&#x…

算法求解(C#)-- 寻找包含目标字符串的最短子串算法

1. 引言 在字符串处理中&#xff0c;我们经常需要从一个较长的字符串中找到包含特定目标字符串的最短子串。这个问题在文本搜索、基因序列分析等领域有着广泛的应用。本文将介绍一种高效的算法来解决这个问题。 2. 问题描述 给定一个源字符串 source 和一个目标字符串 targe…

IDEA启动提示Downloading pre-built shared indexes

Download pre-built shared indexes Reduce the indexing time and CPU load with pre-built JDK shared indexes 翻译&#xff1a; 下载预构建的共享索引 使用预构建的JDK共享索引减少索引时间和CPU负载. 使用预构建的JDK共享索引可以显著减少索引构建时间和CPU负载&#xf…

【DM系列】DM 集成 JDBC 开发指南

前言 数据库访问是数据库应用系统中非常重要的组成部分&#xff0c;DM 作为一个通用数据库管理系统&#xff0c;提供了多种数据库访问接口&#xff0c;包括 ODBC、JDBC、DPI 等方式。本开发指南详细介绍了 DM 的各种访问接口、相应开发环境的配置、以及一些开发用例。本指南的主…

处理PhotoShopCS5和CS6界面字体太小

处理PhotoShop CS6界面字体太小 背景&#xff1a;安装PhotoShop CS6后发现无法调大字体大小&#xff0c;特别是我的笔记本14寸的&#xff0c;显示的字体小到离谱。 百度好多什么降低该电脑分辨率&#xff0c;更改电脑的显示图标大小&#xff0c;或者PS里的首选项中的界面设置。…

【JavaEE进阶】Spring AOP 原理

在之前的博客中 【JavaEE进阶】Spring AOP使用篇_aop多个切点-CSDN博客 我们主要学习了SpringAOP的应用, 接下来我们来学习SpringAOP的原理, 也就是Spring是如何实现AOP的. SpringAOP 是基于动态代理来实现AOP的,咱们学习内容主要分以下两部分 1.代理模式 2.Spring AOP源码剖…

基于springboot+vu的二手车交易系统(全套)

一、系统架构 前端&#xff1a;vue | element-ui | html 后端&#xff1a;springboot | mybatis-plus 环境&#xff1a;jdk1.8 | mysql | maven | nodejs 二、代码及数据库 三、功能介绍 01. web端-首页1 02. web端-首页2 03. web端-注册 04. web端-登录 05. w…

macOS开发环境配置与应用开发(详细讲解)

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 1. 引言 macOS作为Apple公司推出的桌面操作系统&#xff0c;以其稳定性、优雅的用户界面和强大的开发工具吸引了大量开发者。对于…

TinyVue v3.19.0 正式发布!Tree 组件终于支持虚拟滚动啦!UI 也升级啦,更更符合现代审美~

你好&#xff0c;我是 Kagol&#xff0c;个人公众号&#xff1a;前端开源星球。 我们非常高兴地宣布&#xff0c;2024年10月28日&#xff0c;TinyVue 发布了 v3.19.0 &#x1f389;。 本次 3.19.0 版本主要有以下重大变更&#xff1a; 所有组件全面升级到 OpenTiny Design 新…

鸿蒙进阶篇-type、typeof、类

“在科技的浪潮中&#xff0c;鸿蒙操作系统宛如一颗璀璨的新星&#xff0c;引领着创新的方向。作为鸿蒙开天组&#xff0c;今天我们将一同踏上鸿蒙基础的探索之旅&#xff0c;为您揭开这一神奇系统的神秘面纱。” 各位小伙伴们我们又见面了,我就是鸿蒙开天组,下面让我们进入今…

JavaWeb合集23-文件上传

二十三 、 文件上传 实现效果&#xff1a;用户点击上传按钮、选择上传的头像&#xff0c;确定自动上传&#xff0c;将上传的文件保存到指定的目录中&#xff0c;并重新命名&#xff0c;生成访问链接&#xff0c;返回给前端进行回显。 1、前端实现 vue3AntDesignVue实现 <tem…

1.62亿元!812个项目立项!上海市2024年度“科技创新行动计划”自然科学基金项目立项

本期精选SCI&EI ●IEEE 1区TOP 计算机类&#xff08;含CCF&#xff09;&#xff1b; ●EI快刊&#xff1a;最快1周录用&#xff01; 知网(CNKI)、谷歌学术期刊 ●7天录用-检索&#xff08;100%录用&#xff09;&#xff0c;1周上线&#xff1b; 免费稿件评估 免费匹配期…

Flink安装和Flink CDC实现数据同步

一&#xff0c;Flink 和Flink CDC 1&#xff0c; Flink Apache Flink是一个框架和分布式处理引擎&#xff0c;用于对无界和有界数据流进行有状态计算。 中文文档 Apache Flink Documentation | Apache Flink 官方文档 &#xff1a;https://flink.apache.org Flink 中文社区…

VBA高级应用30例应用3在Excel中的ListObject对象:插入行和列

《VBA高级应用30例》&#xff08;版权10178985&#xff09;&#xff0c;是我推出的第十套教程&#xff0c;教程是专门针对高级学员在学习VBA过程中提高路途上的案例展开&#xff0c;这套教程案例与理论结合&#xff0c;紧贴“实战”&#xff0c;并做“战术总结”&#xff0c;以…

windows运行ffmpeg的脚本报错:av_ts2str、av_ts2timestr、av_err2str => E0029 C4576

问题描述 我目前的环境是&#xff1a; 编辑器&#xff1a; Microsoft Visual Studio Community 2022 (64 位) 运行的脚本是ffmpeg自带的remux样例&#xff0c;只不过我想用c语言执行这个样例。在执行的过程中报错如下图&#xff1a; C4576 后跟初始值设定项列表的带圆括…

如何利用 Python 的爬虫技术获取淘宝天猫商品的价格信息?

以下是使用 Python 的爬虫技术获取淘宝天猫商品价格信息的两种常见方法&#xff1a; 方法一&#xff1a;使用 Selenium 一、环境准备&#xff1a; 安装 selenium 库&#xff1a;在命令行中运行 pip install selenium。下载浏览器驱动&#xff1a;如 ChromeDriver&#xff08;确…