【数据结构】C语言实现链式二叉树(附完整运行代码)

举报
修修修也 发表于 2024/09/30 16:46:17 2024/09/30
【摘要】 ​ 🦄个人主页:修修修也 🎏所属专栏:数据 结 构 ⚙️操作环境:Visual Studio 2022​编辑目录一.了解 项 目功能 二. 项 目功能演示 三.逐步 实现项 目功能模 块 及其 逻辑详 解 1. 实现链 式二叉 树 程序菜 单 2. 实现链 式二叉 树 程序功能可循 环 使用 3. 实现链 式二叉 树 的新 结 点 创 建 4. 实现链 式二叉 树 的先序建 树 5. 实...

 

🦄个人主:修修修也

🎏所属专栏:数据

⚙️操作:Visual Studio 2022

​编辑


一.了解 目功能

二. 目功能演示

三.逐步 实现项 目功能模 及其 逻辑详

1. 实现链 式二叉 程序菜

2. 实现链 式二叉 程序功能可循 使用

3. 实现链 式二叉 的新

4. 实现链 式二叉 的先序建

5. 实现链 式二叉 的判空

6. 实现链 式二叉 的先序遍

7. 实现链 式二叉 的中序遍

8. 实现链 式二叉 的后序遍

9. 实现链 式二叉 序遍

10. 实现链 式二叉 的叶子 点数

11. 实现链 式二叉 左孩子 点数

12. 实现链 式二叉 右孩子 点数

13. 实现链 式二叉 树节 点数

14. 实现链 式二叉 高度

15. 实现链 式二叉 树查询 层结 点个数

16. 实现链 式二叉 树查询 点是否存在

17. 实现链 式二叉 判断是否 完全二叉

18. 实现 转链 式二叉

19. 实现链 式二叉 销毁

四. 目完整代

BTree.c文件

 Queue.c 文件

Queue.h文件

结语


一.了解目功能

在本次项目中我们的目标是实现一个式二叉:

式二叉使用动态内存分配空,可以用来任意数量的同型数据.

二叉树结(BTNode)需要包含三个要素:左孩子指left,数据域data,右孩子指right.

二叉树结点(BTNode)逻辑结构如下:

​编辑

 式二叉程序提供的功能有:

1. 二叉的先序建.

2. 二叉的新.

3. 二叉的判空

4. 二叉的先序遍

5. 二叉的中序遍

6. 二叉的后序遍

7. 二叉序遍

8. 二叉的叶子点数

9. 二叉的左孩子点数

10. 二叉的右孩子点数

11. 二叉点数

12. 二叉的高度

13. 查询二叉点个数

14. 查询点是否在二叉

15. 查询是否是完全二叉

16. 二叉

17. 销毁二叉


二.目功能演示

要编写一个式二叉树项,首先要明确想要达到的效果是什么,下面我将用vs2022 编译器来为大家演示一下式二叉程序运行时的样子:


C语言实现链式二叉树程序功能演示


三.逐步实现项目功能模及其逻辑详

通过第二部分对项目功能的介绍,我们已经对式二叉的功能有了大致的了解,虽然看似需要实现的功能很多,貌似一时间不知该如何下手,但我们可以分步分模来分析目的流程,最后再将各部分行整合,所以大家不用担心,跟着我一步一步分析吧!


!!!注意,部分的代只是详细某一部分的实现逻辑,故可能会减一些与部分不相关的代以便大家理解,需要看或拷完整详细的朋友可以移步本文第四部分。

为直观分析式二叉中的递归思路,在后续的功能实现部分,我会繁使用下面画函数递归展开,大家可以先熟悉一下这棵二叉树,我们马上就开始实现具体的功能:

​编辑


1.实现链式二叉程序菜

菜单部分的逻辑比较简单,就是利用Cprintf函数打印出这个界面即可。但要注意序要和后switch...case句的分支相,以免导致后续的问题.基础问题就不过多赘述了,代码如下:

该部分功能实现代码如下: 

//菜单二叉树

void BTMenu()

