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

超详细的堆排序,进来看看吧。

1.堆的基本概念

1.1什么是堆

堆是一种叫做完全二叉树的数据结构,

1.2大堆和小堆

大堆:每个节点的值都大于或者等于他的左右孩子节点的值

小根堆:每个结点的值都小于或等于其左孩子和右孩子结点的值

1.3完全二叉树节点之间的关系

  • leftchild = parent*2 + 1

  • rightchild = parent*2 + 2

  • parent = (child - 1) / 2

1.4堆这个数据结构的实现

heap.h//需要实现的功能列表

#pragma once
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef int HPDataType;
typedef struct Heap
{HPDataType* _a;int _size;int _capacity;
}Heap;// 堆的构建
void HeapCreate(Heap* hp, HPDataType* a, int n);
// 堆的销毁
void HeapDestory(Heap* hp);
// 堆的插入
void HeapPush(Heap* hp, HPDataType x);
// 堆的删除
void HeapPop(Heap* hp);
// 取堆顶的数据
HPDataType HeapTop(Heap* hp);
// 堆的数据个数
int HeapSize(Heap* hp);
// 堆的判空
int HeapEmpty(Heap* hp);

heap.c

堆的向上调整和向下调整

(只能处理一次,创建大小堆的时候需要反复调用)

void Swap(HPDataType* x1, HPDataType* x2)
{HPDataType tmp = *x1;*x1 = *x2;*x2 = tmp;
}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;}}
}void AdjustUp(HPDataType* a, int n, int child)//孩子不断向上
{int parent;assert(a);parent = (child - 1) / 2;while (child > 0){//如果孩子大于父亲,进行交换if (a[child] > a[parent]){Swap(&a[parent], &a[child]);child = parent;parent = (child - 1) / 2;}else{break;}}
}

定义出堆的数据结构

typedef int HPDataType;
typedef struct Heap
{HPDataType* arr;int size;int capacity;
}Heap;

初始化一个堆

void HeapInit(Heap* hp, HPDataType* a, int n)
{int i;assert(hp && a);hp->arr = (HPDataType*)malloc(sizeof(HPDataType) * n);hp->size = n;hp->capacity = n;for (i = 0; i < n; ++i){hp->arr[i] = a[i];}// 建堆: 从最后一个非叶子节点开始进行调整// 最后一个非叶子节点,按照规则: (最后一个位置索引 - 1) / 2// 最后一个位置索引: n - 1// 故最后一个非叶子节点位置: ((n - 1) / 2)-1for (i = (n - 2) / 2; i >= 0; --i){AdjustDown(hp->arr, hp->size, i);}  //for (i = 1; i < n; i++)//{//    AdjustUp(hp->arr,hp->size, i);//}
}

// 建堆: 从最后一个非叶子节点开始进行调整

// 最后一个非叶子节点,按照规则: (最后一个位置索引 - 1) / 2

// 最后一个位置索引: n - 1

// 故最后一个非叶子节点位置: ((n - 1) / 2)-1

  • 我们向下调整来建堆时,要保证当前要调整的节点的左右子树都已经是堆后,才可以向下调整。所以我们要从倒数第一个非叶子结点开始调整

  • 向上调整来建立堆的时候,要保证要调整的节点前面已经是一个合法的堆才行——为了达到这个目的,我们在向上建堆的时候,就需要从数组的第二个元素开始

堆的插入和删除

我们需要注意的是插入删除后我们仍需保持调整后的数组仍是一个堆

void HeapPush(Heap* hp, HPDataType x)
{assert(hp);//检查容量if (hp->size == hp->capacity){hp->capacity *= 2;hp->arr = (HPDataType*)realloc(hp->arr, sizeof(HPDataType) * hp->capacity);}//尾插hp->arr[hp->size] = x;hp->size++;//向上调整AdjustUp(hp->arr, hp->size, hp->size - 1);//因为数据插在尾向不会打乱已有关系,可以直接向上调整
}void HeapPop(Heap* hp)
{assert(hp);//交换Swap(&hp->arr[0], &hp->arr[hp->size - 1]);hp->size--;//向下调整AdjustDown(hp->arr, hp->size, 0);
}HPDataType HeapTop(Heap* hp)
{assert(hp);return hp->arr[0];
}int HeapSize(Heap* hp)
{return hp->size;
}int HeapEmpty(Heap* hp)
{return hp->size == 0 ? 0 : 1;
}void HeapPrint(Heap* hp)
{int i;for (i = 0; i < hp->size; ++i){printf("%d ", hp->arr[i]);}printf("\n");
}

堆的插入,因为数据插在尾向不会打乱已有关系,可以直接向上调整。

堆的删除,因为是删除堆顶的数据,为了防止打乱已有关系,交换数据后向下调整,构建一个新的堆。

测试test.c

void test(void)
{Heap hp;int arr[] = { 0,4,13,45,32,45,2,56,33,32 };HeapInit(&hp, arr, sizeof(arr) / sizeof(arr[0]));HeapPrint(&hp);
}int main()
{test();//TestHeap1();
}

2.向上调整建堆和向下调整建堆的区别

2.1向上调整建堆

时间复杂度计算的是其调整的次数,根据上文的知识我们已经知晓其是从数组的第二个元素开始的,也就是可以理解为第二层的第一个节点。计算的思想非常简单:计算每层有多少个节点乘以该层的高度次,然后累计相加即可。

2.2向下调整建堆

向下调整我们前面已经知道它是从倒数第1个非叶节点开始调整的

每层的调整次数为:该层的节点个数*该层高度减1

一直从倒数第2层开始调直至第1层,并将其依次累加,累加的计算过程和向上调整差不多,都是等比*等差的求和,(但不同的是:每层的调整次数不同)

3.堆的应用

2.1堆排序

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:每个结点的值都大于等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于等于其左右孩子结点的值,称为小顶堆。该算法时间复杂度为O(n log n)。

堆排序算法的原理如下:

​ 1.将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;

​ 2.将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];

