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

二叉树堆的建立与排序

在数据结构中,二叉树是非常好用的一种数据结构,这节暂时按下不表。这节课主要介绍堆的建立与使用。

堆,是二叉树中一种很特殊的结构,首先,他必须是满二叉树,也就是除了最后一层以外,其他层都是满的。

堆对于节点数据也有要求,其基本按照某种规律进行排序。首先堆分为大堆和小堆。大堆上大小大小堆上小下大。有非常大的差距。并且在堆中每个节点也满足完全二叉树的父子节点规律,既child=parent*2+1 | 2,1和2取决于是子左节点还是右节点。

堆的实现


typedef int HPDataType;
typedef struct Heap
{HPDataType* _a;int _size;int _capacity;
}Heap;//child = father*2+1 | 2;

一个堆的基本结构体如上图所示,它应该有一个特定类型的指针_a,一个代表堆目前数量的size,一个代表目前容量的_capacity。为什么选择顺序表作为建堆类型呢?首先是因为堆不需要在中间插入数据,他是满二叉树;第二是因为利用数组来建队可以发现数组的下标之间的关系,就是这个公式:child=parent*2+1 | 2,便于进行计算。本文前半部分基本以小堆为准。

堆的初始化

void HeapInit(Heap* php)
{assert(php);php->_a = NULL;php->_capacity = 0;php->_size = 0;
}//函数初始化Heap* HeapKCreat(int k)
{Heap* hp = (Heap*)malloc(sizeof(Heap));if (hp == NULL){perror("fail:hp creat");exit(1);}int* arr = (int*)malloc(sizeof(int) * k);hp->_a = arr;hp->_size = 0;hp->_capacity = 0;return hp;
}函数创建

堆的创建分为两种方式,一种是在外面申请空间,然后再函数内设置数据,一种是直接在函数内部完成一切,总体而言还是简单的把相关数据进行简单设置。

堆的销毁

void HeapDestory(Heap* hp)
{assert(hp);free(hp->_a);hp->_a = NULL;hp->_capacity = hp->_size = 0;
}

堆的销毁也较为简单,便是顺序表的销毁。其中有一个地方需要注意,便是需要先把数组给free掉。

堆的两种整理方式

void AdjustUp(HPDataType* obj, int child)
{int parent = (child - 1) / 2;while (obj[parent] > obj[child] && child > 0){Swap(&obj[child], &obj[parent]);child = parent;parent = (child - 1) / 2;}
}

第一个函数是从下往上整理,先设置一个parent变量,这个变量便是孩子的父节点,因为/操作符的整除性,所以会自动得到对应节点。接着比较子节点大小与父节点大小的,若父节点大于子节点,那就父子对换,并让子为父,在重新设置父节点。一直到父节点不再大于子节点或者子节点到了顶部。

void AdjustDowm(HPDataType* obj, int n, int parent)
{int child = parent * 2 + 1;while (child < n){if (obj[child + 1] < obj[child] && child + 1 < n){child++;}if (obj[parent] > obj[child]){Swap(&obj[child], &obj[parent]);parent = child;child = parent * 2 + 1;}elsebreak;}
}

另一种方案是从上往下整理,同样的初始造个儿子操作。接着,判断儿子不要超过数组数据大小范围,这个设置出来的儿子是左儿子,接着判断右儿子和左儿子的大小关系.若是右儿子要大一些的话,那就让右儿子来和父节点较量较量。接着,若父节点大于子节点的话,那便换位置。一直到循环结束。

这两种方法总体而言方法二会更好一点,方法二的时间复杂度为O(logN),方法一为O(N).具体计算方法可以上b站查一下。

堆的数据增加

