当前位置: 首页 > news >正文

数据结构之四:堆和二叉树

堆的实现:SData/Heap/heap.c · Hera_Yc/bit_C_学习 - 码云 - 开源中国

树的概念

:是一个非线性数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。

把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。

  • 有一个特殊的结点,称为根结点,根节点没有前驱结点
  • 除根节点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……、Tm,其中每一个集合Ti(1<= i<= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继
  • 因此,树是递归定义的。

树形结构中,子树之间不能有交集,否则就不是树形结构

(树中不能构成回路,不能有孤立的点)。

如何理解树是递归定义的呢?

相关概念

 树的结构定义

链式表示

 数组表示

 二叉树

二叉树概念

一棵二叉树是结点的一个有限集合,该集合:

  1. 或者为空。
  2.  由一个根节点加上两棵别称为左子树和右子树的二叉树组成。
  3. 二叉树不存在度大于2的结点。
  4. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树
特殊的二叉树
  •  满二叉树:一个二叉树,如果每一个层的结点数都达到最大值(2),则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K。那么,结点总数是(2^K - 1),则它就是满二叉树。
  • 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的满二叉树是一种特殊的完全二叉树。(假设有k层的完全二叉树,前k-1层都是满的,最后一层可以不满,但必须是从左到右连续)。

 二叉树性质

1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1)个结点。

2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2^h -1

3. 对任何一棵二叉树, 如果度为0其叶结点个数为n0 , 度为2的分支结点个数为n2 ,则有n0=n2+1

即:度为0(叶子结点)的数量 = 度为2的结点数量 + 1 。

3.在具有 2n 个结点的完全二叉树中,叶子结点个数为( )
A n
B n+1
C n-1
D n/2

解析:假设叶子结点右x个,则度为2的结点右x-1个

总节点数  =  x   +   (x  - 1)  +  度为1的结点数量

所以:总数量= 2*n =x+(x-1)+1   = > x=n

