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

【数据结构】二叉树的链式存储结构

二叉树的存储结构

typedef int BTDataType;
// 二叉树的结构
typedef struct BinaryTreeNode {BTDataType data;             // 树的值struct BinaryTreeNode *left; // 左孩子struct BinaryTreeNode *right;// 右孩子
} BinaryTreeNode;

二叉树的深度优先遍历

在这里插入图片描述

前序遍历

前序遍历,又叫先根遍历。
遍历顺序:根 -> 左子树 -> 右子树

代码:

// 前序遍历
void BinaryTreePrevOrder(BinaryTreeNode *root) {// 前序遍历 根、左子树、右子树// 如果root为空,递归结束if (root == NULL) {printf("NULL ");return;}printf("%d ", root->data);BinaryTreePrevOrder(root->left);BinaryTreePrevOrder(root->right);
}

中序遍历

中序遍历,又叫中根遍历。
遍历顺序:左子树 -> 根 -> 右子树

代码

// 中序遍历
void BinaryTreeInOrder(BinaryTreeNode *root) {// 中序遍历 - 左子树、根、右子树if (root == NULL) {printf("NULL ");return;}BinaryTreeInOrder(root->left);printf("%d ", root->data);BinaryTreeInOrder(root->right);
}

后序遍历

后序遍历,又叫后根遍历。
遍历顺序:左子树 -> 右子树 -> 根

代码

// 后序遍历
void BinaryPostOrder(BinaryTreeNode *root) {// 后序遍历 - 左子树、右子树、根if (root == NULL) {printf("NULL ");return;}BinaryPostOrder(root->left);BinaryPostOrder(root->right);printf("%d ", root->data);
}

二叉树的广度优先遍历

层序遍历

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

在这里插入图片描述

思路(借助一个队列):

  1. 先把根入队列,然后开始从队头出数据。
  2. 出队头的数据,把它的左孩子和右孩子依次从队尾入队列(NULL不入队列)。
  3. 重复进行步骤2,直到队列为空为止。

img

特点:借助队列先进先出的性质,上一层数据出队列的时候带入下一层数据。

// 层序遍历 - 利用队列
void BinaryTreeLevelOrder(BinaryTreeNode *root) {// 创建一个队列,队列中入数据,取队头,然后带左右子树,出一个数,带一个树的所有子树Queue q;QueueInit(&q);if (root) {// root不为NULL,就入队列QueuePush(&q, root);}while (!QueueEmpty(&q)) {// 取队头,打印BinaryTreeNode *front = QueueFront(&q);printf("%d ", front->data);// 取完POPQueuePop(&q);// 取队头,带下一层,if (front->left) {QueuePush(&q, front->left);}if (front->right) {QueuePush(&q, front->right);}}printf("\n");QueueDestroy(&q);
}

二叉树的节点个数

求解树的节点总数时,可以将问题拆解成子问题:

  1. 若为空,则结点个数为0。
  2. 若不为空,则结点个数 = 左子树节点个数 + 右子树节点个数 + 1(自己)。

代码

// 求二叉树节点个数
int BinaryTreeSize(BinaryTreeNode *root) {if (root == NULL) {return 0;}return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}

二叉树的叶子节点个数

子问题拆解:

  1. 若为空,则叶子结点个数为0。
  2. 若结点的左指针和右指针均为空,则叶子结点个数为1。
  3. 除上述两种情况外,说明该树存在子树,其叶子结点个数 = 左子树的叶子结点个数 + 右子树的叶子结点个数。

代码:

