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

news2025/2/27 23:56:47

文章目录

  • 一、二叉树的遍历
    • 1、前序遍历
    • 2、中序遍历
    • 3、后序遍历
    • 4、层序遍历
  • 二、二叉树结点个数及高度
    • 1、二叉树节点个数
    • 2、二叉树叶子节点个数
    • 3、二叉树第k层节点个数
    • 4、二叉树查找值为x的节点
  • 三、二叉树创建及销毁
    • 1、通过前序遍历数组创建二叉树
    • 2、二叉树的销毁
    • 3、判断是否为完全二叉树
  • 四、测试代码

在这里插入图片描述

一、二叉树的遍历

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

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

运行结果:

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

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

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

相关文章

基于SSM+Vue的乐购游戏商城系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

PaddleOCR ‘could not create a primitive descriptor for a reorder primitive‘异常处理

环境 paddlepaddle2.4.0 paddlehub2.3.1 问题描述 PaddleOCR 使用自己训练的模型时&#xff0c;抛出异常 could not create a primitive descriptor for a reorder primitive&#xff0c;且仅在开启MKL加速时报错&#xff0c;不开启MKL加速则不报错。 解决方案 通过查询pa…

笔记1-2:

一、磁荷与磁流的引入 麦克斯韦方程组&#xff1a; 引入磁荷和磁流的概念&#xff0c;上述方程可以写成对称形式&#xff1a; 磁荷和磁流实际上不存在&#xff0c;只具有某种等效意义&#xff0c;可以把某个区域中的电磁场看成是由一组等效磁型源所产生。 对于均匀和各向同性…

MACOS Ventura 本地安装HDFS 3.1.4

1、终端&#xff0c;输入第一条命令一直回车即可&#xff0c;然后将生成的将公钥内容写入到~/.ssh/authorized_keys中 ssh-keygen -t rsacat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys 2、系统登录-共享-远程登录&#xff0c;打开。如下&#xff1a; 3、官网下载安…

Learn Prompt-Prompt 高级技巧:AutoGPT

AutoGPT 是一个由Toran Richards创建的流行开源项目。它利用GPT4作为大脑&#xff0c;结合langchain的链接思想&#xff0c;连接各种工具和互联网资源&#xff0c;来完成人类给予的任务。您只需要设定一个目标&#xff0c;AutoGPT就会自主规划并逐步执行任务。如果遇到问题&…

IEEE PDF eXpress系统报错:TimesNewRoman PS-BoldMT, ItalicMT, PSM

问题&#xff1a; IEEE PDF eXpress系统报错&#xff1a;Errors: Font TimesNewRomanPS-BoldMT, TimesNewRomanPS-ItalicMT, TimesNewRomanPSMT is not embedded (137x on pages 2-6) 答案&#xff1a; 主要原因是PDF的字体嵌入问题&#xff0c;可以看到下图中没有报错中的字体…

JS Ajax 封装

ajax 封装 一、 什么是Ajax&#xff1f;二、 Ajax的优缺点&#xff1f;2.1 优点2.2 缺点 三、 Ajax的使用3.1 状态码3.2 xhr的基本使用3.3 ajax原生封装&#xff1a;3.3.1 触发GET请求&#xff1a;3.3.2 调用POST请求&#xff1a; 四、Ajax的约束 一、 什么是Ajax&#xff1f; …

zabbix实现钉钉报警

首先钉钉创建一个团队 自定义关键词 查看zabbix-server脚本存放的位置&#xff1a; [rootcontrolnode ~]# grep ^AlertScriptsPath /etc/zabbix/zabbix_server.conf AlertScriptsPath/usr/lib/zabbix/alertscripts zabbix server设置 在配置文件书写脚本目录vim /etc/za…

将 Ordinals 与比特币智能合约集成:第 2 部分

在上一篇文章中&#xff0c;我们展示了一种将 Ordinal 与智能合约集成的方法&#xff0c;即将Ordinal和合约放在同一个 UTXO 中。 今天&#xff0c;我们介绍了一种集成它们的替代方案&#xff0c;即它们位于单独的 UTXO 中。 作为展示&#xff0c;我们开发了一个智能合约&…