​ 3.由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

void HeapSort(Heap* hp, int n)
{// 向上调整建堆 -- N*logN/*for (int i = 1; i < n; ++i){AdjustUp(a, i);}*/// 向下调整建堆 -- O(N)// 升序:建大堆,把最大的依次拿到下面去for (int i = (n - 1 - 1) / 2; i >= 0; --i){AdjustDown(hp->arr, n, i);}// O(N*logN)int end = n - 1;while (end > 0){Swap(&hp->arr[end],&hp->arr[0]);AdjustDown(hp->arr, end, 0);--end;}
}

2.2 topK问题

从n个数据中选出排在前k个的数据。

建一个小堆,堆里假设就是前k个数据,如果有比堆顶大的数据则弹出堆顶数据,在插入新的数据,然后向下调整堆,得到新的小堆,如此往复,直到读完n个数据。

//1. 找最大的K个元素
//假设堆为小堆
void PrintTopK(int* a, int n, int k)
{Heap hp;//建立含有K个元素的堆HeapInit(&hp, a, k);for (size_t i = k; i < n; ++i)  // N{//每次和堆顶元素比较,大于堆顶元素,则删除堆顶元素,插入新的元素if (a[i] > HeapTop(&hp)) // LogK{HeapPop(&hp);HeapPush(&hp, a[i]);}}for(int i = 0; i < k; ++i){printf("%d ",HeapTop(&hp));HeapPop(&hp);}
}//2. 找最小的K个元素
//假设堆为大堆
void PrintTopK(int* a, int n, int k)
{Heap hp;//建立含有K个元素的堆HeapInit(&hp, a, k);for (size_t i = k; i < n; ++i)  // N{//每次和堆顶元素比较,小于堆顶元素,则删除堆顶元素,插入新的元素if (a[i] < HeapTop(&hp)) // LogK{HeapPop(&hp);HeapPush(&hp, a[i]);}}for(int i = 0; i < k; ++i){printf("%d ",HeapTop(&hp));HeapPop(&hp);}
}

用大数据测一下