{

    printf("****************************************\n");

    printf("******请选择要进行的操作 ******\n");

    printf("******1.先序建树 ******\n");

    printf("******2.查询树是否为空 ******\n");

    printf("******3.树的先序遍历 ******\n");

    printf("******4.树的中序遍历 ******\n");

    printf("******5.树的后序遍历 ******\n");

    printf("******6.树的层序遍历 ******\n");

    printf("******7.树的叶子节点数 ******\n");

    printf("******8.树的左孩子节点个数 ******\n");

    printf("******9.树的右孩子节点个数 ******\n");

    printf("******10.树的节点个数 ******\n");

    printf("******11.树的高度 ******\n");

    printf("******12.查询树某层的节点个数 ******\n");

    printf("******13.查询结点是否在树中 ******\n");

    printf("******14.查询树是否是完全二叉树 ******\n");

    printf("******15.翻转此树 ******\n");

    printf("******0.退出二叉树程序 ******\n");

    printf("****************************************\n");

    printf("请选择:>");

}


2.实现链式二叉程序功能可循使用

由于我们要实现式二叉的功能可以反复使用的逻辑,且至少在一开始执行一次,因此我们选择do...while的循环语来实现这一部分的逻辑.

该部分功能实现代码如下:

int main()

{

    BTNode* root = NULL;




    int swi = 0;

    do

    {

        BTMenu();

        scanf("%d", &swi);

        switch (swi)

        {

        case 0:

            TreeDestory(root); // 释放树内存

            printf("您已退出程序:>\n");

            break;




        case 1:

            printf("请输入树:>(以'#'表示空孩子)\n");

            char a[100];

            scanf("%s", a);

            int i = 0;

            root = CreatTree(a, &i);

            printf("已成功建树:>\n");




            break;




        case 2:

            if (BTEmpty(root) == true) //判断树空

                printf("当前树为空\n");

            else

                printf("当前树不为空\n");




            break;




        case 3:

            printf("先序遍历此树: ");

            PreOrder(root);

            printf("\n");




            break;




        case 4:

            printf("中序遍历此树: ");

            InOrder(root);

            printf("\n");




            break;




        case 5:

            printf("后序遍历此树: ");

            PostOrder(root);

            printf("\n");




            break;




        case 6:

            printf("层序遍历此树: ");

            LevelOrder(root);

            printf("\n");




            break;




        case 7:

            printf("此树的叶子节点数有: %d\n", BinaryTreeLeafSize(root));




            break;




        case 8:

            printf("此树的左孩子节点数有: %d\n", BinaryTreeLLeafSize(root));




            break;




        case 9:

            printf("此树的右孩子节点数有: %d\n", BinaryTreeRLeafSize(root));




            break;




        case 10:

            printf("此树的节点数有:%d\n", TreeSize(root));




            break;




        case 11:

            printf("此树的高度为:%d\n", TreeHeight(root));




            break;




        case 12:

            printf("请输入你要查询的层数:>");

            int k = 0;

            scanf("%d", &k);




            printf("此树第%d层的节点数有:%d\n",k,TreeKLevel(root,k));




            break;




        case 13:

            printf("请输入你要查询的结点:>");

            setbuf(stdin, NULL);//之前键盘缓冲区有污染,该函数作用是清空键盘缓冲区

            BTDataType x = 0;

            scanf("%c", &x);

            //二叉树查找值为x的结点

            if (BinaryTreeFind(root, x) != NULL)

            {

                printf("结点%c在树中:>\n",x);

            }

            else

            {

                printf("结点%c不在树中:<\n",x);

            }

            

            break;




        case 14:

            if (TreeComplete(root))

            {

                printf("该树是完全二叉树:>\n");

            }

            else

            {

                printf("该树不是完全二叉树:<\n");

            }




            break;

            

        case 15:

            root = InvertTree(root);

            printf("翻转成功:>\n");

            printf("前序遍历结果为:");

            PreOrder(root);

            printf("\n");




            break;




        default:

            printf("输入错误,请重新输入\n");




            break;

        }

    } while (swi);

    return 0;

}


3.实现链式二叉的新

创建链式二叉树点的构体应该包括:数据的数据域data,以及左孩子点地址的指left,存右孩子点地址的指right.