go语言操作数据库

1.10 GO连接MySQL 因为Go语言没有提供任何官方数据库驱动&#xff0c;所以需要安装第三方函数库。由于在github上安装&#xff0c;所以需要安装git软件&#xff0c;安装过程一直点击下一步即可。安装完成后需要配置环境变量 1.10.1 安装git git软件 安装完毕后&#xff0c;配…

基于ENC28J60+uIP1.0+STM32的UDP Server实现,以及主动发送数据,几个关键的问题可算整明白了!

ENC28J60&#xff0c;是一款SPI接口的以太网PHYMAC芯片&#xff0c;实现以太网物理层和MAC层硬件通信。uIP是一个TCP/IP软件协议栈&#xff0c;实现TCP、UDP、ARP、ICMP等网络协议。STM32F103RCT6通过SPI接口与ENC28J60通讯&#xff0c;并移植uIP协议&#xff0c;实现一个小型的…

数据分析回头看2——重复值检查/元素替换/异常值筛选

0、前言&#xff1a; 这部分内容是对Pandas的回顾&#xff0c;同时也是对Pandas处理异常数据的一些技巧的总结&#xff0c;不一定全面&#xff0c;只是自己在数据处理当中遇到的问题进行的总结。 1、当数据中有重复行的时候需要检测重复行&#xff1a; 方法&#xff1a;使用p…

BERT: 面向语言理解的深度双向Transformer预训练

参考视频&#xff1a; BERT 论文逐段精读【论文精读】_哔哩哔哩_bilibili 背景 BERT算是NLP里程碑式工作&#xff01;让语言模型预训练出圈&#xff01; 使用预训练模型做特征表示的时候一般有两类策略&#xff1a; 1. 基于特征 feature based &#xff08;Elmo&#xff09;…

优化系统报错提示信息,提高人机交互(二)

如果服务器接口报错&#xff0c;接口返回报错信息&#xff0c;是怎么实现的呢&#xff1f; 接口调用示例 controller代码 AllArgsConstructor RestController Slf4j public class DemoController {GetMapping("exceptionTest")public Result exceptionTest(Integer…

个人所思所想录

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;CSDN实力新星&#xff0c;后端开发两年经验&#xff0c;曾担任甲方技术代表&#xff0c;业余独自创办智源恩创网络科技工作室。会点点Java相关技术栈、帆软报表、低代码平台快速开…

优化系统报错提示信息,提高人机交互(一)

1、常规报错及处理 package com.example.demo.controller;import com.example.demo.service.IDemoService; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.w…

13基于PCA的人脸识别,程序已调通,可将自己的数据替换进行识别,得到识别准确率结果,MATLAB平台。

基于PCA的人脸识别&#xff0c;程序已调通&#xff0c;可将自己的数据替换进行识别&#xff0c;得到识别准确率结果&#xff0c;MATLAB平台。

DevSecOps内置安全保护

前言 随着DevOps的发展&#xff0c;DevOps大幅提升了企业应用迭代的速度。但同时&#xff0c;安全如果不能跟上步伐&#xff0c;不仅会抵消DevOps变革带来的提升&#xff0c;拖慢企业数字化转型进程&#xff0c;还会导致漏洞与风险不约而至。所以安全能力在全球范围内受到的重…

2023_Spark_实验十二:Spark高级算子使用

掌握Spark高级算子在代码中的使用 相同点分析 三个函数的共同点&#xff0c;都是Transformation算子。惰性的算子。 不同点分析 map函数是一条数据一条数据的处理&#xff0c;也就是&#xff0c;map的输入参数中要包含一条数据以及其他你需要传的参数。 mapPartitions函数是一个…

IOTE 2023国际物联网展直击:芯与物发布全新定位芯片,助力多领域智能化发展

IOTE 2023国际物联网展&#xff0c;作为全球物联网领域的盛会&#xff0c;于9月20日在中国深圳拉开帷幕。北斗星通集团应邀参展&#xff0c;旗下专业从事物联网、消费类GNSS芯片研发设计的芯与物公司也随其亮相本届盛会。 展会上&#xff0c;芯与物展示了一系列创新的GNSS定位…