void TestTopk()
{int n = 1000000;int* a = (int*)malloc(sizeof(int) * n);srand(time(0));//随机生成10000个数存入数组,保证元素都小于1000000for (size_t i = 0; i < n; ++i){a[i] = rand() % 1000000+1000000;}//确定10个最大的数a[5] = 1;a[1231] =  2;a[531] =  3;a[5121] = 4;a[115] = 5;a[2335] = 6;a[9999] =  7;a[76] = 8;a[423] = 9;a[3144] = 10;PrintTopK(a, n, 10);
}
int main()
{test();//TestHeap1();TestTopk();
}

4.附带一张排序算法的表(仅供参考)

相关文章:

超详细的堆排序,进来看看吧。

1.堆的基本概念1.1什么是堆堆是一种叫做完全二叉树的数据结构&#xff0c;1.2大堆和小堆大堆:每个节点的值都大于或者等于他的左右孩子节点的值小根堆:每个结点的值都小于或等于其左孩子和右孩子结点的值1.3完全二叉树节点之间的关系leftchild parent*2 1rightchild parent*…...

线性回归 特征扩展的原理与python代码的实现

文章目录1 多项式扩展的作用2 多项式扩展的函数2.1 接收参数2.2 多项式扩展示例3 多项式扩展的完整实例1 多项式扩展的作用 在线性回归中&#xff0c;多项式扩展是种比较常见的技术&#xff0c;可以通过增加特征的数量和多项式项的次数来提高模型的拟合能力。 举个例子&#…...

订阅关系一致

订阅关系一致指的是同一个消费者Group ID下所有Consumer实例所订阅的Topic、Tag必须完全一致。如果订阅关系不一致,消息消费的逻辑就会混乱,甚至导致消息丢失。本文提供订阅关系一致的正确示例代码以及订阅关系不一致的可能原因,帮助您顺畅地订阅消息。 背景信息 消息队列Ro…...

测试老鸟都在用的接口抓包常用工具以及接口测试工具都有哪些?

目录 接口 接口测试的重要性 常用抓包工具 常用接口测试工具 接口 接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及系统间…...

Delphi 一个函数实现腾讯云最新版(API3.0)短信发送

目录 一、腾讯云短信基本知识 1. 需要在腾讯云后台注册账号 2. 需要在腾讯云中开通短信功能 3. 腾讯云短信版本说明 4. 短信内容的组成 特定规范 二、短信发送函数 三、下载源代码(收费) 一、腾讯云短信基本知识 如今我们随时都收到短信验证码&#xff0c;注册码等等。这是…...

2023年Android现代开发

2023年现代Android开发 下面与大家分享如何构建具有2023年最新趋势的Android应用程序。 Android是什么&#xff1f; Android 是一种基于 Linux 内核并由 Google 开发的开源操作系统。它用于各种设备&#xff0c;包括智能手机、平板电脑、电视和智能手表。 目前&#xff0c…...

自然语言处理(NLP)在医疗领域的应用

自然语言处理&#xff08;Natural Language Processing&#xff0c;NLP&#xff09;是计算机科学领域与人工智能领域中的一个重要方向。它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。在各个领域都有其应用。 其在生物医学领域迅速发展&#xff0c;已经…...

计算机中的浮点数运算

计算机中的浮点数 计算机中以固定长度存储浮点数的方式&#xff0c;造成了浮点数运算过程容易产生上溢和下溢。以float32为例, 其标记位占1bit,指数位占8bit,小数部分占23bit 经典下溢场景 不满足精度导致截断误差 #include <iostream> #include <iomanip> usin…...

看了字节跳动月薪20K+测试岗面试题,让我这个工作3年的测试工程师,冷汗直流....

朋友入职已经两周了&#xff0c;整体工作环境还是非常满意的&#xff01;所以这次特意抽空给我写出了这份面试题&#xff0c;而我把它分享给伙伴们&#xff0c;面试&入职的经验&#xff01; 大概是在2月中的时候他告诉我投递了字节跳动并且简历已通过&#xff0c;2月23经过…...

这两天最好的ChatGPT应用;使用Notion AI提升效率的经验(13);AI编程与程序员的生存 | ShowMeAI日报

&#x1f440;日报合辑 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 硅谷银行风波中&#xff0c;OpenAI 创始人大方帮助硅谷初创公司&#xff1a;钱先拿着用&#xff0c;有了再还 OpenAI 创始人 Sam Altman 的弟弟…...