示如下:

​编辑

因此我们BTNode构体时应由一个数据成员类型及两个指向该结构体的构体的指针组.

了解了式二叉点构造后,建新就和之前单链表中对新结点的处理方法相同了,

具体思路如下:

1. 使用malloc动态开辟点空

2. 对结构体内容行初始化

3. 理完,返回

该部分代码实现如下:

//获取二叉树结点

BTNode* BuyNode(BTDataType x)

{

    BTNode* node = (BTNode*)malloc(sizeof(BTNode));

    if (node == NULL)

    {

        perror("malloc fail::");

        return NULL;

    }




    node->data = x;

    node->left = NULL;

    node->right = NULL;




    return node;

}


4.实现链式二叉的先序建

先序建部分,我们采用的思路是:

1. 先在主函数接收先序排列的建字符串

2. 再将其入建函数递归

我们按照最开始画的那颗树先前序遍历树:

​编辑

我们给函数入我前序遍得到的字符串,此时就可以画出前序建树时的函数递归展开:

​编辑

该部分实现代码如下:

//前序建树

BTNode* CreatTree(char* a, int* pi)

{

    

    if (a[(*pi)] == '#') //不是#不++!

    {

        (*pi)++;

        return NULL;

    }




    BTNode* root = BuyNode(a[(*pi)]);




    (*pi)++;

    root->left = CreatTree(a, pi);

    root->right = CreatTree(a, pi);




    return root;

}




//主函数部分调用建树逻辑

case 1:

         printf("请输入树:>(以'#'表示空孩子)\n");

        char a[100];

        scanf("%s", a);

        int i = 0;

        root = CreatTree(a, &i);

        printf("已成功建树:>\n");




        break;

5.实现链式二叉的判空

链式二叉树的判空逻辑较为简单,只需要返回点的状即可.

该部分实现代码如下:

//判断树空

bool BTEmpty(BTNode* root)

{

        return (!root);

}


6.实现链式二叉的先序遍

先序遍的思路是:

1. 访问

2. 递归访问左子

3. 递归访问右子

 我们画一下先序遍的函数递归展开:

​编辑

该部分代码实现如下:

//前序遍历

void PreOrder(BTNode* root)

{

    if (root == NULL)

    {

        printf("NULL ");

        return;

    }




    printf("%c ", root->data);

    PreOrder(root->left);

    PreOrder(root->right);

}


7.实现链式二叉的中序遍

中序遍的思路是:

1. 递归访问左子

2. 访问

3. 最后递归访问右子

该部分递归展开图于先序遍历类似,故不作展示,代码实现如下:

//中序遍历

void InOrder(BTNode* root)

{

    if (root == NULL)

    {

        printf("NULL ");

        return;

    }




    InOrder(root->left);

    printf("%c ", root->data);

    InOrder(root->right);

}


8.实现链式二叉的后序遍

后序遍的思路是:

1. 递归访问左子

2. 递归访问右子

3. 最后访问

该部分递归展开图于先序遍历类似,故不作展示,代码实现如下:

//后序遍历

void PostOrder(BTNode* root)

{

    if (root == NULL)

    {

        printf("NULL ");

        return;

    }




    PostOrder(root->left);

    PostOrder(root->right);

    printf("%c ", root->data);

}


9.实现链式二叉序遍

实现序遍的思路为(借助实现):

1. 将根点入

2. 如果点不,将点不空的孩子入

3. 访问队首元素并将其出

注:因在之前的文章中我经实现过链队列程序了,所以在部分我不涉及链队列的实现,而是直接使用.

 序遍算法演示如下:

​编辑

该部分实现代码如下(链队列的实现在文末的两个Queue文件中):

//层序遍历(借助队列)

void LevelOrder(BTNode* root)

{

    Que q;

    QueueInit(&q);




    if (root)

        QueuePush(&q, root);




    while (!QueueEmpty(&q))

    {

        BTNode* front = QueueFront(&q);

        QueuePop(&q);

        printf("%c ", front->data);

        if (front->left != NULL)

        {

            QueuePush(&q, front->left);

        }

        if (front->right != NULL)

        {

            QueuePush(&q, front->right);

        }

    }




    QueueDestroy(&q);

}