4.二叉树的高度:(用于堆的选树、搜索二叉树、平衡搜索二叉树

 二叉树存储

二叉树的逻辑结构是一棵树,物理结构分为顺序存储和链式存储两种结构。

数组实现

 ------------------------------------------------二叉树实现在文章末尾 ------------------------------------------------ 

:实际上就是数组形式存储完全二叉树。(逻辑结构是完全二叉树,物理结构是数组)

堆的作用:堆排序效率高、选数等

向下调整算法

(向下调整算法是堆中最重要的算法,堆、堆排序等都需要调整算法来支撑。

向下调整算法构建堆:

前提是:根节点的左右字数必须是大堆或者小堆。

//向下调整算法 
//左右子树必须保证:都是小堆(或者大堆)
static void AdjustDown(HPDataType* a, int n, int root)
{int parent = root;int child = parent * 2 + 1;//默认是左孩子更小while (child<n){//找出左右孩子中小的一个if (child+1<n && a[child + 1] < a[child]){++child;}//如果孩子小于父亲则交换if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent*2+1;}else{break;}}
}
 数组建堆

向下调整算法用于建堆

//arr是传入的数据 arr[n]
void HeapInit(Heap* php, HPDataType* arr, int n)
{assert(php);php->_a = (HPDataType*)malloc(sizeof(HPDataType) * n);if (php->_a == NULL){printf("%s\n", strerror(errno));return;}memcpy(php->_a, arr, sizeof(HPDataType) * n);//内存拷贝php->_size = n;php->_capacity = n;//数组建堆//利用的向下调整算法:// 从最下面的第一个非叶子结点开始调整,// 一层层完成小堆的构建//直到根节点,在对根节点向下调整int i = 0;for (i=(php->_size-1);i >= 0; i--){AdjustDown(php->_a, php->_size, i);}//
}
 向上调整算法

向上调整算法用于入堆。

     向上调整算法与向下调整类似,不过是从子节点往父节点走。对于堆而言,父节点和子节点的下标关系是必须掌握的。

void AdjustUp(HPDataType* arr,int n,int child)
{//从子节点往父结点调整//由child得出parentint parent= (child-1)/2;while(child>=0){if(arr[child]<arr[parent]){Swap(&arr[child],&arr[parent]); //child=parent;parent=(child-1)/2;  //迭代向上}else{break;}}
}

堆排序:见排序与查找-CSDN博客。

入堆
void HeapPush(Heap* php, HPDataType x)
{assert(php);if (php->_size == php->_capacity){php->_capacity *= 2;HPDataType* tmp = (HPDataType*)realloc(php->_a,sizeof(HPDataType) * (php->_size));if (tmp == NULL){printf("%s\n", strerror(errno));return;}php->_a = tmp;}php->_a[php->_size++] = x;AdjustUp(php->_a, php->_size, php->_size-1);}

与堆有关的OJ题:面试题 17.14. 最小K个数 - 力扣(LeetCode)(典型的TopK问题)

N个树中找出最大或最小的前K个数?

  • 排序  问题:a、N*logN的效率能否进一步提高?  b、假设N非常大,内存不够排序
  • 建一个大小为K的堆来解决问题

eg:找最大的前K个,建一个大小为K的小堆,比堆顶大则进堆(顶替掉堆顶的数据,然后向下调整)。

  • 大堆性质:堆顶的元素一定是最大的。(找最小的K个数)。
  • 小堆性质:堆顶的元素一定是最小的。(找最大的K个数)。

解法一在:leetcode/TopK/test_1.c · Hera_Yc/bit_C_学习 - 码云 - 开源中国 

//建K大小的堆解法
void Swap(int* x, int* y) {int tmp = *x;*x = *y;*y = tmp;
}void AdjustDown(int* arr, int n, int root) {int parent = root;int child = parent * 2 + 1;while (child < n) // child不越界{if (child + 1 < n && arr[child + 1] > arr[child]) // 大堆找更大的孩子{child++;}if (arr[child] > arr[parent]) // 大堆的父节点更大{Swap(&arr[child], &arr[parent]);parent = child;child = 2 * parent + 1; // 向下迭代} else {break;}}
}int* smallestK(int* arr, int arrSize, int k, int* returnSize) {*returnSize = k;if (k == 0)return NULL;int* retArr = (int*)malloc(sizeof(int) * k);*returnSize = k;int i = 0;// 建K个数的大堆:for (i = 0; i < k; i++) {retArr[i] = arr[i];}for (i = (k - 1 - 1) / 2; i >= 0; i--) {AdjustDown(retArr, k, i);} // 大堆建立完成:K个数的大堆int j = 0;for (j = k; j < arrSize; j++) {if (arr[j] < retArr[0]) {retArr[0] = arr[j];AdjustDown(retArr, k, 0);}}return retArr;
}

 ------------------------------------------------堆到此结束 ------------------------------------------------

二叉树

伪树

        在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。由于现在对二叉树结构掌握还不够深入,为了降低学习成本,此处手动快速创建一棵简单的二叉树,快速进入二叉树操作学习,等二叉树结构了解的差不多时,我们反过头再来研究二叉树真正的创建方式。

BTNode* BuyNode(BTDataType ch)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));node->_data = ch;node->_left = NULL;node->_right = NULL;return node;
}
//一个树的增删查改没有意义
//这里写一颗伪树
BTNode* A = BuyNode('A');
BTNode* B = BuyNode('B');
BTNode* C = BuyNode('C');
BTNode* D = BuyNode('D');
BTNode* E = BuyNode('E');
BTNode* f = BuyNode('f');
A->_left = B;
A->_right = C;
B->_left = D;
B->_right = E;
D->_left = f;

(学习二叉树的目的是为了掌握更加深层的数据结构,因此会边学边补充)

任何一个二叉树,都要看作三个部分:

1、根节点。2、左子树。3、右子树。

遍历 

  • 深度优先遍历:先往深处走,无路可走是退回来 访问其他结点。(递归和栈实现)。
  • 广度优先遍历:一层层的走,走完一层走下一层。(队列实现)。

树不同于其他的数据结构:

  1. 简单的树的增删查改没有意义。
  2. 单独的二叉树没有意义。
  3. 平衡二叉树和搜索二叉树才有实际意义。
深度优先遍历 
// 二叉树前序遍历
void PreOrder(BTNode* root);
// 二叉树中序遍历
void InOrder(BTNode* root);
// 二叉树后序遍历
void PostOrder(BTNode* root);
typedef char BTDataType;
typedef struct BinaryTree
{BTDataType _data;struct BinaryTree* _left;struct BinaryTree* _right;
}BTNode;
//前序
void PreOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}printf("%c ", root->_data); //根PreOrder(root->_left);		//左子树PreOrder(root->_right);		//右子树
}
int TreeSize(BTNode* root)
{if (root == NULL)return 0;elsereturn 1 + TreeSize(root->_left) + TreeSize(root->_right);
}

关于TreeSize如何返回值?

广度优先遍历 

广度优先遍历:即层序遍历,与递归无关,通过队列的性质(先进先出)来实现。

 结点个数
// 二叉树节点个数
int BinaryTreeSize(BTNode* root);
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);

实现

int BinaryTreeSize(BTNode* root)
{if (root == NULL)return 0;elsereturn 1 + TreeSize(root->_left) + TreeSize(root->_right);
}
int BinaryTreeLeafSize(BTNode* root)
{if (root == NULL){return 0;}else if(root->_left == NULL && root->_right == NULL){return 1;}else{return TreeLeafSize(root->_left) + TreeLeafSize(root->_right);}
}

 