// 求二叉树的叶子节点个数
int BinaryTreeLeafSize(BinaryTreeNode *root) {if (root == NULL) {return 0;}if (root->left == NULL && root->right == NULL) {return 1;}return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

第K层节点的个数

思路:
相对于根结点的第k层结点的个数 = 相对于以其左孩子为根的第k-1层结点的个数 + 相对于以其右孩子为根的第k-1层结点的个数。

在这里插入图片描述

代码

// 求第k层的节点个数 k>=1
int BinaryTreeLevelSize(BinaryTreeNode *root, int k) {if (root == NULL) {return 0;}if (k == 1) {return 1;}return BinaryTreeLevelSize(root->left, k - 1) + BinaryTreeLevelSize(root->right, k - 1);
}

值为x的节点

子问题:

  1. 先判断根结点是否是目标结点。
  2. 再去左子树中寻找。
  3. 最后去右子树中寻找。

代码

// 二叉树查找值为x的节点
BinaryTreeNode *BinaryTreeFind(BinaryTreeNode *root, BTDataType x) {if (root == NULL) {return NULL;}if (root->data == x) {return root;}// 左子树递归的节点保存到leftTree中,如果leftTree不为NULL,则return leftTreeBinaryTreeNode *leftTree = BinaryTreeFind(root->left, x);if (leftTree) {return leftTree;}// 右子树递归的节点保存到rightTree中,如果rightTree不为NULL,则return rightTreeBinaryTreeNode *rightTree = BinaryTreeFind(root->right, x);if (rightTree) {return rightTree;}// 找不到,返回NULLreturn NULL;
}

树的高度

子问题:

  1. 若为空,则深度为0。
  2. 若不为空,则树的最大深度 = 左右子树中深度较大的值 + 1。

代码

// 求二叉树的高度
int BinaryTreeHeight(BinaryTreeNode *root) {// 求左子树的高度,右子树的高度// 取最大的if (root == NULL) {return 0;}int leftHeight = BinaryTreeHeight(root->left);int rightHeight = BinaryTreeHeight(root->right);//如果左右子树两边相等就取左边的高度,所以大于等于return leftHeight >= rightHeight ? leftHeight + 1 : rightHeight + 1;
}

判断二叉树是否是完全二叉树

判断二叉树是否是完全二叉树的方法与二叉树的层序遍历类似,但又有一些不同。

思路(借助一个队列):

  1. 先把根入队列,然后开始从队头出数据。
  2. 出队头的数据,把它的左孩子和右孩子依次从队尾入队列(NULL也入队列)。
  3. 重复进行步骤2,直到读取到的队头数据为NULL时停止入队列。
  4. 检查队列中剩余数据,若全为NULL,则是完全二叉树;若其中有一个非空的数据,则不是完全二叉树。

在这里插入图片描述

代码

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BinaryTreeNode *root) {// 层序走,走到第一个为空的时候,就跳出去,如果是满二叉树,后面的节点都应该为空Queue q;QueueInit(&q);if (root) {QueuePush(&q, root);}while (!QueueEmpty(&q)) {BinaryTreeNode *front = QueueFront(&q);QueuePop(&q);if (front == NULL) {break;} else {QueuePush(&q, front->left);QueuePush(&q, front->right);}}// 出到空以后,如果后面全是空,则是完全二叉树while (!QueueEmpty(&q)) {BinaryTreeNode *front = QueueFront(&q);QueuePop(&q);if (front != NULL) {QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}

判断二叉树是否是单值二叉树

单值二叉树,所有节点的值都相同的二叉树即为单值二叉树,判断某一棵二叉树是否是单值二叉树的一般步骤如下:

  1. 判断根的左孩子的值与根结点是否相同。
  2. 判断根的右孩子的值与根结点是否相同。
  3. 判断以根的左孩子为根的二叉树是否是单值二叉树。
  4. 判断以根的右孩子为根的二叉树是否是单值二叉树。

若满足以上情况,则是单值二叉树。

注:空树也是单值二叉树。

代码

//求单值二叉树
bool isUnivalTree(BinaryTreeNode *root) {if (root == nullptr) {return true;}if (root->left && root->data != root->left->data) {return false;}if (root->right && root->data != root->right->data) {return false;}return isUnivalTree(root->left) && isUnivalTree(root->right);
}

判断二叉树是否是对称二叉树

对称二叉树,这里所说的对称是指镜像对称:

要判断某二叉树是否是对称二叉树,则判断其根结点的左子树和右子树是否是镜像对称即可。因为是镜像对称,所以左子树的遍历方式和右子树的遍历方式是不同的,准确来说,左子树和右子树的遍历是反方向进行的。

代码

//求对称二叉树
bool _isSymmetric(BinaryTreeNode *left, BinaryTreeNode *right) {// 两个都为NULL,对称if (left == NULL && right == NULL)return true;// 两个其中一个为NULL,一个不为NULL,不对称if (left == NULL || right == NULL)return false;// left的左孩子的值和right的值不相等,不对称if (left->data != right->data)return false;// 左子树的左孩子,和右子树的右孩子对比,然后左子树的右孩子和右子树的左孩子在对比return _isSymmetric(left->left, right->right) && _isSymmetric(left->right, right->left);
}bool isSymmetric(BinaryTreeNode *root) {if (root == nullptr) {return true;}return _isSymmetric(root->left, root->right);
}

翻转二叉树

思路:

  1. 翻转左子树。
  2. 翻转右子树。
  3. 交换左右子树的位置。

代码

BinaryTreeNode *invertTree(BinaryTreeNode *root) {if (root == nullptr) {return nullptr;}BinaryTreeNode *leftTree = invertTree(root->left);BinaryTreeNode *rightTree = invertTree(root->right);root->left = rightTree;root->right = leftTree;return root;
}

二叉树的构建和销毁

// 申请树节点
BinaryTreeNode *BuyBinaryTreeNode(BTDataType x) {BinaryTreeNode *newnode = (BinaryTreeNode *) malloc(sizeof(BinaryTreeNode));if (newnode == NULL) {perror("malloc fail");exit(-1);}newnode->data = x;newnode->left = newnode->right = NULL;return newnode;
}// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BinaryTreeNode *BinaryTreeCreate(BTDataType *a, int *pi) {if (a[*pi] == '#') {(*pi)++;return NULL;}BinaryTreeNode *root = (BinaryTreeNode *) malloc(sizeof(BinaryTreeNode));if (root == NULL) {perror("malloc fail");exit(-1);}root->data = a[(*pi)++];root->left = BinaryTreeCreate(a, pi);root->right = BinaryTreeCreate(a, pi);return root;
}

