【数据结构篇】链式结构二叉树

目录:

一 二叉链的概念与结构:

1.1 概念:

1.2 结构:

二 二叉链的实现:

2.1 二叉树的构建:

2.2 二叉树的遍历:

2.2.1 前序遍历:

2.2.2 中序遍历:

2.2.3 后序遍历:

2.3 二叉树结点个数:

2.4 二叉树叶子结点个数:

2.5 二叉树第k层结点个数:

2.6 二叉树深度/高度:

2.7 二叉树查找值为x的结点:

2.8 二叉树的销毁:

2.9 二叉树的层序遍历:

三 判断是否为完全二叉树:

四 二叉树性质选择题:


一 二叉链的概念与结构:

1.1 概念:

        用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址。

1.2 结构:

typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;

回顾二叉树:

二叉树分为空树和非空二叉树,非空二叉树由根结点、根结点的左子树、根结点的右子树组成的。根结点的左子树和右子树分别又是由子树结点、子树结点的左子树、子树结点的右子树组成的,因此 二叉树定义是递归式的,后序链式二叉树的操作中基本都是按照该概念实现的。

二 二叉链的实现:

Tree.h

定义二叉链结构

将存储数据类型重命名

所写的函数的声明

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef int BTdatatype;typedef struct BinaryTreenode
{int data;struct BinaryTreenode* left;struct BinaryTreenode* right;
}BTnode;//前序遍历
void Preorder(BTnode* root);//中序遍历
void Inorder(BTnode* root);//后序遍历
void Postorder(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);//层序遍历
//借助数据结构---队列
void LevelOrder(BTnode* root);

Tree.c

函数的实现方法

2.1 二叉树的构建:

二叉树的构建是递归实现的

二叉树的创建方式比较复杂,为了更好的步入到二叉树内容中,我们先手动创建一棵链式二叉树

方法:

BTNode* BuyBTNode(int val)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("malloc fail");return NULL;}newnode->val = val;newnode->left = NULL;newnode->right = NULL;return newnode;
}BTNode* CreateTree()
{BTNode* n1 = BuyBTNode(1);BTNode* n2 = BuyBTNode(2);BTNode* n3 = BuyBTNode(3);BTNode* n4 = BuyBTNode(4);BTNode* n5 = BuyBTNode(5);BTNode* n6 = BuyBTNode(6);BTNode* n7 = BuyBTNode(7);n1->left = n2;n1->right = n4;n2->left = n3; n4->left = n5; n4->right = n6; n5->left = n7; return n1;
}

2.2 二叉树的遍历:

按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历
1)前序遍历(先序遍历):访问根结点的操作发⽣在遍历其左右⼦树之前
访问顺序为:根结点、左⼦树、右⼦树
2)中序遍历:访问根结点的操作发⽣在遍历其左右⼦树之中(间)
访问顺序为:左⼦树、根结点、右⼦树
3)后序遍历:访问根结点的操作发⽣在遍历其左右⼦树之后
访问顺序为:左⼦树、右⼦树、根结点

2.2.1 前序遍历:

核心思想就是递归:先递推,再回归

   传入根节点,依据前序遍历根左右的规则,先打印根节点,然后再将左结点当做一课新树的根节点进行相同操作,右子树同理为递推,当root==NULL时,直接返回为回归。

图解:

代码:

void Preorder(BTnode* root)
{if (root == NULL){return;}printf("%d ", root->data);Preorder(root->left);Preorder(root->right);
}

2.2.2 中序遍历:

原理同前序遍历:(访问顺序为:左⼦树、根结点、右⼦树

//中序遍历
void Inorder(BTnode* root)
{if (root == NULL){return;}Inorder(root->left);printf("%d ", root->data);Inorder(root->right);}

2.2.3 后序遍历:

原理同前序遍历:(访问顺序为:左⼦树、右⼦树、根结点

//后序遍历
void Postorder(BTnode* root)
{if (root == NULL){return;}Postorder(root->left);Postorder(root->right);printf("%d ", root->data);}

2.3 二叉树结点个数:

求二叉树结点个数,即当下结点+左子树+右子树

当结点某一子树为空时,返回0即可,递推结束

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

2.4 二叉树叶子结点个数:

叶子结点度为0

要求叶子结点,就是求左右子树叶子结点之和,依次递推下去

满足叶子结点条件或是某一子树为空结束递推

// ⼆叉树叶⼦结点个数
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);
}

2.5 二叉树第k层结点个数:

求第k层节点个数,即将根结点设为k,每递推一层,便将k-1, 当k==1时说明已经递推到第k层了,此时若不是空结点,返回1,若遇到空节点,返回0,然后在回归时将它们加起来即可。