void HeapPush(Heap* hp, HPDataType x)
{assert(hp);if (hp->_capacity == hp->_size){int newcapacity = hp->_capacity == 0 ? 4 : hp->_capacity * 2;HPDataType* b = (HPDataType*)realloc(hp->_a, newcapacity * sizeof(HPDataType));if (b == NULL){exit(1);}hp->_a = b;hp->_capacity = newcapacity;}hp->_a[hp->_size] = x;hp->_size++;AdjustUp(hp->_a, hp->_size - 1);
}

堆的push首先断言一下,防止输入的结构体为空。接着,若此时容量等于当前数据量,那么会进入扩容阶段。此处建立一个一个newcapacity,利用三目操作符,如果此时容量大小为0,那么调整为4,若不是0,那么扩容两倍。接着realloc一个新的结构体指针,其大小便是调整后的新容量。接着在判断一下realloc是否成功,接着将realloc出来的指针给结构体中的_a指针,然后吧容量变为新的容量。接着就开始进行赋值,把数据x放在数组的最后一个空地址,接着将size++。再然后向上调整或者向下调整都是可以的。这里便选择了向上调整了。

堆的删除

void HeapPop(Heap* hp)
{assert(hp);assert(hp->_size > 0);Swap(&hp->_a[0], &hp->_a[hp->_size - 1]);hp->_size--;AdjustDowm(hp->_a, hp->_size, 0);}

堆的删除首先要先确定不是空指针和堆里确实有数据。接着交换一下堆顶数据和堆底数据。将hp的size--,保证后续读取不到要删除的数据。接着将堆顶数据向下调整即可。

堆的部分简单判断与取数据

HPDataType HeapTop(Heap* hp)
{assert(hp);assert(hp->_size > 0);return hp->_a[0];
}//取堆顶数据int HeapSize(Heap* hp)
{assert(hp);return hp->_size;
}取堆大小int HeapEmpty(Heap* hp)
{assert(hp);return hp->_size == 0;
}判断堆是否空了

堆的排序

void HeapSort(int* a, int n)
{//for (int i = 0; i < n; i++)//{//	AdjustUp(a, a[i]);//}空间要求较多,建议从下往上整,既下面方案int end = n - 1;while (end--)//{Swap(&a[0], &a[end]);AdjustDowm(a, n, 0);}
}

说是堆的排序,但其实针对于任何混乱的数组,将他们整理成有序的堆。堆的排序分为两种方式,第一种方法是从上面的代码,但是其堆空间的要求较多,因此较为推荐下面的方法。

TopK问题

我们建堆是为了什么呢?建堆一个很重要的意义便是找出最大的几个数据或者最小的几个数据。一个很大的数据本,要求前k个最大的数据,可以通过什么方法呢?一个相对好用的方法就是通过建容量为k的小堆,然后逐渐替换堆内的数据来达成这个容量为k的小堆内的数据便是原数据库的前k个最大的数据。具体实现过程如下

创建数据库

void CreateNDate()
{// 造数据int n = 100000;srand(time(0));const char* file = "data.txt";FILE* fin = fopen(file, "w");if (fin == NULL){perror("fopen error");return;}for (size_t i = 0; i < n; ++i){int x = rand() % 1000000;fprintf(fin, "%d\n", x);}fclose(fin);
}

首先我们先来利用time的伪随机来创建一个数据库,内部包含10万个随机的数据,并将这些数据写入名字为data的txt文件,这就是我们后面用来举例的数据库了。

topk数据库

void PrintTopK(int k)
{int* arr = (int*)malloc(sizeof(int)*k);char* file = "data.txt";FILE* fin = fopen(file, "r");for (int i = 0; i < k; i++){fscanf(fin, "%d ",&arr[i]);}int a = 0;while (fscanf(fin, "%d ", &a)!=EOF) {if (a > arr[0]){arr[0] = a;AdjustDowm(arr,k,0);}}for (int i = 0; i < k; i++){printf("%d ", arr[i]);}}

