初阶数据结构:二叉树(补充扩展)

目录

  • 1. 堆排序
    • 1.1补充:建堆的时间复杂度
    • 1.2 堆排序:升序与降序
  • 2. TopK问题
  • 3. 二叉树的链式结构及其遍历方式
    • 3.1 二叉树的链式结构
    • 3.2 二叉树的前序遍历
    • 2.2 二叉树的中序遍历
    • 2.3 后序遍历
    • 2.4 层序遍历
  • 4. 二叉树OJ练习
    • 4.1 单值二叉树
    • 4.2 判断两棵二叉树是否相等
    • 4.3 判断对称二叉树
    • 4.4 另一棵二叉树的子树
    • 4.5 二叉树的构建与销毁
    • 4.6 判断二叉树是否为完全二叉树
    • 4.7 补充练习
      • 4.7.1 二叉树的节点数
      • 4.7.2 二叉树的叶子节点数
      • 4.7.3 二叉树的第K层结点数
      • 4.7.4 查找二叉树中为x值的结点

1. 堆排序

1.1补充:建堆的时间复杂度

这里使用满二叉树近似计算,向下调整法建堆的时间复杂度:

在这里插入图片描述

等比数列求和,得需调整n - log(n + 1),时间复杂度为O(n)

1.2 堆排序:升序与降序

思路:我们先建堆,然后将堆顶(堆顶元素总是为最大或最小)的元素与尾部元素交换,size–,然后向下调整,直至堆为空。

  1. 排升序,建大堆(大堆的父亲结点都大于小堆)
  2. 排降序,建小堆

代码实现如下:

void HeapAdjustDown(int* arr, int n, int parent)
{//n为元素个数int child = parent * 2 + 1;while (child < n){if (child + 1 < n && arr[child] < arr[child + 1]){child++;}if (arr[parent] < arr[child]){swap(&arr[parent], &arr[child]);parent = child;child = parent * 2 + 1;}else{break;}}
}int arr[] = { 27,15,18,28,34,65,49,25,37 };
//向下调整建堆
int n = sizeof(arr) / sizeof(arr[0]);
for (int i = (n - 1 - 1) / 2; i >= 0; i--)
{HeapAdjustDown(arr, n, i);
}ArrPrint(arr, n);//交换首尾元素,size--,再向下调整
int size = n;
while (size)
{swap(&arr[0], &arr[size - 1]);size--;HeapAdjustDown(arr, size, 0);
}

2. TopK问题

当数据量很大时,且为乱序,数据无法一下全部加载到内存中,所以整体排序无法得出最大或最小的前K个数,那么,如何快速得出前K个最大/最小数。

思路:
先于数据首部建一个大小为K的

  1. 得出最大,建小堆
  2. 得出最小,建大堆

然后,再将剩余的N- K个数据与堆顶元素比较

  1. 当需要最大的数时,若比较元素大于堆顶元素,则交换二者再进行向下调整。
  2. 当需要最小的数时,若比较元素小于堆顶元素,则交换二者再进行向下调整。
void HeapAdjustDown2(int* arr, int n, int parent)
{//n为元素个数int child = parent * 2 + 1;while (child < n){if (child + 1 < n && arr[child] > arr[child + 1]){child++;}if (arr[parent] > arr[child]){swap(&arr[parent], &arr[child]);parent = child;child = parent * 2 + 1;}else{break;}}
}void TopK(int* arr, int k, int n)
{//筛选k个最大的数//在数据顶部建一个大小为k的小堆for (int i = (k - 1 - 1) / 2; i >= 0; i--){HeapAdjustDown2(arr, k, i);}//若遍历到大于堆顶的元素,交换并向下调整for (int j = k; j < n; j++){if (arr[j] > arr[0]){swap(&arr[j], &arr[0]);HeapAdjustDown2(arr, k, 0);}}
}

3. 二叉树的链式结构及其遍历方式

3.1 二叉树的链式结构

在前面的学习中,我们已经了解到,二叉树的结构由三部分组成根,左子树,右子树

在这里插入图片描述

当我们使用链式存储的方式构建二叉树时,其结点的结构定义如下:

typedef struct TreeNode
{int val;//左子树指针struct TreeNode* left;//右子树指针struct TreeNode* right;
}