销毁

// 二叉树销毁
void BinaryTreeDestory(BinaryTreeNode **root) {if (*root == NULL) {return;}// 后序遍历销毁,根要最后释放BinaryTreeDestory(&(*root)->left);BinaryTreeDestory(&(*root)->right);free(*root);*root = NULL;
}

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

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

相关文章

EXCEL如何把一个单元格内的文本和数字分开?例如:龚龚15565 = 龚龚 15565

使用工具:WPS 举例: EXCEL如何把一个单元格内的文本和数字批量分开?不使用数据分列。 第一步、将第二行数据冻结 第二步、在B1、C1单元格输入需要分开的示例 第三步、点击选中B1单元格,输入快捷键【CTRLE】进行填充。B2单元格也是…

【AIGC】图片生成的原理与应用

前言 近两年 AI 发展非常迅速,其中的 AI 绘画也越来越火爆,AI 绘画在很多应用领域有巨大的潜力,AI 甚至能模仿各种著名艺术家的风格进行绘画。 目前比较有名商业化的 AI 绘画软件有 Midjourney、DALLE2、以及百度出品的文心一格:…

MinGW-W64 下载、安装与配置(支持最新版的GCC,目前 GCC 13.2.0)VSCode配置c/c++环境 彻底删除vscode(包括插件及配置!)

目录 一、简介 二、下载 1 旧版安装(8.1.0) 从 sourceforge.net 下载 2 新版安装(本次采用较新版本~~~) 从 github 下载 从 镜像站点 下载 自己编译 三、安装与配置 1. 在线安装(这里仅作参考了解) 2. 离线安装&…

异步FIFO设计的仿真与综合技术(3)

概述 本文主体翻译自C. E. Cummings and S. Design, “Simulation and Synthesis Techniques for Asynchronous FIFO Design 一文,添加了笔者的个人理解与注释,文中蓝色部分为笔者注或意译。前文链接: 异步FIFO设计的仿真与综合技术&#xf…

自动化测试(五):自动化测试框架的搭建和基于yaml热加载的测试用例的设计

该部分是对自动化测试专栏前四篇的一个补充,本次参考以下文章实现一个完整的谷歌翻译接口自动化测试:   [1]【python小脚本】Yaml配置文件动态加载   [2]【python做接口测试的学习记录day8——pytest自动化测试框架之热加载和断言封装】 目标:框架封…

新增动态排序图、桑基图、AntV组合图,DataEase开源数据可视化分析平台v1.18.10发布

2023年9月14日,DataEase开源数据可视化分析平台正式发布v1.18.10版本。 这一版本的功能升级包括:数据集方面,对字段管理的后台保存做了相关优化,降低了资源消耗;仪表板方面,对联动、查询结果以及过滤组件等…

系统架构:软件工程速成

文章目录 参考概述软件工程概述软件过程 可行性分析可行性分析概述数据流图数据字典 需求分析需求分析概述ER图状态转换图 参考 软件工程速成(期末考研复试软考)均适用. 支持4K 概述 软件工程概述 定义:采用工程的概念、原理、技术和方法来开发与维护软件。 三…

GET,POST,DELETE,PUT参数传递的形式

一.get请求参数在地址后面进行拼接 1.代码&#xff1a; <template><div class""><button click"fn">点击</button></div> </template><script> import axios from "axios"; //安装完之后&#xff0…

MFC中嵌入显示opencv窗口