首先,我们需要先创建出一个容量符合小堆的数组,因为我这里的数据都是整型,因此便直接使用int类型了。接着打开data文件,首先将data中前10个数据写入arr数组,接着设置一个普普通通的int类型数据a,接着进入while循环,fscanf会返回读到的数据数量,当没有数据的时候,则返回EOF,当还有数据的时候,将数据写入a中,判断a和arr[0]的大小关系。若arr[0]小于a,则将a写入数组中成为堆顶。接着向下调整刚刚写入的数据。直到已经将data文件中的数据全部读了一遍,此时数组中包含的数据便是所有的最大数据。接着将这些数据打印出来,便得到了TopK个数据了。

相关文章:

二叉树堆的建立与排序

在数据结构中&#xff0c;二叉树是非常好用的一种数据结构&#xff0c;这节暂时按下不表。这节课主要介绍堆的建立与使用。 堆&#xff0c;是二叉树中一种很特殊的结构&#xff0c;首先&#xff0c;他必须是满二叉树&#xff0c;也就是除了最后一层以外&#xff0c;其他层都是…...

【软件测试】Bug 篇

哈喽&#xff0c;哈喽&#xff0c;大家好~ 我是你们的老朋友&#xff1a;保护小周ღ 今天给大家带来的是 【软件测试】Bug 篇&#xff0c;首先了解, 什么是Bug, 如何定义一个Bug, 如何描述一个 Bug, Bug的级别, 和 Bug 的生命周期, 以及测试人员跟开发人员产生争执如何处理,…...

oracle 多表查询

3.6多表查询 当查询的数据并不是来源一个表时&#xff0c;需要使用多表连接操作完成查询。多表连接查询通过表之间的关联字段&#xff0c;一次查询出多个表的数据。 3.6.1等值连接 等值连接也称为简单连接(Simple Joins)或者内连接(Inner Join)。通过等号来判断连接条件中的数据…...

layui 可以使点击图片放大

layui可以使图片点击放大&#xff0c;不用在写jquyery了真是很方便。 操作示例 引入 <link rel"stylesheet" href"https://cdn.jsdelivr.net/npm/layui-layer3.1.1/dist/layui.css" /> <script src"https://cdn.bootcdn.net/ajax/libs/jqu…...

制作网上3D展馆需要什么技术并投入多少费用?

制作网上3D展览馆项目&#xff0c;需要考虑以下技术和预算方面的信息&#xff1a; 技术需求&#xff1a; 1、三维建模技术&#xff1a;利用3D软件&#xff08;3ds max、maya、blender、c4d等&#xff09;制作展馆和展品的3D模型 2、Web3D技术&#xff1a;如WebGL&#xff0c…...

C++标准库容器类——string类

引言 在c中&#xff0c;string类的引用极大地简化了字符串的操作和管理&#xff0c;相比 C 风格字符串&#xff08;char*或cahr[]&#xff09;&#xff0c;std::string 提供了更高效和更安全的字符串操作。接下来让我们一起来深入学习string类吧&#xff01; 1.string 的构造…...

Qt --- 常用控件的介绍 --- 其他控件

一、QPushButton QWidget中设计到的各种属性/函数/使用方法&#xff0c;针对接下来要介绍的Qt的各种控件都是有效的。 使用QPushButton表示一个按钮&#xff0c;这也是当前我们最熟悉的一个控件了。这个类继承了QAbstractButton&#xff0c;这个类是一个抽象类&#xff0c;是…...

spark读取数据性能提升

1. 背景 spark默认的jdbc只会用单task读取数据&#xff0c;读取大数据量时&#xff0c;效率低。 2. 解决方案 根据分区字段&#xff0c;如日期进行划分&#xff0c;增加task数量提升效率。 /*** 返回每个task按时间段划分的过滤语句* param startDate* param endDate* param …...

一次使用threading.Thread来实现Pytorch多个模型并发运行的失败案例

