【数据结构】二叉树的链式实现及遍历

2023-09-20 23:35:50


在这里插入图片描述

一、二叉树的遍历

后文所有代码中的二叉树结点:

typedef char BTDataType;
//二叉树结点结构体
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

1、前序遍历

前,中,后序遍历都可以采用分治递归的思想解决,将根节点和它的孩子结点分别处理。

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root)
{
    if (root == NULL)
    {
        printf("NULL ");
        return;
    }

    printf("%c ", root->data);
    BinaryTreePrevOrder(root->left);
    BinaryTreePrevOrder(root->right);
}

此处仅利用递归展开图分析前序遍历,中序和后序也是相同的思想:

在这里插入图片描述

在这里插入图片描述

2、中序遍历

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
    if (root == NULL)
    {
        printf("NULL ");
        return;
    }

    BinaryTreeInOrder(root->left);
    printf("%c ", root->data);
    BinaryTreeInOrder(root->right);
}

3、后序遍历

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
    if (root == NULL)
    {
        printf("NULL ");
        return;
    }

    BinaryTreePostOrder(root->left);
    BinaryTreePostOrder(root->right);
    printf("%c ", root->data);
}

4、层序遍历

层序遍历需要利用队列来进行,如果二叉树跟结点不为空,则让指向它的一个指针入队,然后将队头结点记录下来,先将它的值打印,然后判断它的左右孩子为非空则入队,然后删掉队头换下一个继续记录打印…直到队列为空则遍历完成。

例如对如图这个二叉树:

层序遍历结果为:12345
在这里插入图片描述
先将根节点1入队,打印1

在这里插入图片描述

然后将1的左右孩子2和3入队
在这里插入图片描述

删掉队头1,front换为2,打印2
在这里插入图片描述

然后将2的左孩子4入队
在这里插入图片描述

删掉队头2,front换为3,打印3
在这里插入图片描述

然后将3的右孩子5入队
在这里插入图片描述

… …

接着按这样打印4,5便完成了二叉树的层序遍历

在这里插入图片描述

程序代码利用了自己创建的队列,代码如下:

//层序遍历
void LevelOrder(BTNode* root)
{
    //创建队列
    Que q;
    QueueInit(&q);

    //如果根节点不为空,则放进队列
    if (root)
        QueuePush(&q, root);

    while (!QueueEmpty(&q))
    {
        //将队头打印
        BTNode* front = QueueFront(&q);
        printf("%c ", front->data);
        //判断front左右节点不为空则入队
        if (front->left)
            QueuePush(&q, front->left);

        if (front->right)
            QueuePush(&q, front->right);
        
        QueuePop(&q);
    }
    printf("\n");

    QueueDestroy(&q);
}

二、二叉树结点个数及高度

1、二叉树节点个数

采用分治法递归实现,当根节点为空时返回值为0,不为空则返回左右子树上的节点数加上自身1。

int BinaryTreeSize(BTNode* root)
{
    return root == NULL ? 0 : BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

2、二叉树叶子节点个数

采用分治法递归实现,根节点为空时返回0,当根节点没有孩子结点时说明它是叶子节点,返回1,其他情况时只需左右子树上的叶子节点相加即可。

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);
}

3、二叉树第k层节点个数

需要保证k大于0才可,当根节点为空,则返回0,当k等于1时只有一层一个节点,返回1,k>1时第k层节点数就相当于它左右孩子的第k-1层节点数相加。

int BinaryTreeLevelKSize(BTNode* root, int k)
{
    assert(k > 0);

    if (root == NULL)
    {
        return 0;
    }
    if (k == 1)
    {
        return 1;
    }
    return BinaryTreeLevelKSize(root->left, k - 1)
        + BinaryTreeLevelKSize(root->right, k - 1);
}

4、二叉树查找值为x的节点

跟节点为空则找不到返回NULL,当根节点的值为要找的值时返回该节点,不相等则分别判断它的左右孩子节点,直到找到为止。

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
    if (root == NULL)
    {
        return NULL;
    }
    if (root->data == x)
    {
        return root;
    }
    BTNode* ret = BinaryTreeFind(root->left,x);
    if (ret)
    {
        return ret;
    }
    return BinaryTreeFind(root->right, x);
}

三、二叉树创建及销毁

1、通过前序遍历数组创建二叉树

读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。

#include <stdio.h>
#include<stdlib.h>
typedef char BTDataType;