// 二叉树第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);
}

 查找

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->_data == x)return root;BTNode* node = BinaryTreeFind(root->_left, x);if (node)return node;node = BinaryTreeFind(root->_right, x);if (node)return node;return NULL;
}
销毁
// 二叉树销毁
void BinaryTreeDestory(BTNode* root);
// 二叉树销毁
void BinaryTreeDestory(BTNode* root)
{if (root == NULL)return;BinaryTreeDestory(root->_left);BinaryTreeDestory(root->_right);free((root));//后序free不需要保存左和右root = NULL;
}
判断一棵树是否是完全二叉树
// 判断二叉树是否是完全二叉树
//是返回1,不是返回0
int BinaryTreeComplete(BTNode* root)
{//完全二叉树的层序遍历是两段:非空结点+空节点Queue q;QueueInit(&q);if (root == NULL)return 0;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){QueueDestory(&q);return 0;}}QueueDestory(&q);return 1;
}

------------------------------------------本文二叉树到此结束-----------------------------------------------

到这里,二叉树的学习进程仅有40%左右,其余待补充.....

相关文章:

数据结构之四:堆和二叉树

堆的实现:SData/Heap/heap.c Hera_Yc/bit_C_学习 - 码云 - 开源中国 树 树的概念 树&#xff1a;是一个非线性数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。 把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就…...

【论文阅读】国际开源发展经验及其对我国开源创新体系建设的启示

作者&#xff1a;包云岗老师 包云岗老师是计算机体系结构方向的大牛&#xff0c;推动了体系结构方面的开源事业! 欢迎对本栏目感兴趣的人学习"一生一芯"~ 学习体会&#xff1a; 承接前文&#xff0c;唐志敏老师讲到已有的软硬件生态系统和开发成本制约了对新结构的探…...

redis击穿,穿透,雪崩以及解决方案

目录 击穿 解决方案一 解决方案二 穿透 解决方案 雪崩 解决方案 击穿 指的是单个key在缓存中查不到&#xff0c;去数据库查询&#xff0c;这样如果并发不大或者数据库数据量不大的话是没有什么问题的。 如果数据库数据量大并且是高并发的情况下那么就可能会造成数据库压…...

时频转换 | Matlab格拉姆角和场Gramian angular summation field一维数据转二维图像方法

目录 基本介绍程序设计参考资料获取方式 基本介绍 时频转换 | Matlab格拉姆角和场Gramian angular summation field一维数据转二维图像方法 程序设计 clear clc % close all load x.mat % 导入数据 x x(1:5120); % 本数据只选择5120个点进行分析 fs 6400 ; % 数据采样频…...

qt QCryptographicHash详解

1、概述 QCryptographicHash是Qt框架中提供的一个类&#xff0c;用于实现加密散列函数&#xff0c;即哈希函数。哈希函数能够将任意长度的数据转换为固定长度的哈希值&#xff0c;也称为散列值或数据指纹。这个哈希值通常用于数据的完整性校验、密码存储等场景。QCryptographi…...

亚马逊云科技大语言模型加速OCR应用场景发展

目录 前言Amazon Bedrock关于OCR解决方案Amazon Bedrock进行OCR关键信息提取方案注册亚马逊账号API调用环境搭建 总结 前言 大语言模型是一种基于神经网络的自然语言处理技术&#xff0c;它能够学习和预测自然语言文本中的规律和模式&#xff0c;可以理解和生成自然语言的人工…...

什么是分库?分表?分库分表?

分库分表&#xff0c;是企业里面比较常见的针对高并发、数据量大的场景下的一种技术优化方案&#xff0c;所谓“分库分表”&#xff0c;根本不是一回事&#xff0c;而是三件事&#xff0c;他们要解决的问题也都不一样。 这三个事分别是“只分库不分表”、“只分表不分库”、以…...

QT 中 sqlite 数据库使用

一、前提 --pro文件添加sql模块QT core gui sql二、使用 说明 --用于与数据库建立连接QSqlDatabase--执行各种sql语句QSqlQuery--提供数据库特定的错误信息QSqlError查看qt支持的驱动 QStringList list QSqlDatabase::drivers();qDebug()<<list;连接 sqlite3 数据库 …...

不一样的CSS(4)--icon图标系列之svg

序言 上一节内容我们讲解了如何利用css去画一个五角星&#xff0c;其中包括了使用svg的方法&#xff0c;有些小伙伴们对svg的使用不是很了解&#xff0c;那么本节内容我们主要来讲一下&#xff0c;关于svg标签的的使用。 目录 序言一、svg的介绍二、安装SVG扩展插件三、SVG基…...