10.实现链式二叉的叶子点数

叶子点的上我们采用递归分治的思想,即

点的叶子点数=左子的叶子点数+右子的叶子点数.

当然,叶子点的判断条件根存在且左右子.

函数的递归展开如下:

​编辑

该部分代码实现如下:

//叶子节点数

int BinaryTreeLeafSize(BTNode* root)

{

    if (root == NULL)

        return 0;




    if (root->left==NULL && root->right==NULL)//左右子树都为空就是叶子结点

    {

        return 1;

    }

    return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);//返回每颗子树的左右叶子节点数

}


11.实现链式二叉左孩子点数

左孩子点的上我们同样采用递归分治的思想,即

点的左孩子点数=左子的左孩子点数+右子的左孩子点数.

当然,左孩子点的判断条件根存在且左子.

该函数的递归展开和叶子节点计算类似,这里就不赘述了,代码实现如下:

//左孩子节点数

int BinaryTreeLLeafSize(BTNode* root)

{

    if (root == NULL)

        return 0;

    if (root->left != NULL)

        return BinaryTreeLLeafSize(root->left) + BinaryTreeLLeafSize(root->right)+1;

    else

        return BinaryTreeLLeafSize(root->left) + BinaryTreeLLeafSize(root->right);

}


12.实现链式二叉右孩子点数

右孩子点的上我们同样采用递归分治的思想,即

点的右孩子点数=左子的右孩子点数+右子的右孩子点数.

当然,右孩子点的判断条件点存在且右子.

该函数的递归展开和叶子节点计算类似,这里就不赘述了,代码实现如下:

//右孩子节点数

int BinaryTreeRLeafSize(BTNode* root)

{

    if (root == NULL)

        return 0;

    if (root->right != NULL)

        return BinaryTreeRLeafSize(root->left) + BinaryTreeRLeafSize(root->right)+1;

    else

        return BinaryTreeRLeafSize(root->left) + BinaryTreeRLeafSize(root->right);

}


13.实现链式二叉树节点数

点的上我们同样采用递归分治的思想,即

点的点数=左子点数+右子点数.

当然,点的判断条件点存在.

该函数的递归展开和叶子节点计算类似,这里就不赘述了,代码实现如下:

//树的结点个数

int TreeSize(BTNode* root)

{

    if (root == NULL)

        return 0;

    else

        return TreeSize(root->left) + TreeSize(root->right) + 1;//返回左子树个数和右子树个数加上自己


    //return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;

    //从这条语句里体会分治的思想

}


14.实现链式二叉高度

二叉的高度上我们同样采用递归分治的思想,即

二叉的高度左子和右子高的那个高度加上根自己的高度,即

二叉的高度=左子的高度>右子的高度?左子高度+1:右子高度+1.

函数的递归展开如下:​编辑

该部分代码实现如下:

//树高

int TreeHeight(BTNode* root)

{

    if (root == NULL)

        return 0;


    int leftHeight = TreeHeight(root->left);

    int rightHeight = TreeHeight(root->right);


    return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1 ;

    //返回左子树和右子树高的那个并加上自己那份

}


15.实现链式二叉树查询层结点个数

层结点的我们同样采用递归分治的思想,即

点的K层节点数=左子K层节点数+右子K层节点数.

当然,K层结点的判断条件在K点存在.

该函数的递归展开和高度计算类似,这里就不赘述了,代码实现如下:

//层结点个数

int TreeKLevel(BTNode* root, int k)

{

    assert(k > 0);


    if (root == NULL) //思路是,对每个根结点分别求左子树第k层的结点+右子树第k层的结点

        return 0;


    //如果在k层,且不为空,则就是k层的有效结点

    if (k == 1)

        return 1;


    return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);

}


16.实现链式二叉树查询点是否存在

查询点是否存在我们同样采用递归分治的思想,即

是否存在该结取决于左子是否存在该节或右子是否存在该节,

中是否存在该结 = 左子是否存在该节 || 右子是否存在该节

我们采取后序遍的思想,从叶子点逐传查,如果没找到,就级传上空,如果找到了,就该节点逐级传到根.