根据逻辑遍历的方式顺序不同,二叉树的遍历方式分为四种:前序,中序,后序,层序

3.2 二叉树的前序遍历

  1. 遍历逻辑顺序:根结点,左子树,右子树(根左右)
  2. 题目链接:
    前序遍历
void preorder_part(struct TreeNode* root, int* arr, int* size)
{if(root == NULL){return;}arr[*size] = root->val;(*size)++;preorder_part(root->left, arr, size);preorder_part(root->right, arr, size);
}int* preorderTraversal(struct TreeNode* root, int* returnSize) 
{//根左右//为空树时,不反回空指针//返回数组*returnSize = 0;int* arr = (int*)malloc(100 * sizeof(int));preorder_part(root, arr, returnSize);return arr;
}

2.2 二叉树的中序遍历

  1. 遍历逻辑顺序:左根右
  2. 题目链接:
    中序遍历
void inorder_part(struct TreeNode* root, int* arr, int* size)
{if(root == NULL){return;}inorder_part(root->left, arr, size);arr[*size] = root->val;(*size)++;inorder_part(root->right, arr, size);
}int* inorderTraversal(struct TreeNode* root, int* returnSize) 
{*returnSize = 0;int* arr = (int*)malloc(100 * sizeof(int));inorder_part(root, arr, returnSize);return arr;    
}

2.3 后序遍历

  1. 遍历逻辑顺序:左右根
  2. 题目链接:
    后序遍历
void postorder_part(struct TreeNode* root, int* arr, int* size)
{if(root == NULL){return;}postorder_part(root->left, arr, size);postorder_part(root->right, arr, size);arr[*size] = root->val;(*size)++;
}int* postorderTraversal(struct TreeNode* root, int* returnSize) 
{*returnSize = 0;int* arr = (int*)malloc(100 * sizeof(int));postorder_part(root, arr, returnSize);return arr;        
}

2.4 层序遍历

遍历逻辑:依次按层进行遍历(利用队列存储子节点)

void LevelOrder(TreeNode* root)
{Queue q1;QueueInit(&q1);QueuePush(&q1, root);TreeNode* top = QueueFront(&q1);while (!QueueEmpty(&q1)){if (top){QueuePush(&q1, top->left);QueuePush(&q1, top->right);}if (top){printf("%c ", top->val);}else{printf("NULL ");}QueuePop(&q1);if (!QueueEmpty(&q1)){top = QueueFront(&q1);}}
}

4. 二叉树OJ练习

4.1 单值二叉树

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    单值二叉树
  3. 思路:任选一种遍历方式遍历整个二叉树,同时判断左右孩子结点的值等于父亲结点的值
bool isUnivalTree(struct TreeNode* root) 
{if(root == NULL){return true;}if(root->left && root->val != root->left->val){return false;}if(root->right && root->val != root->right->val){return false;}return isUnivalTree(root->left) && isUnivalTree(root->right);    
}

4.2 判断两棵二叉树是否相等

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    判断两颗二叉树是否相等
    3 . 思路:按同样顺序遍历两棵树,同时判断