文章目录 背景我的做法&#xff08;但证明不起效果&#xff09; 背景 我有多个pytorch GPU模型&#xff0c;他们有不同的参数&#xff08;也就是说不是共享的&#xff09;&#xff0c;但是相同的数据输入&#xff0c;想要并发运行。 不并发运行&#xff0c;当然就是循环喽。 …...

HashMap源码

简介 HashMap 是一种基于哈希表的 Map 接口实现&#xff0c;它存储键值对&#xff08;key-value pairs&#xff09;&#xff0c;并允许使用键来快速检索值。在 Java 中&#xff0c;HashMap 是 java.util 包的一部分&#xff0c;它不是同步的&#xff0c;这意味着它不是线程安全…...

探索 Web Speech API:实现浏览器语音识别与合成

引言 Web Speech API 是一项由 W3C 开发的 Web 标准&#xff0c;为开发者提供了在 Web 应用程序中实现语音识别和语音合成的能力。通过 Web Speech API&#xff0c;我们可以让网页与用户进行语音交互&#xff0c;实现更加智能化和便捷的用户体验。本文将深入探讨 Web Speech A…...

python基础题练习

1.可否定义一个sum函数呢&#xff1f;返回指定区间的值的和&#xff1f;例如&#xff0c;区间[1,4]的和为123410返回指定区间值的平方的和呢&#xff1f;立方呢&#xff1f; 代码&#xff1a; # 计算从start到end&#xff08;包括end&#xff09;的所有整数的和。 def sum_ra…...

工业交换机如何保证数据的访问安全

在现代工业自动化环境中&#xff0c;工业交换机作为关键的网络设备&#xff0c;扮演着数据传输和信息交互的重要角色。为了确保数据的访问安全&#xff0c;工业交换机不仅具备高效的转发性能&#xff0c;还集成了多层次的安全防护机制&#xff0c;以抵御各种潜在的网络威胁。 首…...

jmeter得到的文档数据处理

通过前面jmeter得到的输出文档&#xff0c;这里是txt文档&#xff0c;里面包含了很多条数据&#xff0c;每条数据的结构如下&#xff1a; 【request】 uuid&#xff1a;xxxxxxx timestamp&#xff1a;xxxxxxxx No.x question&#xff1a;xxxxxxx 【response】 code&#…...

12- 【JavaWeb】校园快递管理系统-数据库建设

项目概述 开发一个Javaweb校园快递管理系统&#xff0c;包含以下功能&#xff1a; 数据库设计 首先,我们需要设计数据库的表结构。主要包括以下表: 学生表: 存储学生的基本信息&#xff0c;姓名、手机号。快递表: 存储快递的信息&#xff0c;快递单号、收件人、收件人手机号、…...

Windows本地连接远程服务器并创建新用户详细记录

前提可知&#xff1a; &#xff08;1&#xff09;服务器IP地址&#xff1a;x.x.x.x &#xff08;2&#xff09;服务器名称&#xff1a;root&#xff08;一般默认为root&#xff0c;当然也有别的名称&#xff09; &#xff08;3&#xff09;服务器登陆密码&#xff1a;**** 一、…...

【kaggle竞赛】毒蘑菇的二元预测题目相关信息和思路求解代码

毒蘑菇的二元预测 您提供了很多关于不同二元分类任务的资源和链接&#xff0c;看起来这些都是Kaggle竞赛中的参考资料和高分解决方案。为了帮助您更好地利用这些资源&#xff0c;这里是一些关键点的总结&#xff1a; Playground Season 4 Episode 8 主要关注的竞赛: 使用银行…...

Pytest-allure如何在测试完成后自动生成完整报告?

一、完整步骤 常规allure报告的生成方法是在pytest全部用例执行完成后&#xff0c;手动在命令行执行如 allure generate ./temps -o ./report --clean每次用例执行完成后都要重复如此的操作&#xff0c;十分繁琐。 可以使用如下方式让用例执行完成后自动生成报告到当前目录下…...

数据结构-树(基础,分类,遍历)