在MFC窗体中建立一个Picture Control控件,用于显示opencv窗口 在属性中设置图片控件的资源ID为IDC_PIC1 主要的思路: 使用GetWindowRect可以获取图片控件的区域 使用cv::resizeWindow可以设置opencv窗口的大小,适合图片控件的大小 使用cvGetWindowHandle函数可以获取到ope…

OpenCV(四十二):Harris角点检测

1.Harris角点介绍 什么是角点&#xff1f; 角点指的是两条边的交点&#xff0c;图中红色圈起来的点就是角点。 Harris角点检测原理&#xff1a;首先定义一个矩形区域&#xff0c;然后将这个矩形区域放置在我的图像中&#xff0c;求取这个区域内所有的像素值之和&#xff0c;之…

麒麟v10安装mysql(ARM架构)

下载MYSQL安装包 华为开源镜像站_软件开发服务_华为云 上面的选择一个下载 或者用命令下载 wget https://repo.huaweicloud.com/kunpeng/yum/el/7/aarch64/Packages/database/mysql-5.7.27-1.el7.aarch64.rpm 检查是否已经安装MySQL rpm -qa | grep mysql将包卸载掉 rpm -…

图论第三天|130. 被围绕的区域、417. 太平洋大西洋水流问题、827. 最大人工岛

130. 被围绕的区域 文档讲解 &#xff1a;代码随想录 - 130. 被围绕的区域 状态&#xff1a;开始学习。 思路&#xff1a; 步骤一&#xff1a; 深搜或者广搜将地图周边的 ‘O’ 全部改成 ’A’&#xff0c;如图所示&#xff1a; 步骤二&#xff1a; 再遍历地图&#xff0c;将 …

JWT 安全及案例实战

文章目录 一、JWT (json web token)安全1. Cookie&#xff08;放在浏览器&#xff09;2. Session&#xff08;放在服务器&#xff09;3. Token4. JWT (json web token)4.1 头部4.1.1 alg4.1.2 typ 4.2 payload4.3 签名4.4 通信流程 5. 防御措施 二、漏洞实例&#xff08;webgoa…

API原理概念篇(六)玩转正则表达式等常用API

一 玩转正则表达式等常用API ① 正则 1、openresty存在两套正则表达式规范1) lua自身独有的正则规范 备注&#xff1a;大约有5%&#xff5e;15%性能损耗损耗原因&#xff1a;表达式compile成pattern,并不会被缓存,每次都会被重新compile编译2) nginx的符合POSIX规范的PCR…

集合减法【新思路】

#include<stdio.h> int main() {int n,m,flag0;int x;int a[100001]{0},b[100001]{0};scanf("%d %d",&n,&m);以集合A所有元素作为数组下标映射值成1 for (int i 0; i < n; i) {scanf("%d", &x);a[x] 1; }以集合B所有元素作为数组下…

生产消费者模型的介绍以及其的模拟实现

目录 生产者消费者模型的概念 生产者消费者模型的特点 基于阻塞队列BlockingQueue的生产者消费者模型 对基于阻塞队列BlockingQueue的生产者消费者模型的模拟实现 ConProd.c文件的整体代码 BlockQueue.h文件的整体代码 对【基于阻塞队列BlockingQueue的生产者消费者模型…

windows系统安装php,运行php

一、安装php 官网&#xff1a;PHP For Windows: Binaries and sources Releases 下载最新的PHP解释器 解压好放入 C:\php 目录文件下 二、配置php 配置环境变量&#xff1a;在CMD命令提示符中输入以下命令&#xff0c;将PHP路径添加到系统环境变量中&#xff0c;以便可以在…

【第四阶段】kotlin语言集合转换与快捷转换学习

1.list可以通过转换为set进行去重 2.list转set在转list也能去重 3.使用快捷函数distinct进行去重 package Kotlin.Stage4fun main() {val list mutableListOf("java", "ktolin", "c", "java", "ktolin", "c")pr…

MyVector 的实现

myVector #include <iostream> #include <vector>int size20;using namespace std;template <typename type> class myvector {int size;type value;type *arr;public://无参构造myvector(){};//有参构造myvector(int s,type v):size(s),value(v){arrnew in…

laravel8框架-语言包的安装和配置

1, 查找 laravel框架语言包地址&#xff1a; \根目录\resources\lang\ 默认有个 en 语言包 2&#xff0c;下载 和 安装 下载地址&#xff1a;https://packagist.org/ 搜索 laravel/lang 参考网址&#xff1a;https://packagist.org/packages/overtrue/laravel-lang 选择你…