只要左右子其中有一个存在,那中就是存在该结的.

该部分代码实现如下:

//二叉树查找值为x的结点

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)

{

    if (root == NULL)

        return NULL;


    if (root->data == x)

        return root;

    //找到了就逐级传回


    BTNode* lret = BinaryTreeFind(root->left, x);

    if (lret)

    {

        return lret;

    }


    BTNode* rret = BinaryTreeFind(root->right, x);

    if (rret)

    {

        return rret;

    }


    return NULL;

}


17.实现链式二叉判断是否完全二叉

我们判断二叉是否完全二叉的思路是利用完全二叉的性:

若完全二叉为满二叉,必定连续在最后一的靠右部分.

如下图所示,线所表示的是空:​编辑

因此我们利用序遍的思路,将所有点的空孩子也入,当完全二叉到第一个空后面一定全,如果后面有非空,那么这颗树就不是完全二叉.

该部分代码实现如下(实现链队列部分在文末的Queue文件中):

//判断一棵树是否是完全二叉树

bool TreeComplete(BTNode* root)

{

    //完全二叉树按层序走,非空结点一定是连续的(出过的结点的空子树也被无形中带入队了,不用担心结点在后面没有入队)

    Que q;

    QueueInit(&q);

    if (root)

        QueuePush(&q, root);


    while (!QueueEmpty(&q))

    {

        BTNode* front = QueueFront(&q);

        QueuePop(&q);

        

        if (front==NULL)

        {

            break;

        }

        else

        {

            QueuePush(&q, front->left);

            QueuePush(&q, front->right);

        }

    }


    //判断是不是完全二叉树(即出队过程中剩余元素有没有非空的结点)

    while (!QueueEmpty(&q))

    {

        BTNode* front = QueueFront(&q);

        QueuePop(&q);


        //front不为空,就为真,就返回假

        if (front)

        {

            QueueDestroy(&q);

            return false;

        }

    }


    QueueDestroy(&q);

    return true;

}


18.实现转链式二叉

二叉我们同样采用递归分治的思想,即

二叉=翻左子+翻右子.

我们采用后序遍的思想,最后再翻点的左右子

该部分代码实现如下:

//翻转二叉树

BTNode* InvertTree(BTNode* root)

{

    if (root == NULL)

        return NULL;

    BTNode* tmp = InvertTree(root->right);

    root->right = InvertTree(root->left);

    root->left = tmp;

    return root;

}


19.实现链式二叉销毁

二叉销毁我们采用后序递归的思想,即:销毁左右子,销毁

该部分代码实现如下:

//销毁树

void TreeDestory(BTNode* root)

{

    if (root == NULL)

        return;

    //递归后序销毁

    TreeDestory(root->left);

    TreeDestory(root->right);

    free(root);

}


四.目完整代

我们将程序运行的代码分别在三个工程文件中编辑,完整代码如下:

BTree.c文件

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

#include<assert.h>

#include<stdlib.h>

#include<stdbool.h>

#include"Queue.h"




typedef char BTDataType;




typedef struct BinaryTreeNode

{

    BTDataType data;

    struct BinarytreeNode* left;

    struct BinarytreeNode* right;

}BTNode;







//获取二叉树结点

BTNode* BuyNode(BTDataType x)

{

    BTNode* node = (BTNode*)malloc(sizeof(BTNode));

    if (node == NULL)

    {

        perror("malloc fail::");

        return NULL;

    }




    node->data = x;

    node->left = NULL;

    node->right = NULL;




    return node;

}







//前序建树

BTNode* CreatTree(char* a, int* pi)

{

    

    if (a[(*pi)] == '#') //不是#不++!

    {

        (*pi)++;

        return NULL;

    }




    BTNode* root = BuyNode(a[(*pi)]);




    (*pi)++;

    root->left = CreatTree(a, pi);

    root->right = CreatTree(a, pi);




    return root;

}







//前序遍历

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 PostOrder(BTNode* root)

{

    if (root == NULL)

    {

        printf("NULL ");

        return;

    }




    PostOrder(root->left);

    PostOrder(root->right);

    printf("%c ", root->data);

}