typedef struct BinaryTreeNode {
    BTDataType data;
    struct BinaryTreeNode* left;
    struct BinaryTreeNode* right;
} BTNode;
BTNode* BinaryTreeCreate(BTDataType* a, int* pi) {
    if (a[*pi] == '#') {
        ++*pi;
        return NULL;
    }

    BTNode* root = (BTNode*)malloc(sizeof(BTDataType));
    root->data = a[*pi];
    ++*pi;

    root->left = BinaryTreeCreate(a, pi);
    root->right = BinaryTreeCreate(a, pi);

    return root;
}
//中序遍历
void InOrder(BTNode* root)
{
    if(root==NULL)
    {
        return;
    }
    InOrder(root->left);
    printf("%c ",root->data);
    InOrder(root->right);
}
int main() {
    char a[100];
    scanf("%s",a);
    int pi=0;
    BTNode* root=BinaryTreeCreate(a, &pi);
    InOrder(root);
    return 0;
}

2、二叉树的销毁

void BinaryTreeDestory(BTNode* root)
{
    if (root == NULL)
    {
        return;
    }

    BinaryTreeDestory(root->left);
    BinaryTreeDestory(root->right);
    free(root);
}

3、判断是否为完全二叉树

在二叉树层序遍历的基础上修改一下,让空节点也进入队列,遍历时遇到空节点则退出,继续遍历如果结束前还有非空节点则不是完全二叉树。

int BinaryTreeComplete(BTNode* root)
{
    //创建队列
    Que q;
    QueueInit(&q);

    //如果根节点不为空,则放进队列
    if (root)
        QueuePush(&q, root);

    while (!QueueEmpty(&q))
    {
        BTNode* front = QueueFront(&q);
        if (front == NULL)
        {
            break;
        }
        QueuePush(&q, front->left);
        QueuePush(&q, front->right);
        QueuePop(&q);
    }
    //此时已经遇到空节点,如果再遇到非空节点则不是完全二叉树
    while (!QueueEmpty(&q))
    {
        BTNode* front = QueueFront(&q);
        if (front)
        {
            QueueDestroy(&q);
            return false;
        }
        QueuePop(&q);
    }

    QueueDestroy(&q);
    return true;
}

四、测试代码

手动构建一个如下图的二叉树,对代码进行测试:
在这里插入图片描述
测试结果应该为:

前序:123874569
中序:832715469
后序:837259641

是否为完全二叉树:0
节点数:9
叶子节点数:4

BTNode* BuyNode(BTDataType x)
{
    BTNode* node = (BTNode*)malloc(sizeof(BTNode));
    if (node == NULL)
    {
        perror("malloc fail");
        exit(-1);
    }

    node->data = x;
    node->left = NULL;
    node->right = NULL;

    return node;
}


int main()
{
    	// 手动构建
	BTNode* node1 = BuyNode('1');
	BTNode* node2 = BuyNode('2');
	BTNode* node3 = BuyNode('3');
	BTNode* node4 = BuyNode('4');
	BTNode* node5 = BuyNode('5');
	BTNode* node6 = BuyNode('6');
	BTNode* node7 = BuyNode('7');
	BTNode* node8 = BuyNode('8');
	BTNode* node9 = BuyNode('9');

	node1->left = node2;
	node1->right = node4;
	node2->left = node3;
	node4->left = node5;
	node4->right = node6;

	node2->right = node7;
	node3->left = node8;
	node6->right = node9;

    printf("前序遍历:");
    BinaryTreePrevOrder(node1);
	printf("\n");

    printf("中序遍历:");
    BinaryTreeInOrder(node1);
	printf("\n");

    printf("后序遍历:");
    BinaryTreePostOrder(node1);
	printf("\n");

    printf("层序遍历:");
    LevelOrder(node1);
    printf("\n");

    printf("BinaryTreeComplete:%d\n", BinaryTreeComplete(node1));
    printf("BinaryTreeSize:%d\n", BinaryTreeSize(node1));
    printf("BinaryTreeLeafSize:%d\n", BinaryTreeLeafSize(node1));

    BinaryTreeDestory(node1);
	node1 = NULL;

    return 0;
}

运行结果:

在这里插入图片描述
运行结果与预测结果一致。

更多推荐

Leetcode算法入门与数组丨4. 数组排序

文章目录1冒泡排序2选择排序3插入排序4归并排序5希尔排序6快速排序7堆排序8计数排序9桶排序10基数排序task05task061冒泡排序冒泡排序(BubbleSort)是一种简单的排序算法。它重复地遍历待排序的元素列表,一次比较相邻的两个元素,并按照顺序交换它们,直到整个列表排序完成。基本步骤下面是冒泡排序的基本步