Linux 内核likely与unlikey

内核源码的时候经常可以看到likely()和unlikely()函数&#xff0c;这两个函数的作用是什么&#xff1f;-- 先得学一学GCC提供的内建函数&#xff01;&#xff01; likely和unlikely内核中的定义 # define likely(x) __builtin_expect(!!(x), 1) # define unlikely(x) __built…...

成功解决主从同步异常之Slave_IO_Running显示为No的问题

前言 MySQL主从同步在做的过程中很容易出问题, 尤其是双主配置,参数多,需要在两台服务器中反复操作,容易搞错导致失败,这里汇总的是主从同步异常之Slave_IO_Running显示为No的解决方案。 文章目录 前言一. 问题重现二. 排查过程2.1 查看UUID是否相同,并修改2.2 修改完UU…...

面试阿里测开岗失败后,被面试官在朋友圈吐槽了......

前一阵子有个徒弟向我诉苦&#xff0c;说自己在参加某大厂测试面试的时候被面试官怼得哑口无言&#xff0c;场面让他一度十分尴尬印象最深的就是下面几个问题&#xff1a;根据你以前的工作经验和学习到的测试技术&#xff0c;说说你对质量保证的理解&#xff1f;非关系型数据库…...

蓝桥杯嵌入式--字符串比较在串口通信中的应用

前言今天做了个模拟题&#xff0c;大致意思是接收上位机发的字符串&#xff0c;然后执行相应操作。思路很明确&#xff0c;就是把接收到的内容进行比较&#xff0c;但是从前我只学过比较数字的方式&#xff0c;即直接用“”进行比较&#xff0c;但是字符串不能使用这个方法&…...

考研408每周一题(2019 41)