//树的结点个数

int TreeSize(BTNode* root)

{

    if (root == NULL)

        return 0;

    else

        return TreeSize(root->left) + TreeSize(root->right) + 1;//返回左子树个数和右子树个数加上自己




    //return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;

    //从这条语句里体会分治的思想

}




//树高

int TreeHeight(BTNode* root)

{

    if (root == NULL)

        return 0;




    int leftHeight = TreeHeight(root->left);

    int rightHeight = TreeHeight(root->right);




    return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1 ;

    //返回左子树和右子树高的那个并加上自己那份

}







//层结点个数

int TreeKLevel(BTNode* root, int k)

{

    assert(k > 0);




    if (root == NULL) //思路是,对每个根结点分别求左子树第k层的结点+右子树第k层的结点

        return 0;




    //如果在k层,且不为空,则就是k层的有效结点

    if (k == 1)

        return 1;




    return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);

}







//二叉树查找值为x的结点

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)

{

    if (root == NULL)

        return NULL;




    if (root->data == x)

        return root;

    //找到了就逐级传回




    BTNode* lret = BinaryTreeFind(root->left, x);

    if (lret)

    {

        return lret;

    }




    BTNode* rret = BinaryTreeFind(root->right, x);

    if (rret)

    {

        return rret;

    }




    return NULL;

}







//层序遍历(借助队列)

void LevelOrder(BTNode* root)

{

    Que q;

    QueueInit(&q);




    if (root)

        QueuePush(&q, root);




    while (!QueueEmpty(&q))

    {

        BTNode* front = QueueFront(&q);

        QueuePop(&q);

        printf("%c ", front->data);

        if (front->left != NULL)

        {

            QueuePush(&q, front->left);

        }

        if (front->right != NULL)

        {

            QueuePush(&q, front->right);

        }

    }




    QueueDestroy(&q);

}




//判断一棵树是否是完全二叉树

bool TreeComplete(BTNode* root)

{

    //完全二叉树按层序走,非空结点一定是连续的(出过的结点的空子树也被无形中带入队了,不用担心结点在后面没有入队)

    Que q;

    QueueInit(&q);

    if (root)

        QueuePush(&q, root);




    while (!QueueEmpty(&q))

    {

        BTNode* front = QueueFront(&q);

        QueuePop(&q);

        

        if (front==NULL)

        {

            break;

        }

        else

        {

            QueuePush(&q, front->left);

            QueuePush(&q, front->right);

        }

    }




    //判断是不是完全二叉树(即出队过程中剩余元素有没有非空的结点)

    while (!QueueEmpty(&q))

    {

        BTNode* front = QueueFront(&q);

        QueuePop(&q);




        //front不为空,就为真,就返回假

        if (front)

        {

            QueueDestroy(&q);

            return false;

        }

    }




    QueueDestroy(&q);

    return true;

}







//销毁树

void TreeDestory(BTNode* root)

{

    if (root == NULL)

        return;

    //递归后序销毁

    TreeDestory(root->left);

    TreeDestory(root->right);

    free(root);

}







//叶子节点数

int BinaryTreeLeafSize(BTNode* root)

{

    if (root == NULL)

        return 0;




    if (root->left==NULL && root->right==NULL)//左右子树都为空就是叶子结点

    {

        return 1;

    }

    return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);//返回每颗子树的左右叶子节点数

}




//左孩子节点数

int BinaryTreeLLeafSize(BTNode* root)

{

    if (root == NULL)

        return 0;

    if (root->left != NULL)

        return BinaryTreeLLeafSize(root->left) + BinaryTreeLLeafSize(root->right)+1;

    else

        return BinaryTreeLLeafSize(root->left) + BinaryTreeLLeafSize(root->right);

}




//右孩子节点数

int BinaryTreeRLeafSize(BTNode* root)

{

    if (root == NULL)

        return 0;

    if (root->right != NULL)

        return BinaryTreeRLeafSize(root->left) + BinaryTreeRLeafSize(root->right)+1;

    else

        return BinaryTreeRLeafSize(root->left) + BinaryTreeRLeafSize(root->right);

}







