二叉树的创建
创建一颗二叉树,首先需要定义二叉树中节点的结构:
typedef int DataType;
typedef struct BTNode {
DataType data; //节点数据类型
struct BTNode* left; //左孩子
struct BTNode* right; //右孩子
}BTNode;
递归创建一颗二叉树,可以根据给定的先序遍历方式来进行创建:
BTNode* BTreeCreate(int arr[],int size,int* index)
{
BTNode* root = NULL;
//*index 用来确定插入位置,使用指针形式是为了操作外部实参,若直接使用 index 将会是实参的一份拷贝,并不能将实际的值传出函数
if (*index < size && arr[*index] != -1) {
root = BuyBTNode(arr[*index]); //先创建根
++(*index); //递归创建左右子树
root->left = BTreeCreate(arr, size,index);
++(*index);
root->right = BTreeCreate(arr, size, index);
}
return root;
}
二叉树求高度
二叉树的高度是指二叉树左右子树中最大的高度,因此求二叉树高度等价于求其子树最大高度+1 (+1 表示加上根节点)
int BinaryTreeHight(BTNode* root)
{
if (NULL == root)
return 0;
//先求子树高度
int leftHight = BinaryTreeHight(root->left);
int rightHight = BinaryTreeHight(root->right);
return leftHight > rightHight ? 1 + leftHight : 1 + rightHight;
}
二叉树中节点总数
求二叉树的节点总数等价于求根节点的左右子树中节点数的和+1:
int BinaryTreeSize(BTNode* root)
{
if (NULL == root)
return 0;
return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}
二叉树中叶子节点个数
二叉树叶子节点指的是没有左孩子也没有右孩子的节点:
int BinaryTreeLeafSize(BTNode*root)
{
if (NULL == root)
return 0;
if (root->left == NULL && root->right == NULL)
return 1;
return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}
二叉树第 K 层节点个数
int BinaryTreeLevelKSize(BTNode* root , int k)
{
if (NULL == root || k <= 0)
return 0;
if (1 == k)
return 1; //根节点
//求其子树(k-1)层中节点个数和
return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}
二叉树的销毁
二叉树的销毁需要操作的是外部实参的销毁,因此需要传递二级指针来接受二叉树根节点的位置:
void BinaryDestroy(BTNode** proot)
{
assert(proot);
if (*proot == NULL)
return;
BinaryDestroy(&(*proot)->left);
BinaryDestroy(&(*proot)->right);
free(*proot);
*proot = NULL;
}
二叉树中元素的查找
BTNode* BinaryTreeFind(BTNode* root, DataType x)
{
if (NULL == root)
return NULL;
if (root->data == x) //要查找的元素为根节点
return root;
BTNode* ret = NULL;
ret = BinaryTreeFind(root->left, x);
if (ret != NULL)
return ret;
return BinaryTreeFind(root->right, x);
}
二叉树的三种遍历
先序遍历
遍历顺序为: 根节点------》左子树-------》右子树
void PreOrder(BTNode* root)
{
if (NULL == root)
return;
printf("%d ", root->data);
PreOrder(root->left);
PreOrder(root->right);
}
中序遍历
遍历顺序为:左子树------》根节点-----》右子树:
void InOrder(BTNode* root)
{
if (NULL == root)
return;
InOrder(root->left);
printf("%d ", root->data);
InOrder(root->right);
}
后序遍历
遍历顺序为:左子树----》右子树------》根节点:
void PostOrder(BTNode* root)
{
if (NULL == root)
return;
PostOrder(root->left);
PostOrder(root->right);
printf("%d ", root->data);
}
二叉树的层序遍历
层序遍历需要借助队列来进行实现,需要依次保存每一层中的节点,并按顺序遍历各个根结点的左右子树:
void BinaryLevelOrder(BTNode* root)
{
if (NULL == root)
return;
//树不空情况下,需要借助队列来实现层序遍历
Queue q;
QueueInit(&q);
//根先入队,队不空,循环:
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
struct BTNode* cur = QueueFront(&q); //取队头元素
printf("%d ", cur->data);
if (cur->left != NULL) { //根的左孩子不空保存左孩子节点
QueuePush(&q, cur->left);
}
if (cur->right != NULL) //根的右孩子不空保存右孩子节点
QueuePush(&q, cur->right);
QueuePop(&q); //队头元素出队
}
QueueDestroy(&q);
printf("\n");
}
完全二叉树的判断
完全二叉树是指节点从上至下、从左至右的顺序排列,度为1的节点最多只有一个,且度为1的节点只有左孩子没有右孩子(具体概念理解参考本人上一篇博客:https://blog.csdn.net/weixin_46655027/article/details/127285421)
在完全二叉树的第一个不饱和节点之前的所有节点必须是饱和节点(度为2),之后的所有节点必须都没有孩子
因此判断一颗二叉树是否是完全二叉树需要利用二叉树的层序遍历来进行实现:
int BinaryTreeComplete(BTNode* root)
{
if (NULL == root)
return 1; //空树是完全二叉树
Queue q;
QueueInit(&q);
QueuePush(&q, root);
int flag = 0; //标记第一个不饱和节点
int TreeComplete = 1; //标记是完全二叉树
while (!QueueEmpty(&q)) {
BTNode* cur = QueueFront(&q);
QueuePop(&q);
if (flag) { //前边以及存在不饱和节点
if (cur->left || cur->right)
{
//此时的节点依旧不包含,说明不是完全二叉树
TreeComplete = 0;
break;
}
}
else {
if (cur->left && cur->right) {
QueuePush(&q, cur->left);
QueuePush(&q, cur->right);
}
else if (cur->left) {
//此时只有左孩子没有右孩子
QueuePush(&q, cur->left);
flag = 1;
}
else if (cur->right) {
//只有右孩子没有左孩子
break;
TreeComplete = 0; //不是完全二叉树
}
else {
//左右孩子都不存在
flag = 1;
}
}
}
QueueDestroy(&q);
return TreeComplete;
}
ps:二叉树的创建以及销毁、层序遍历需要更深一步理解,需要重点练习!!