// ⼆叉树第k层结点个数
int BinaryTreeLevelKSize(BTnode* root, int k)
{if (root == NULL){return 0;}if (k == 1){return 1;}return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

2.6 二叉树深度/高度:

要求高度,即子树高度的最大值+1,子树高度的最大值又是其子树高度最大值+1,以此类推当递推到空节点时结束——>返回0(空节点不算高度)

回归时每次返回左右子树高度取最大值+1

//⼆叉树的深度/⾼度
int BinaryTreeDepth(BTnode* root)
{if (root == NULL){return 0;}int leftdep = BinaryTreeDepth(root->left);int rightdep = BinaryTreeDepth(root->right);return leftdep > rightdep ? leftdep + 1 : rightdep + 1;}

2.7 二叉树查找值为x的结点:

分为左右子树查找,依次递推即可

结束条件为空:说明在这一路径上没有找到

结束条件找到了返回结点指针即可

// ⼆叉树查找值为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->right,x);if (rightfind){return rightfind;}return NULL;
}

2.8 二叉树的销毁:

先销毁左右子树,最后销毁根节点

当为空时,不用销毁直接返回

// ⼆叉树销毁
//将本来指向根节点的root指针改为空,所以传二级指针(一级指针也可以,只不过在调用完记得把root置为空)
void BinaryTreeDestory(BTnode** root)
{if (*root == NULL){return;}BinaryTreeDestory(&((*root)->left));BinaryTreeDestory(&((*root)->right));free(*root);*root = NULL;}

2.9 二叉树的层序遍历:

除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根结点所在层数为1,层序遍历就是从所在二叉树的根结点出发,首先访问第一层的树根结点,然后从左到右访问第2 层上的结点,接着是第3层的结点,以此类推,自上而下,自左而右逐层访问树的结点的过程就是层序遍历

由于递归会沿着一边路径一直递归下去,所以显然不能使用递归!

实现层序遍历需要额外借助数据结构:队列

图解:

1.创建并初始化队列,注意将队列结点存储的数据类型更改
2.插入的是指向结点的指针,而不是结点的值,否则找不到结点的左右孩子,所以队列结点存储的数据类型为struct BTNode*
3.首先将指向根节点的指针入队列,保存后并打印结点的值
4.根节点出队列,保证每一次取到的队列的头都是新的
5.如果根节点左右孩子不为空就将其入队列,为空则无必要,不需要打印NULL
6.重复上述操作直到队列为空