Level DB --- Cache

class Cache是Level DB中的重要的数据结构&#xff0c;它是一个LRU&#xff08;Least Recently Used&#xff09; Cache的实现。这里面的判断条件主要是内存大小&#xff08;而不是存储entry的个数&#xff09;。当内存达到上界&#xff0c;会释放不被使用的entry&#xff08;存…...

学在西电录播课使用python下载,通过解析m3u8协议、多线程下载ts视频块以及ffmpeg合并

本文涵盖的内容仅供个人学习使用&#xff0c;如果侵犯学校权利&#xff0c;麻烦联系我删除。 初衷 研究生必修选逃&#xff0c; 期末复习怕漏过重点题目&#xff0c;但是看学在西电的录播回放课一卡一卡的&#xff0c;于是想在空余时间一个个下载下来&#xff0c;然后到时候就…...

Springboot3介绍

一、Springboot3简介: https://docs.spring.io/spring-boot/docs/current/reference/html/getting-started.html?spmwolai.workspace.0.0.68b62306Q6jtTw#getting-started.introducing-spring-boot 无论使用XML、注解、Java配置类还是他们的混合用法&#xff0c;配置文件过于…...

Oracle 11G DataGuard GAP 修复过程(通过主库scn增备恢复)

Oracle 11G DataGuard GAP 修复 &#xff08;通过主库scn增备恢复&#xff09; 介绍 DG GAP 顾名思义就是&#xff1a;DG不同步&#xff0c;当备库不能接受到一个或多个主库的归档日志文件时候&#xff0c;就发生了 GAP。 那么&#xff0c;如果遇到GAP如何修复呢&#xff1f…...

WLAN AutoConfig服务假死?重启服务恢复网络连接!

目录 背景&#xff1a; 过程&#xff1a; 可能引起原因&#xff1a; 具体解决步骤&#xff1a; 方法一&#xff1a; 方法二&#xff1a; 总结&#xff1a; 背景&#xff1a; 这个问题困扰我好长一段时间了&#xff0c;每次下班将电脑关机后&#xff0c;次日早上电脑开机…...

【linux】(30)shell-条件判断

if 语句 if 语句是 Shell 脚本中用于条件判断的基本结构。 基本语法 if 语句的基本语法如下&#xff1a; if [ condition ] thencommands ficondition 是要测试的条件。commands 是在条件为真时要执行的命令。 示例 简单条件判断 #!/bin/bashif [ 1 -eq 1 ] thenecho &q…...

docker安装启动问题解决排查

一、安装docker报错 刚开始安装docker报这个错&#xff1a; Error: Transaction test error: file /usr/libexec/docker/cli-plugins/docker-buildx from install of docker-ce-cli-1:20.10.8-3.el8.x86_64 conflicts with file from package docker-buildx-plugin-0:0.14.0…...

《MySQL 查询进阶:复杂查询语句的魅力》

一、引言 MySQL 的复杂查询语句就像是一把神奇的钥匙&#xff0c;能够打开数据世界的大门&#xff0c;展现出数据的无限魅力。本文将带你深入探索 MySQL 查询进阶技巧&#xff0c;从常用查询到子查询&#xff0c;再到视图的运用&#xff0c;让你领略复杂查询语句的强大功能。 …...

OpenHarmony-3.HDF框架(2)

OpenHarmony HDF 平台驱动 1.平台驱动概述 系统平台驱动框架是系统驱动框架的重要组成部分&#xff0c;它基于HDF驱动框架、操作系统适配层(OSAL, operating system abstraction layer)以及驱动配置管理机制&#xff0c;为各类平台设备驱动的实现提供标准模型。 系统平台驱动(…...

人大金仓(KingBaseEs)数据库操作手册

人大金仓数据库&#xff08;KingbaseES&#xff09;是由北京人大金仓信息技术股份有限公司&#xff08;简称人大金仓&#xff09;自主研发的、具有自主知识产权的通用关系型数据库管理系统。 官方下载地址&#xff1a;KingbaseES 人大金仓数据库 KES技术文档在线手册&#xf…...

Flink+Paimon实时数据湖仓实践分享

随着 Paimon 近两年的推广普及&#xff0c;使用 FlinkPaimon 构建数据湖仓的实践也越来越多。在 Flink 实时数据开发中&#xff0c;对于依赖大量状态 state 的场景&#xff0c;如长周期的累加指标计算、回撤长历史数据并更新等&#xff0c;使用实时数仓作为中间存储来代替 Flin…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

Qemu arm操作系统开发环境

使用qemu虚拟arm硬件比较合适。 步骤如下&#xff1a; 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载&#xff0c;下载地址&#xff1a;https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...