【深度学习】 Python 和 NumPy 系列教程(十一):NumPy详解:3、数组数学(元素、数组、矩阵级别的各种运算)

目录一、前言二、实验环境三、NumPy0、多维数组对象(ndarray)多维数组的属性1、创建数组2、数组操作3、数组数学1.元素级别a.直接运算b.加法:np.add()函数c.减法:np.subtract()函数d.乘法:np.multiply()函数e.除法:np.divide()函数f.幂运算:np.power

WIFI6特性分析

特性介绍wifi6作为全新一代wifi协议,提供了更快速度,信道利用率更高,抗干扰能力更强,更高的频宽,更好的待机表现。下边是对比wifi456三代特性的区别:OFDMA:正交多频分址,提升物理媒介的并发通信能力。MU-MINO:多用户上传下载,提升多用处场景wifi速率160MHZ:拓展频段宽度TWT:休眠唤醒机制,

php外贸代购系统网站,淘宝代购系统,淘宝代购集运系统,海外代购系统

PHP外贸代购系统网站建设需要以下步骤:链接各大热门商城上的商品并自动获取参数,程序集成了淘宝、拍拍等大型热门商城抓取规则,可以直接一键代购上面的任何商品,自动获取相应的参数。确定网站功能,如:产品展示、在线购物、搜索引擎等。选择适合的数据库,例如MySQL、PostgreSQL等,存储网站的数据信息。根据目标用户的需

【leetcode 力扣刷题】栈—波兰式///逆波兰式相关知识和题目

波兰式、逆波兰式相关知识和题目波兰式、逆波兰式介绍常规表达式转换成逆波兰式==编程让常规表达式转换成逆波兰式==逆波兰式运算过程常规表达式转换成波兰式==编程让常规表达式转换成波兰式==波兰式运算过程150.逆波兰式表达式求值224.基本计算器227.基本计算器Ⅱ282.给表达式添加运算符波兰式、逆波兰式介绍我们常看到

计算机毕业设计 基于SpringBoot餐厅点餐系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌🍅文末获取源码联系🍅👇🏻精彩专栏推荐订阅👇🏻不然下次找不到哟————————————————计算机毕业设计题目《10

个人简历内容

简历个人信息专业技能熟悉Java基础,如集合、代理、反射等。了解Java多线程,了解JVM内存模型、常见GC算法、类加载机制。·#熟悉SSM+SpringBoot框架,熟悉AOP、IOC和SpringBoot自动配置原理,了解SpringMVC执行流程。熟悉MySQL数据库,熟悉InnoDB存储引擎、事务、MVCC机制

2023年云南省职业院校技能大赛中职组“网络安全”赛项样题

2023年云南省职业院校技能大赛中职组“网络安全”赛项样题一、竞赛时间总计:180分钟二、竞赛阶段竞赛阶段任务阶段竞赛任务竞赛时间分值A、B模块A-1登录安全加固180分钟200分A-2数据库加固A-3服务加固SSH\VSFTPDA-4防火墙策略B-1隐写术应用-B400分B-2内存取证B-3数据库渗透B-4Linux

信息检索与数据挖掘 | (二)布尔检索与倒排索引

文章目录📚词项-文档关联矩阵🐇相关名词🐇词项-文档关联矩阵的布尔查询处理📚倒排索引🐇关于索引🐇建立索引🐇基于倒排索引的布尔查询处理🐇查询优化📚字典数据结构🐇哈希表🐇各种树🐇B树vsB+树📚短语查询及含位置信息的倒排记录🐇二元词索引(Biwordindexes)🐇位置信息索引🐇混合索引机制

Hadoop学习总结(搭建Hadoop集群的安装准备)

目录一、安装jdk1、查看电脑中安装的jdk版本2、安装jdk173、配置path(配置jdk)4、对jdk8和jdk17版本做自由切换二、安装vmware三、安装centos7(虚拟机)四、虚拟机设置五、虚拟机网络配置1、查看NAT的网段2、修改主机名(1)修改虚拟机的hosts(2)修改虚拟机的hostname3、

Spring MVC 中的数据绑定和验证机制是什么,如何使用

在SpringMVC应用中,数据绑定和验证是非常重要的一部分,它们可以帮助我们将用户提交的数据绑定到Java对象上,并对数据进行验证,保证数据的正确性和可靠性。在SpringMVC中,数据绑定和验证机制都是通过注解来实现的。本文将介绍SpringMVC中的数据绑定和验证机制,以及如何使用它们。数据绑定数据绑定是将用户提

热文推荐