数据结构-树 1.什么是树&#xff1f; 在计算机科学中&#xff0c;树是一种常用的非线性数据结构&#xff0c;用于表示具有层次关系的数据。与线性数据结构&#xff08;如数组和链表&#xff09;不同&#xff0c;树结构以节点&#xff08;Nodes&#xff09;和边&#xff08;Ed…...

CodeGeeX4:程序员的高效助手,多语言代码生成神器!

你是否曾在编写代码时&#xff0c;为复杂的语法、逻辑错误而绞尽脑汁&#xff1f;或是在面对多个编程语言的切换时&#xff0c;感觉脑子快要爆炸&#xff1f;别担心&#xff01;一款全新的多语言代码生成神器——CodeGeeX4&#xff0c;正悄然成为程序员们的“救命稻草”。它不仅…...

小程序组件间通信

文章目录 父传子子传父获取组件实例兄弟通信 父传子 知识点&#xff1a; 父组件如果需要向子组件传递指定属性的数据&#xff0c;在 WXML 中需要使用数据绑定的方式 与普通的 WXML 模板类似&#xff0c;使用数据绑定&#xff0c;这样就可以向子组件的属性传递动态数据。 父…...

Homebrew安装与切换下载源

一、安装 1.Homebrew的官网地址 https://brew.sh/zh-cn/ 2.执行命令行安装 /bin/bash -c “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)” 3.无法连接到https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh的地址 解决…...

C#回调函数

1、定义并初始化委托 public delegate void CallbackDelegate(string message);//定义一个委托类型CallbackDelegate callbackDelegate;//声明一个委托对象/// <summary>/// 定义委托对应的函数/// </summary>/// <param name"str"></param>…...

Matplotlib绘制热力图

热力图&#xff08;Heatmap&#xff09;是一种使用颜色来表示数值强度的数据可视化工具。它常用于以下场景&#xff1a; 热力图的适用场景 数据的相关性分析&#xff1a;在统计学中&#xff0c;热力图常用于展示变量之间的相关性&#xff0c;尤其是当数据量较大时&#xff0c;…...

手写SpringMVC

1、开发HspDispatcherServlet 2、完成客户端/浏览器可以请求控制层 目的&#xff1a;发出url请求时&#xff0c;经过前端控制器&#xff0c;找到Monster的List方法&#xff0c;把结果再打回去 3、从web.xml动态获取hspspringmvc.xml 4、完成自定义Service注解功能 目的&…...

mysql学习教程,从入门到精通,SQL 删除数据(DELETE 语句)(18)

1、SQL 删除数据&#xff08;DELETE 语句&#xff09; 在编写SQL中的DELETE语句时&#xff0c;需要非常小心&#xff0c;因为一旦执行&#xff0c;被删除的数据就无法恢复了&#xff08;除非你有备份&#xff09;。DELETE语句用于从数据库表中移除一条或多条记录。这里&#x…...

周边游小程序开发

开发一个周边游小程序是一个既有趣又富有挑战性的项目&#xff0c;它可以帮助用户发现周边的旅游景点、活动、美食和住宿等&#xff0c;提升用户的旅游体验。以下是开发周边游小程序的基本步骤和一些建议&#xff1a; 1.市场调研与需求分析 目标用户定位&#xff1a;确定你的用…...

初级前端面试

1.介绍自己 2.介绍一下之前做过的项目以及接触的业务 3.最近学的技术&#xff0c;接触的是哪一块&#xff08;回答了vue3&#xff09; 4.vue3在什么时候调用接口 beforeCreate 在实例初始化之后&#xff0c;数据观测 (data observer) 和 event/watcher 事件配置之前被调用。 用…...

微软AI核电计划

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

图片马赛克处理(Java)

1.需求 给图片的指定区域打码给整张图片打码马赛克方格取色支持中心点取色和随机取色马赛克支持灰度处理 2.源码 package com.visy.utils;import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOE…...