2019年(单链表&#xff09; 41.(13分)设线性表L(a1,a2,a3,...,a(n-2),a(n-1),an)采用带头结点的单链表保存&#xff0c;链表中的结点定义如下&#xff1a; typedef struct node {int data;struct node *next; } NODE; 请设计一个空间复杂度为O(1)且时间上尽可能高效的算法&…...

Angular学习笔记(一)

以下内容基于Angular 文档中文版的学习 目录 使用Angular CLI 工具创建项目 HTML标签中{{}}插入值,[]绑定属性,()绑定事件,[(ngModel)]双向绑定 绑定属性 类和样式绑定 事件绑定 双向绑定 循环 IF 定义输入属性 定义输出事件 特殊符号 模板引用变量 页面跳转(路由…...

Linux用户和权限 —— 操作演示

Linux用户和权限——操作演示认知root用户用户、用户组管理查看权限控制修改权限控制- chmod修改权限控制- chownLinux系列&#xff1a; Linux基本命令 —— 操作演示 认知root用户 root用户(超级管理员) 无论是Windows、MacOS、Linux均采用多用户的管理模式进行权限管理。…...

【华为OD机试真题2023 JAVA】单核CPU任务调度

华为OD机试真题,2023年度机试题库全覆盖,刷题指南点这里 单核CPU任务调度 知识点队列优先级队列 时间限制:1s 空间限制:256MB 限定语言:不限 题目描述: 现在有一个CPU和一些任务需要处理,已提前获知每个任务的任务ID、优先级、所需执行时间和到达时间。 CPU同时只…...

News乐鑫科技亮相德国嵌入式展 Embedded World 2023!

3 月 14 日&#xff0c;德国纽伦堡嵌入式展 Embedded World 2023 火热启幕。本届 Embedded World 主题为 “embedded. responsible. sustainable”&#xff0c;乐鑫科技 (688018.SH) 携众多 AIoT 科技成果亮相展会&#xff0c;致力于打造更智能、更互联、更绿色的物联网未来。…...

java如何创建线程

java如何创建线程1. java如何创建线程1.1 通过继承Thread类来创建线程1.2 通过实现Runnable接口来创建线程1.3 通过匿名内部类来创建线程1.4 lambda表达式1.5 通过实现Runnable接口的方式创建线程目标类的优缺点1. java如何创建线程 一个线程在Java中使用一个Thread实例来描述…...

要是早看到这篇文章,你起码少走3年弯路,20年老程序员的忠告

文章目录前言一、程序员的薪资是怎么样的&#xff1f;二、我现在的情况适合做程序员吗&#xff1f;三、大学期间到底应该学些什么&#xff1f;四、工作还是考研&#xff1f;五、总结前言 我是龙叔&#xff0c;一名工作了20多年的退休老程序员。 如果你在工作之前看到这篇文章…...

IP地址的分类

1. 前言 最初设计互联网络时&#xff0c;为了便于寻址以及层次化构造网络&#xff0c;每个IP地址包括两个标识码&#xff08;ID&#xff09;&#xff0c;即网络ID和主机ID。 同一个物理网络上的所有主机都使用同一个网络ID&#xff0c;网络上的一个主机&#xff08;包括网络上工…...

win10下使用docker运行部署nginx,mysql

一、docker的步骤&#xff1a;1.进入docker官网下载安装包2.打开控制面板 - 程序和功能 - 启用或关闭Windows功能&#xff0c;勾选Hyper-V&#xff0c;然后点击确定即可&#xff0c;如图&#xff1a;3.重新启动电脑4.启动Docker在桌面找到Docker for Windows快捷方式&#xff0…...

sprinboot车辆充电桩

sprinboot车辆充电桩演示录像2022开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;ecli…...

仿京东放大镜效果的实现

仿京东放大镜 &#xff08;1&#xff09; 整个案例可以分为三个功能模块 &#xff08;2&#xff09; 鼠标经过小图片盒子&#xff0c; 黄色的遮挡层 和 大图片盒子显示&#xff0c;离开隐藏2个盒子功能 &#xff08;3&#xff09;黄色的遮挡层跟随鼠标功能。 &#xff08;4&…...

ESP32设备驱动-LM35温度传感器驱动

LM35温度传感器驱动 文章目录 LM35温度传感器驱动1、LM35介绍2、硬件准备3、软件准备4、驱动实现1、LM35介绍 LM35 系列是精密集成电路温度传感器,其输出电压与摄氏(摄氏度)温度成线性比例。 因此,LM35 优于以开尔文校准的线性温度传感器,因为用户无需从其输出中减去较大…...

基于深度学习的犬种识别软件(YOLOv5清新界面版,Python代码)

摘要&#xff1a;基于深度学习的犬种识别软件用于识别常见多个犬品种&#xff0c;基于YOLOv5算法检测犬种&#xff0c;并通过界面显示记录和管理&#xff0c;智能辅助人们辨别犬种。本文详细介绍博主自主开发的犬种检测系统&#xff0c;在介绍算法原理的同时&#xff0c;给出Py…...

【IDEA插件开发】环境搭建

基础信息 GRADLE 7.5.1 IDEA IntelliJ IDEA 2020.1.1 (Ultimate Edition) Build #IU-201.7223.91, built on April 30, 2020 Licensed to https://zhile.io You have a perpetual fallback license for this version Subscription is active until July 8, 2089 Runtime ve…...

【蓝桥杯专题】 DP(C++ | 洛谷 | acwing | 蓝桥)

菜狗现在才开始备战蓝桥杯QAQ 文章目录【蓝桥杯专题】 DP&#xff08;C | 洛谷 | acwing | 蓝桥&#xff09;AcWing 1205. 买不到的数目Acwing 1216. 饮料换购【模拟】01背包271. 杨老师的照相排列最长公共上升子序列PPPPPPPP总结【蓝桥杯专题】 DP&#xff08;C | 洛谷 | acwi…...

咪咕MGV3201_ZG_GK国科6323_UWE5621DS_免拆卡刷固件包

咪咕MGV3201_ZG_GK国科6323_UWE5621DS_免拆卡刷固件包 特点&#xff1a; 1、适用于对应型号的电视盒子刷机&#xff1b; 2、开放原厂固件屏蔽的市场安装和u盘安装apk&#xff1b; 3、修改dns&#xff0c;三网通用&#xff1b; 4、大量精简内置的没用的软件&#xff0c;运行…...