bool isSameTree(struct TreeNode* p, struct TreeNode* q) 
{//调整逻辑顺序,不出现越界情况//二者都为NULLif(p == NULL && q == NULL){return true;}//有一个为NULLif(p && q == NULL){return false;}if(q && p == NULL){return false;}//都不为NULLif(p->val != q->val){return false;}return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

4.3 判断对称二叉树

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    对称二叉树
  3. 思路:按照对称的遍历方式,遍历判断二叉树的左右子树
bool order_part(struct TreeNode* left, struct TreeNode* right)
{if(left == NULL && right == NULL){return true;}if(left && right == NULL){return false;}if(right && left == NULL){return false;}if(left->val != right->val){return false;}return order_part(left->left, right->right) && order_part(left->right, right->left);
}bool isSymmetric(struct TreeNode* root) 
{return order_part(root->left, root->right);
}

4.4 另一棵二叉树的子树

1.题目信息:
在这里插入图片描述
2. 题目链接:
另一颗树的子树
3. 思路:遇到与配对子树的根节点相同的结点即开始配对,直至遍历完整个树。
4. 注:将逻辑,语言转换(翻译)为代码

bool isSameTree(struct TreeNode* p, struct TreeNode* q) 
{//调整逻辑顺序,不出现越界情况//二者都为NULLif(p == NULL && q == NULL){return true;}//有一个为NULLif(p && q == NULL){return false;}if(q && p == NULL){return false;}//都不为NULLif(p->val != q->val){return false;}return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot)
{if(root == NULL){return false;}if(root->val == subRoot->val && isSameTree(root, subRoot)){return true;}return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}

4.5 二叉树的构建与销毁

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    二叉树的构建与遍历
  3. 先创建根结点,再依次创建左子树,右子树
typedef struct TreeNode
{char val;struct TreeNode* left;struct TreeNode* right;
}TreeNode;void inorder_part(struct TreeNode* root, char* arr, int* size)
{if (root == NULL){return;}inorder_part(root->left, arr, size);arr[*size] = root->val;(*size)++;inorder_part(root->right, arr, size);
}char* inorderTraversal(struct TreeNode* root, int* returnSize)
{//根左右//为空树时,不反回空指针//返回数组*returnSize = 0;char* arr = (char*)malloc(100 * sizeof(int));inorder_part(root, arr, returnSize);return arr;
}TreeNode* BuyTreeNode(char val)
{TreeNode* newnode = (TreeNode*)malloc(sizeof(TreeNode));newnode->val = val;newnode->left = newnode->right = NULL;return newnode;
}TreeNode* BinaryTreeCreate(char* a, int n, int* pi)
{TreeNode* root = NULL;if (a[*pi] == '#'){(*pi)++;return NULL;}if (a[*pi] != '#'){root = BuyTreeNode(a[*pi]);}(*pi)++;root->left = BinaryTreeCreate(a, n, pi);root->right = BinaryTreeCreate(a, n, pi);return root;
}int main()
{char* a = (char*)malloc(100 * sizeof(char));char str;int count = 0;while(scanf("%c", &str) != EOF){a[count++] = str;}int i = 0;TreeNode* root = BinaryTreeCreate(a, strlen(a), &i);int returnSize = 0;char* ret = inorderTraversal(root, &returnSize);for (int j = 0; j < returnSize; j++){printf("%c ", ret[j]);}return 0;
}

二叉树的销毁:

void BinaryTreeDestory(TreeNode* root)
{//后序遍历if (root == NULL){return;}BinaryTreeDestory(root->left);BinaryTreeDestory(root->right);free(root);
}

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

思路:使用层序遍历,如果出现NULL后,又出现非NULL指针,那么此树就不是完全二叉树,反之,则是。

int BinaryTreeComplete(TreeNode* root)
{//层序遍历判断是否为完全二叉树Queue q1;QueueInit(&q1);QueuePush(&q1, root);TreeNode* top = QueueFront(&q1);//标志有NULL指针出现int count = 0;while (!QueueEmpty(&q1)){if (top){QueuePush(&q1, top->left);QueuePush(&q1, top->right);}if (top == NULL){count++;}if (count && top){return 0;}QueuePop(&q1);if (!QueueEmpty(&q1)){top = QueueFront(&q1);}}return 1;
}

4.7 补充练习

4.7.1 二叉树的节点数

// 二叉树节点个数
int BinaryTreeSize(TreeNode* root)
{//根结点 + 左子树结点 + 右子树结点if (root == NULL){return 0;}return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

4.7.2 二叉树的叶子节点数

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

4.7.3 二叉树的第K层结点数

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

4.7.4 查找二叉树中为x值的结点

// 二叉树查找值为x的节点
TreeNode* BinaryTreeFind(TreeNode* root, char x)
{//没找到if (root == NULL){return NULL;}//找到了if (root->val == x){return root;}//在左侧找TreeNode* left = BinaryTreeFind(root->left, x);//在右侧找TreeNode* right = BinaryTreeFind(root->right, x);if (left){return left;}return right;
}

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

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

相关文章

Qt之QPluginLoader使用插件子项目及插件间通信(简易框架)(含部分源码+注释)

文章目录 一、项目示例1.导航栏操作页面操作示例图2.打开所有页面操作示例图3.打开指定界面操作示例图3.插件重载操作演示 二、插件逻辑个人理解1.QPluginLoader的简单使用2.子插件的基本要素 三、项目结构&#xff08;思路&#xff09;简述1.定义插件接口类2.定义插件类别一个…

C/C++ 纸张尺寸问题(蓝桥杯)

题目描述&#xff1a; 在 ISO 国际标准中定义了 A 0 A0A0 纸张的大小为 1189 m m 841 m m 1189mm841mm1189mm841mm&#xff0c;将 A 0 A0A0 纸沿长边对折后为 A 1 A1A1 纸&#xff0c;大小为 841 m m 594 m m 841mm594mm841mm594mm&#xff0c;在对折的过程中长度直接取下整…

Python自动化测试:API接口自动化——requests、webSocket

接口自动化测试1 一、requests二、简单示例1.导入/引入库2.请求与响应示例1>简单访问百度主页-GET请求2>简单的登录请求-POST请求3>保存cookies至头信息headers4>其他接口请求时携带headers 三、webSocketwebSocket连接与数据收发示例 本文介绍了借助Python的reque…

什么是同源策略?如何检测跨站点 WebSocket 劫持漏洞?post 表单跳转跨域问题、Ajax跨域请求、浏览器特性和安全策略、WebSocket 协议连接

什么是同源策略?如何检测跨站点 WebSocket 劫持漏洞?post 表单跳转跨域问题、Ajax跨域请求、浏览器特性和安全策略、WebSocket 协议连接。 同源策略(Same Origin Policy)是一种浏览器安全机制,用于保护用户的信息和数据安全。它限制了来自不同源(协议、域名、端口)的网页…

华为手环 8:返校季新宠,助力高效学习与健康生活

随着春节假期的结束&#xff0c;学生们也纷纷踏上了返校的旅途。新的学期&#xff0c;新的气象&#xff0c;让华为手环8为你的带来全新的智能生活体验。它不仅仅是一款风格多变的时尚手环&#xff0c;还拥有了智能消息提醒、100多种运动模式和睡眠监测等强大功能&#xff0c;让…

计算机设计大赛 深度学习疲劳驾驶检测 opencv python

文章目录 0 前言1 课题背景2 实现目标3 当前市面上疲劳驾驶检测的方法4 相关数据集5 基于头部姿态的驾驶疲劳检测5.1 如何确定疲劳状态5.2 算法步骤5.3 打瞌睡判断 6 基于CNN与SVM的疲劳检测方法6.1 网络结构6.2 疲劳图像分类训练6.3 训练结果 7 最后 0 前言 &#x1f525; 优…

基于springboot实现粮食仓库管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现粮食仓库管理系统演示 摘要 粮食作为人类生活的重要物质来源&#xff0c;在粮食流通过程中对于粮食仓库的管理不容忽视&#xff0c;随着我国粮食生产能力的提升以粮食存储管理的不断革新&#xff0c;粮食产量的增加为粮食仓储管理带来了挑战也带来了机遇&am…

蜂窝物联:物联网大数据云平台功能模块简介

蜂窝云平台可远程获取现场环境&#xff08;如温室大棚、稻田&#xff09;的空气温湿度、土壤水分温度、二氧化碳浓度、光照强度及视频图像&#xff0c;通过数据模型分析&#xff0c;可以自动控制湿帘、风机、喷淋滴灌、内外遮阳、顶窗侧窗、加温补光、增氧机等设备&#xff1b;…

MySQL面试题-锁(答案版)

锁 1、MySQL 有哪些锁&#xff1f; &#xff08;1&#xff09;全局锁 加了全局锁之后&#xff0c;整个数据库就处于只读状态了&#xff0c;这时其他线程执行以下操作&#xff0c;都会被阻塞&#xff1a; 对数据的增删改操作&#xff0c;比如 insert、delete、update等语句&…

【深度学习笔记】计算机视觉——R-CNN

区域卷积神经网络&#xff08;R-CNN&#xff09;系列 sec_rcnn 除了 sec_ssd中描述的单发多框检测之外&#xff0c; 区域卷积神经网络&#xff08;region-based CNN或regions with CNN features&#xff0c;R-CNN&#xff09; Girshick.Donahue.Darrell.ea.2014也是将深度模型…

知识图谱辅助的个性化推荐系统

知识图谱辅助的个性化推荐系统 将从下面4个方面展开&#xff1a; 推荐系统的基础知识知识图谱辅助的推荐方法介绍基于embedding的知识图谱推荐方法混合型知识图谱推荐方法 推荐系统的基础知识 1、什么是推荐系统 在当前互联网时代&#xff0c;推荐系统是所有面向用户的互联…

【深度学习笔记】计算机视觉——多尺度目标检测

多尺度目标检测 在 sec_anchor中&#xff0c;我们以输入图像的每个像素为中心&#xff0c;生成了多个锚框。 基本而言&#xff0c;这些锚框代表了图像不同区域的样本。 然而&#xff0c;如果为每个像素都生成的锚框&#xff0c;我们最终可能会得到太多需要计算的锚框。 想象一…

【PHP】PHP实现与硬件串口交互,向硬件设备发送指令数据(下)

目录 一、前言 二、 效果图 三、安装PHP扩展 四、添加模拟串口 五、PHP发送数据给硬件 PHP代码 前端代码 一、前言 上篇文章写到PHP怎么与硬件串口交互之实时接收硬件发送的数据&#xff0c;这里同样是以天平为例&#xff0c;介绍怎么向硬件设备发送数据&#xff0c; 需…

深度学习500问——Chapter02:机器学习基础(3)

文章目录 2.10 主成分分析&#xff08;PCA&#xff09; 2.10.1 主成分分析&#xff08;PCA&#xff09;思想总结 2.10.2 图解PCA核心思想 2.10.3 PCA算法推理 2.10.4 PCA算法流程总结 2.10.5 PCA算法主要优缺点 2.10.6 降维的必要性及目的 2.10.7 KPCA与PCA的区别 2.11 模型评估…

利用excel文件增量同步一个库的数据并自动校正两端数据库条数不一致

利用excel文件增量同步一个库的数据并自动校正两端数据库条数不一致 现在有sqlserver和mysql两个库上的表在进行同步&#xff0c;sqlserver上的是源表&#xff0c;mysql上是目标表。 我们就把sqlserver上的数据同步到mysql上 mysql 是没有数据的。 sqlserver的三个表只是创建了…

利用Python自动化日常任务

在快节奏的现代生活中&#xff0c;时间就是一切。幸运的是&#xff0c;Python提供了一系列强大的库和工具&#xff0c;可以帮助我们自动化那些乏味且重复的任务&#xff0c;从而释放我们的时间&#xff0c;让我们可以专注于更有创造性和有意义的工作。下面&#xff0c;我们将探…

6、Linux-服务管理、权限管理和授权(sudo权限)

一、服务管理 systemctl list-unit-files&#xff1a;查看服务systemctl start 服务名&#xff1a;启动服务systemctl stop 服务名&#xff1a;关闭服务systemctl restart 服务名&#xff1a;重启服务systemctl status 服务名&#xff1a;查看服务状态systemctl enable 服务名…

BioTech - 药物晶型预测与剂型设计 概述

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/136441046 药物晶型预测与剂型设计是指利用计算机模拟和优化药物分子在固态形式下的结构、性质和稳定性&#xff0c;以及与制剂工艺和质…

Python实现微信电脑版微信支付收款监听及支付回调通知

摘要 为什么要监听收款&#xff1f;那是因为现在还有人在使用微信的收款码、商业码、赞赏码实现免签支付&#xff0c;这类实现方法的最终方案还是监听收款结果。 技术原理 通过Python实时解析微信电脑版控件的文本内容来获取信息。不需要Hook和抓包&#xff0c;也不是走任何…

[DevOps云实践] 跨AWS账户及Region调用Lambda

[DevOps云实践] 跨AWS账户及Region调用Lambda 本文將幫大家理清一下幾個問題: 如何跨不同AWS賬戶,不同Region來調用Lambda? 不同Lambda之間如何互相調用?有時我們希望我們的Lambda脚本能夠運行在多個AWS賬戶中的不同Region下,但是,我們還不希望每個下面都去建立一個運行…