//层序遍历
//借助数据结构---队列
void LevelOrder(BTnode* root)
{Queue q;Queueinit(&q);Queuepush(&q, root);while (!QueueEmpty(&q)){//取队头,打印BTnode* front = QueueFront(&q);printf("%d ", front->data);QueuePop(&q);//队头节点的左右孩子入队列if (front->left)QueuePush(&q, front->left);if (front->right)Queuepush(&q, front->right);}//队列为空QueueDestroy(&q);
}

三 判断是否为完全二叉树:

使用层序遍历
1.左右结点不管是否为空,都入队列
2.第一个循环用来取二叉树第一个NULL结点前的所有数据:

         如果是完全二叉树,跳出此循环后剩下的都是NULL结点
         如果是非完全二叉树,跳出此循环后还有非空结点

3.第二个循环用来判断此时队列里是否有非空的指针

    如果直到队列为空跳出循环说明全是空指针,返回true
    反之返回false


//判断二叉树是否为完全二叉树
//---队列
bool BinaryTreeComplete(BTnode* root)
{Queue q;QueueInit(&q);QueuePush(&q, root);while (!QueueEmpty(&q)){BTnode* front = QueueFront(&q);QueuePop(&q);if (front == NULL){break;}QueuePush(&q, front->left);QueuePush(&q, front->right);}//队列不一定为空while (!QueueEmpty(&q)){BTnode* front = QueueFront(&q);QueuePop(&q);if (front != NULL){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}

四 二叉树性质选择题:

选 B。

性质:度为0结点个数==度为2结点个数+1

选 A。

2n为偶数,由二叉树的定义可知,树中必定存在度为0的结点和度为2的结点,设度为0结点有a个,根据度为0的结点(即叶子结点)总比度为2的结点多一个,得度为2的结点有a-1个。

再根据完全二叉树的定义,度为1的结点有0个或1个

设度为1的结点有0个,a+0+a-1=2n,得2a=2n-1,由于结点个数必须为整数,假设不成立;

设度为1的结点有1个,a+1+a-1=2n,得a=n,即叶子结点个数为n。

选B。

由2^9-1<531<2^10-1

说明第九层填满,第十层没有填满

选B。

由二叉树的定义可知,树中必定存在度为0的结点和度为2的结点,设度为0结点有a个,根据度为0的结点(即叶子结点)总比度为2的结点多一个,得度为2的结点有a-1个。
再根据完全二叉树的定义,度为1的结点有0个或1个
假设度1结点为0个,a+0+a-1=767,得2a=768,即叶子结点个数为384
当度为1的结点为1个时,a+1+a-1=767,不为整数,舍去。

选D。

后序遍历最后一个一定是根节点

中序遍历中得到根节点左右子树

确定一个划去一个

在左右子树又可以根据后序遍历确定根节点

再看中序遍历得到左右子树

重复上述操作即可画出二叉树

以上就是【数据结构篇】链式结构二叉树的全部内容,欢迎指正~ 🌹🌹🌹

码文不易,还请多多关注支持,这是我持续创作的最大动力!

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

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

相关文章

【MySQL】02.数据库基础

1. 数据库的引入 之前存储数据用文件就可以了&#xff0c;为什么还要弄个数据库? 文件存储存在安全性问题&#xff0c;文件不利于数据查询和管理&#xff0c;文件不利于存储海量数据&#xff0c;文件在程序中控制不方便。而为了解决上述问题&#xff0c;专家们设计出更加利于…

什么是 Langchain 以及其核心组件

LangChain 官方文档&#xff1a;LangChain 一、什么是Langchain LangChain 是一个用于构建基于LLM的应用框架&#xff0c;它提供了对 LLM API 的封装和扩展&#xff0c;使开发者能够更方便地构建复杂的应用。 个人理解&#xff1a;用类比的方法来说&#xff0c;LangChain类似…

博客系统功能测试

博客系统网址&#xff1a;http://8.137.19.140:9090/blog_list.html 主要测试内容 功能测试、界面测试、性能测试、易用性测试、安全测试、兼容性测试、弱网测试、安装卸载测试、压力测试… 测试方法及目的 利用selenium和python编写测试脚本&#xff0c;对博客系统进行的相关…

项目制作流程

一、使用 CRA 创建项目 npx create-react-app name 二、按照业务规范整理项目目录 &#xff08;重点src目录&#xff09; 三、安装插件 npm install sass -Dnpm install antd --savenpm install react-router-dom 四、配置基础路由 Router 1. 安装路由包 react-router-dom …

ngx_http_random_index_module 模块概述

一、使用场景 随机内容分发 当同一目录下存放多份等价内容&#xff08;如多张轮播图、不同版本静态页面等&#xff09;时&#xff0c;可通过随机索引实现负载均衡或流量分散。A/B 测试 通过目录请求自动随机分配用户到不同测试组&#xff0c;无需后端逻辑参与。动态“首页”选…

智能权限守护者:基于Python描述符的动态角色控制实现

智能权限守护者:基于Python描述符的动态角色控制实现 引言:当描述符遇见权限管理 在Python的魔法方法体系中,描述符(Descriptor)以其优雅的属性访问控制机制著称。当我们将描述符与RBAC(基于角色的访问控制)模型结合,就能创造出既灵活又安全的动态权限管理系统。本文…

Linux 的 UDP 网络编程 -- 回显服务器,翻译服务器

目录 1. 回显服务器 -- echo server 1.1 相关函数介绍 1.1.1 socket() 1.1.2 bind() 1.1.3 recvfrom() 1.1.4 sendto() 1.1.5 inet_ntoa() 1.1.6 inet_addr() 1.2 Udp 服务端的封装 -- UdpServer.hpp 1.3 服务端代码 -- UdpServer.cc 1.4 客户端代码 -- UdpClient.…

Linux 内核等待机制详解:prepare_to_wait_exclusive 与 TASK_INTERRUPTIBLE

1. prepare_to_wait_exclusive 函数解析 1.1 核心作用 prepare_to_wait_exclusive 是 Linux 内核中用于将进程以独占方式加入等待队列的关键函数,其主要功能包括: 标记独占等待:通过设置 WQ_FLAG_EXCLUSIVE 标志,表明此等待条目是独占的。 安全入队:在自旋锁保护下,将条…

【Android构建系统】了解Soong构建系统

背景介绍 在Android7.0之前&#xff0c;Android使用GNU Make描述和执行build规则。Android7.0引入了Soong构建系统&#xff0c;弥补Make构建系统在Android层面变慢、容易出错、无法扩展且难以测试等缺点。 Soong利用Kati GNU Make克隆工具和Ninja构建系统组件来加速Android的…

信息学奥赛一本通 1539:简单题 | 洛谷 P5057 [CQOI2006] 简单题

【题目链接】 ybt 1539&#xff1a;简单题 洛谷 P5057 [CQOI2006] 简单题 【题目考点】 1. 树状数组 模板题及讲解&#xff1a;洛谷 P3374 【模板】树状数组 【解题思路】 解法1&#xff1a;树状数组 该有01构成数组初值都为0。 某位置的元素被修改奇数次后值为1&#x…

仓颉开发语言入门教程:搭建开发环境

仓颉开发语言作为华为为鸿蒙系统自研的开发语言&#xff0c;虽然才发布不久&#xff0c;但是它承担着极其重要的历史使命。作为鸿蒙开发者&#xff0c;掌握仓颉开发语言将成为不可或缺的技能&#xff0c;今天我们从零开始&#xff0c;为大家分享仓颉语言的开发教程&#xff0c;…

玉米籽粒发育

成熟玉米籽粒的结构 玉米籽粒的组成 成熟的玉米籽粒主要由以下三部分组成&#xff1a; 母体组织&#xff1a;包括种皮、胎座和花梗。种皮由珠被发育而来&#xff0c;起到保护种子的作用&#xff0c;并在种子的休眠和萌发中发挥重要作用。胚&#xff1a;包含根分生组织、茎分…

sherpa-ncnn:音频处理跟不上采集速度 -- 语音转文本大模型

目录 1. 问题报错2. 解决方法 1. 问题报错 报错&#xff1a; An overrun occurred, which means the RTF of the current model on your board is larger than 1. You can use ./bin/sherpa-ncnn to verify that. Please select a smaller model whose RTF is less than 1 fo…

Postman一直打不开的解决办法

Postman 是一款非常流行的开源 API 开发工具&#xff0c;主要用于构建、测试、调试和文档化应用程序接口&#xff08;API&#xff09;。但有时它的性能不会特别稳定&#xff0c;功能限制和扩展性不足&#xff1b;应用于开发、测试、运维等环节&#xff0c;尤其在开发 RESTful A…

问题|对只允许输入的变量是否进行了更改

“对只允许输入的变量是否进行了更改”这一问题的核心是&#xff1a;在编程中&#xff0c;某些变量被设计为仅用于输入&#xff08;只读&#xff09;&#xff0c;但在代码中可能被意外修改&#xff0c;导致潜在错误。以下是详细解释&#xff1a; 1. 什么是“只允许输入的变量”…

RPC与SOAP的区别

一.RPC&#xff08;远程过程调用&#xff09;和SOAP&#xff08;简单对象访问协议&#xff09;均用于实现分布式系统中的远程通信&#xff0c;但两者在设计理念、协议实现及应用场景上存在显著差异。 二.对比 1.设计理念 2.协议规范 3.技术特性 4.典型应用场景 5.总结 三.总结…

c#的内存指针操作(仅用于记录)

c#也可以直接操作内存指针&#xff0c;如下为示例&#xff1a; unsafe {byte[] a {1,2,3};fixed (byte* p1 a, p2 &a[^1]){Debugger.Log(1, "test", $"max index:{p2-p1}");Debugger.Log(1, "test", $"address:{(long)p1:X}")…

Jsp技术入门指南【十三】基于 JSTL SQL 标签库实现 MySQL 数据库连接与数据分页展示

Jsp技术入门指南【十三】基于 JSTL SQL 标签库实现 MySQL 数据库连接与数据分页展示 前言一、回顾SQL标签的内容1. 什么是JSTL SQL标签&#xff1f;2.为什么要用SQL标签&#xff1f;3.第一步&#xff1a;引入SQL标签库4. SQL标签的核心功能&#xff1a;连接数据库标签常用属性&…

羽毛球订场小程序源码介绍

基于ThinkPHP、FastAdmin以及UniApp开发的羽毛球订场小程序源码&#xff0c;这款小程序旨在为羽毛球爱好者提供便捷的场地预订服务。 该小程序前端采用UniApp框架开发&#xff0c;具有良好的跨平台兼容性&#xff0c;可以一键发布至iOS和Android平台&#xff0c;极大地提高了开…

Unreal Engine: Windows 下打包 AirSim项目 为 Linux 平台项目

环境&#xff1a; Windows: win10, UE4.27, Visual Studio 2022 Community.Linux: 22.04 windows环境安装教程&#xff1a; 链接遇到的问题&#xff08;问题&#xff1a;解决方案&#xff09; 点击Linux打包按钮&#xff0c;跳转至网页而不是执行打包流程&#xff1a;用VS打开项…