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

目录

  • 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.定义插件类别一个…

提取阿里国际站商家电话的爬虫软件

引言: 随着电子商务的快速发展&#xff0c;越来越多的商家选择在阿里国际站上开设店铺。然而&#xff0c;对于想要联系某些商家或者进行商务合作的人来说&#xff0c;商家的联系电话往往是非常重要的信息。在这篇文章中&#xff0c;我们将介绍如何使用爬虫软件提取阿里国际站商…

装箱问题(贪婪策略:首次适应递减(First Fit Decreasing, FFD))

装箱问题&#xff08;贪婪策略:首次适应递减&#xff08;First Fit Decreasing, FFD&#xff09;&#xff09; 装箱问题是一种典型的组合优化问题&#xff0c;它可以用多种贪婪&#xff08;greedy&#xff09;策略来解决。贪婪算法通过在每一步选择当前最优的解决方案&#xf…

IDEA推荐使用十大插件

在本文中&#xff0c;我们将介绍 10 多个最好的 IntelliJ IDEA 插件&#xff0c;以提高工作效率并在更短的时间内完成更多工作。如果将这些插件合并到您的工作流程中&#xff0c;您将能够更有效地应对开发挑战。 1、TabNine TabNine 是一个 IntelliJ IDEA 插件&#xff0c;可…

c# 获取oracle 表及表内容

1、 /// <summary> /// 获取表名列 /// </summary> /// <param name"owner"></param> private void GetTableNameList(string owner) { TableNameGridList.Clear(); GetT…

YOLOv5语义分割7.0推理代码封装

YOLOv5语义分割7.0推理代码封装 YOLOv5语义分割7.0推理代码封装 YOLOv5语义分割7.0推理代码封装 import argparse import os import numpy as np import re import sys from pathlib import Path import torchFILE = Path(__file__).resolve() ROOT = FILE.parents[1

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;在对折的过程中长度直接取下整…

CSS常用选择器(通配符选择器,标签选择器,类选择器,id选择器……),你知道了多少?

目录 CSS常用选择器 一、什么是选择器 二、通配符选择器 基本语法格式&#xff1a; 三、标签选择器 基本语法格式&#xff1a; 四、类选择器 基本语法格式&#xff1a; 五、id选择器 基本语法格式&#xff1a; 六、类选择器还是 ID 选择器&#xff1f; 区别 1&…

芯片设计后端遇到的各种文件类型和文件后缀

芯片设计后端遇到的各种文件类型和文件后缀 文件类型 描述 文件后缀 netlist网表文件 verilog文件格式&#xff0c;记录了芯片里各个instance的逻辑连接关系 .v (for Verilog netlists) Lib&#xff0c;liberty timing file 记录了cell的timing信息及一定power信息。有的…

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

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

leetcode-重复的子字符串

459. 重复的子字符串 题解&#xff1a; 首先&#xff0c;我们需要找到字符串s的所有子串。然后&#xff0c;我们需要检查这些子串是否可以通过重复多次构成原字符串s。如果找到了这样的子串&#xff0c;返回True&#xff0c;否则返回False。 class Solution:def repeatedSub…

什么是同源策略?如何检测跨站点 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;…

Java零基础-包机制

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一个人虽可以走的更快&#xff0c;但一群人可以走的更远。 我是一名后…

实践课项目化

程序设计实践 项目内容&#xff1a; 这是一门物联网工程专业的必修课程&#xff0c;基于大学计算机基础和C编程课程&#xff0c;要求使用C语言设计和实现一个小型信息管理系统。课程提供两个小项目供学生选择&#xff0c;学生分组完成其中一个项目&#xff0c;每组5人。 成果…

MySQL面试题-锁(答案版)

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

C# 异步操作汇总

在C#中&#xff0c;异步操作&#xff08;Asynchronous Operations&#xff09;可以提高程序的性能和响应能力。通常情况下&#xff0c;程序会等待某个操作完成之后才会继续执行下一个操作&#xff0c;这会导致程序的运行速度变慢。而异步操作可以让程序在等待某个操作完成的同时…