//判断树空

bool BTEmpty(BTNode* root)

{

    return (!root);

}







//翻转二叉树

BTNode* InvertTree(BTNode* root)

{

    if (root == NULL)

        return NULL;

    BTNode* tmp = InvertTree(root->right);

    root->right = InvertTree(root->left);

    root->left = tmp;

    return root;

}







//菜单二叉树

void BTMenu()

{

    printf("****************************************\n");

    printf("******请选择要进行的操作 ******\n");

    printf("******1.先序建树 ******\n");

    printf("******2.查询树是否为空 ******\n");

    printf("******3.树的先序遍历 ******\n");

    printf("******4.树的中序遍历 ******\n");

    printf("******5.树的后序遍历 ******\n");

    printf("******6.树的层序遍历 ******\n");

    printf("******7.树的叶子节点数 ******\n");

    printf("******8.树的左孩子节点个数 ******\n");

    printf("******9.树的右孩子节点个数 ******\n");

    printf("******10.树的节点个数 ******\n");

    printf("******11.树的高度 ******\n");

    printf("******12.查询树某层的节点个数 ******\n");

    printf("******13.查询结点是否在树中 ******\n");

    printf("******14.查询树是否是完全二叉树 ******\n");

    printf("******15.翻转此树 ******\n");

    printf("******0.退出二叉树程序 ******\n");

    printf("****************************************\n");

    printf("请选择:>");

}







int main()

{

    BTNode* root = NULL;




    int swi = 0;

    do

    {

        BTMenu();

        scanf("%d", &swi);

        switch (swi)

        {

        case 0:

            TreeDestory(root); // 释放树内存

            printf("您已退出程序:>\n");

            break;




        case 1:

            printf("请输入树:>(以'#'表示空孩子)\n");

            char a[100];

            scanf("%s", a);

            int i = 0;

            root = CreatTree(a, &i);

            printf("已成功建树:>\n");




            break;




        case 2:

            if (BTEmpty(root) == true) //判断树空

                printf("当前树为空\n");

            else

                printf("当前树不为空\n");




            break;




        case 3:

            printf("先序遍历此树: ");

            PreOrder(root);

            printf("\n");




            break;




        case 4:

            printf("中序遍历此树: ");

            InOrder(root);

            printf("\n");




            break;




        case 5:

            printf("后序遍历此树: ");

            PostOrder(root);

            printf("\n");




            break;




        case 6:

            printf("层序遍历此树: ");

            LevelOrder(root);

            printf("\n");




            break;




        case 7:

            printf("此树的叶子节点数有: %d\n", BinaryTreeLeafSize(root));




            break;




        case 8:

            printf("此树的左孩子节点数有: %d\n", BinaryTreeLLeafSize(root));




            break;




        case 9:

            printf("此树的右孩子节点数有: %d\n", BinaryTreeRLeafSize(root));




            break;




        case 10:

            printf("此树的节点数有:%d\n", TreeSize(root));




            break;




        case 11:

            printf("此树的高度为:%d\n", TreeHeight(root));




            break;




        case 12:

            printf("请输入你要查询的层数:>");

            int k = 0;

            scanf("%d", &k);




            printf("此树第%d层的节点数有:%d\n",k,TreeKLevel(root,k));




            break;




        case 13:

            printf("请输入你要查询的结点:>");

            setbuf(stdin, NULL);//之前键盘缓冲区有污染,该函数作用是清空键盘缓冲区

            BTDataType x = 0;

            scanf("%c", &x);

            //二叉树查找值为x的结点

            if (BinaryTreeFind(root, x) != NULL)

            {

                printf("结点%c在树中:>\n",x);

            }

            else

            {

                printf("结点%c不在树中:<\n",x);

            }

            

            break;




        case 14:

            if (TreeComplete(root))

            {

                printf("该树是完全二叉树:>\n");

            }

            else

            {

                printf("该树不是完全二叉树:<\n");

            }




            break;

            

        case 15:

            root = InvertTree(root);

            printf("翻转成功:>\n");

            printf("前序遍历结果为:");

            PreOrder(root);

            printf("\n");




            break;




        default:

            printf("输入错误,请重新输入\n");




            break;

        }

    } while (swi);

    return 0;

}

 Queue.c 文件

#include"Queue.h"




void QueueInit(Que* pq)

{

    assert(pq);




    pq->head = pq->tail = NULL;

    pq->size = 0;




}

void QueueDestroy(Que* pq)

{

    assert(pq);




    QNode* cur = pq->head;

    while (cur)

    {

        QNode* next = cur->next;

        free(cur);

        cur = next;

    }

    pq->head = pq->tail = NULL;

    pq->size = 0;




}




void QueuePush(Que* pq, QDatatype x) //入队是尾插

{

    QNode* newnode = (QNode*)malloc(sizeof(QNode));

    if (newnode == NULL)

    {

        perror("malloc fail");

        return;

    }

    newnode->data = x;

    newnode->next = NULL;




    if (pq->head == NULL)//头插

    {

        assert(pq->tail == NULL);//head为空,tail不为空就出事了,队头为空但是队尾不为空

        

        pq->head = pq->tail = newnode;

        

    }

    else//尾插

    {

        pq->tail->next = newnode;

        pq->tail = newnode;

    }




    pq->size++;




}







void QueuePop(Que* pq)//出队是头删

{

    assert(pq);

    assert(!QueueEmpty(pq));//assert为假会终止程序




    QNode* cur = pq;




    if (pq->head->next == NULL)

    {

        free(pq->head);

        pq->head = pq->tail = NULL;

    }

    else

    {

        QNode* next = pq->head->next;

        free(pq->head);

        pq->head = next;

    }




    pq->size--;




}




int QueueSize(Que* pq)

{

    assert(pq);




    return pq->size;




}




bool QueueEmpty(Que* pq)//判空!为空返回真!

{

    assert(pq);




    return pq->size==0;

}




QDatatype QueueFront(Que* pq)

{

    assert(pq);

    assert(!QueueEmpty(pq));




    return pq->head->data;




}

QDatatype QueueBack(Que* pq)

{

    assert(pq);

    assert(!QueueEmpty(pq));




    return pq->tail->data;




}




void QMenu()

{

    printf("**********************************\n");

    printf("******请选择要进行的操作 ******\n");

    printf("******1.链队列入队 ******\n");

    printf("******2.链队列出队 ******\n");

    printf("******3.取队首元素 ******\n");

    printf("******4.取队尾元素 ******\n");

    printf("******5.队列判空 ******\n");

    printf("******6.查询当前队列长 ******\n");

    printf("******7.清空队列 ******\n");

    printf("******0.退出链队列程序 ******\n");

    printf("**********************************\n");

    printf("请选择:>");




}


Queue.h文件

#pragma once

#define _CRT_SECURE_NO_WARNINGS 1




#include<stdio.h>

#include<stdlib.h>

#include<stdbool.h>

#include<assert.h>




typedef struct BinaryTreeNode* QDatatype;




typedef struct QueueNode//一个是结点结构

{

    struct QueueNode* next;

    QDatatype data;

}QNode;







typedef struct Queue//一个是队列整体结构

{

    QNode* head;

    QNode* tail;

    int size ;

}Que;




void QueueInit(Que* pq);

void QueueDestroy(Que* pq);




void QueuePush(Que* pq,QDatatype x);

void QueuePop(Que* pq);




int QueueSize(Que* pq);




bool QueueEmpty(Que* pq);




QDatatype QueueFront(Que* pq);

QDatatype QueueBack(Que* pq);




void QMenu();


结语

希望式二叉实现详解能大家有所帮助,迎大佬留言或私信与我交流.

学海漫浩浩,我亦苦作舟!关注我,大家一起学,一起!

相关文章推荐

【数据 构】 C 实现顺 序表万字 (附完整运行代 )

【数据 构】 C 实现单链 表万字 (附完整运行代 )

【数据 构】 C 实现带头 双向循 环链 表万字 (附完整运行代 )

【数据 构】用 C 实现顺 (附完整运行代 )

【数据 构】 C 实现链队 (附完整运行代 )


​编辑

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。