C/C++ 堆排序

个人主页:仍有未知等待探索-CSDN博客

专题分栏:数据结构_仍有未知等待探索的博客-CSDN博客

                                                      欢迎大家来指教!

一、前言

今天要介绍的是堆排序。

首先什么是堆?简而言之,堆就是二叉树的数组形式,用数组来存储二叉树。

这个堆和C语言中讲的堆区是不同的两个概念,不要混淆。

二、堆排序

堆排序的核心就是构建一个特殊的二叉树,这个二叉树的特性是:其父节点大于等于(小于等于)其左右孩子结点。

故,最终创建的二叉树的根节点会是该二叉树的最大值(最小值)。

那怎么才能让整个数组中的数据有序呢?那我们就让数组中第一个数和最后一个数进行交换,然后以第一个数和倒数第二个数为端点,继续进行构建堆,然后选出次最小值。以此类推~~~

我以大根堆为例(从数组下标为1的地方开始存储):

1、堆的数据类型

typedef int HpDataType;
typedef struct Heap
{HpDataType* a;//进行存储堆中的数据int size;//该堆的有效数据个数int capacity;//该堆中的容量
}Hp;

2、堆的初始化

//初始化
void Heapinit(Hp* php)
{assert(php);//断言,如果php为空的话,报错php -> a = NULL;php -> size = 0;php -> capacity = 0;
}

3、堆的销毁

//堆的销毁
void HeapDestory(Hp* php)
{assert(php);free(php -> a);//释放掉开辟的空间php -> a = NULL;//防止php -> a为野指针php -> size = 0;php -> capacity = 0;
}

4、堆的创建

// 堆的创建
// k为要插入到堆里面的元素
void Heap_push(Hp* php, int k)
{assert(php); //断言if (php -> size == php -> capacity)// 如果容量不够,扩容{// 如果容量为0,则给个初始值,否则就二倍扩容int size = php -> capacity == 0 ? 4 : php -> capacity * 2;Hp* tmp = (Hp* ) realloc(php -> a, (size + 1) * sizeof(int));if (tmp == NULL) {perror("realloc failed");exit(-1);// 扩容失败则结束程序}php -> a = tmp;php -> capacity = size;	}// 插入到堆的最后php -> a[++ php -> size] = k;// 向上调整,如果比父节点要大就进行交换up(php -> a, php -> size);
}

 5、向上调整

// 向上调整
// idx为要调整元素的下标
void up(int* a, int idx)
{assert(a);int child = idx;// 该结点下标int parent = child / 2;// 该结点的父节点,我是从下标为1开始存的while (child != 1){if (a[parent] < a[child]){Swap(&a[parent], &a[child]);}else{// 不需要调整,就退出break;}// 继续向上找child = child / 2;parent = parent / 2;}
}

 6、删除堆的最后一个元素

该操作的主要作用是将该堆中最大的元素进行归位,并且进行调整除了最后一个元素的二叉树的顺序,使其仍为一个堆。

// 进行删除最后一个元素
void Heappop(Hp* php)
{assert(php);assert(php -> size > 0);Swap(&php -> a[1], &php -> a[php -> size]);php -> size --;int parent = 1;int child = 2 * parent;while (child <= php -> size){// 假设左节点最大,如果右结点比左节点大,就child存右节点下标if (child + 1 <= php -> size && php -> a[child + 1] > php -> a[child]){child += 1;}// 判断孩子结点和父节点的值if (php -> a[parent] < php -> a[child]){Swap(&php -> a[parent], &php -> a[child]);}else {// 不需要则退出break;}parent = child;child = 2 * parent;}
}

 7、取出堆顶元素

// 取出堆顶元素
HpDataType Heaptop(Hp* php)
{assert(php);assert(php -> size > 0);return php -> a[1];
}

三、总代码及其运行结果

#define _CRT_SECURE_NO_WARNINGS  1// 大根堆#include <stdio.h>
#include <assert.h>
#include <stdlib.h>typedef int HpDataType;
typedef struct Heap
{HpDataType* a;// 进行存储堆中的数据int size;// 该堆的有效数据个数int capacity;// 该堆中的容量
}Hp;void Heapinit(Hp* php);// 初始化
void HeapDestory(Hp* php);// 堆的销毁
void Heap_push(Hp* php, int k);// 堆的创建
void Swap(int* a, int* b);// 交换
void up(int* a, int idx);// 向上调整
HpDataType Heaptop(Hp* php);// 取堆顶元素
void Heappop(Hp* php);// 删除堆的最后一个元素int main()
{int a[] = {1, 2, 3, 4, 5, 6, 7};Hp hp;Heapinit(&hp);int len = sizeof(a) / sizeof(a[0]);for (int i = 0; i < len; i++ ){Heap_push(&hp, a[i]);}printf("初始堆:\n");for (int i = 1; i <= len; i ++ ){printf("%d ", hp.a[i]);}printf("\n有序序列:\n");while (hp.size > 0){printf("%d ", Heaptop(&hp));Heappop(&hp);}HeapDestory(&hp);return 0;
}// 初始化
void Heapinit(Hp* php)
{assert(php);// 断言,如果php为空的话,报错php -> a = NULL;php -> size = 0;php -> capacity = 0;
}// 堆的销毁
void HeapDestory(Hp* php)
{assert(php);free(php -> a);// 释放掉开辟的空间php -> a = NULL;// 防止php -> a为野指针php -> size = 0;php -> capacity = 0;
}void Swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}// 向上调整
// idx为要调整元素的下标
void up(int* a, int idx)
{assert(a);int child = idx;// 该结点下标int parent = child / 2;// 该结点的父节点,我是从下标为1开始存的while (child != 1){if (a[parent] < a[child]){Swap(&a[parent], &a[child]);}else{// 不需要调整,就退出break;}// 继续向上找child = child / 2;parent = parent / 2;}
}// 堆的创建
// k为要插入到堆里面的元素
void Heap_push(Hp* php, int k)
{assert(php); //断言if (php -> size == php -> capacity)// 如果容量不够,扩容{// 如果容量为0,则给个初始值,否则就二倍扩容int size = php -> capacity == 0 ? 4 : php -> capacity * 2;Hp* tmp = (Hp* ) realloc(php -> a, (size + 1) * sizeof(int));if (tmp == NULL) {perror("realloc failed");exit(-1);// 扩容失败则结束程序}php -> a = tmp;php -> capacity = size;	}// 插入到堆的最后php -> a[++ php -> size] = k;// 向上调整,如果比父节点要大就进行交换up(php -> a, php -> size);
}// 取出堆顶元素
HpDataType Heaptop(Hp* php)
{assert(php);assert(php -> size > 0);return php -> a[1];
}// 进行删除最后一个元素
void Heappop(Hp* php)
{assert(php);assert(php -> size > 0);Swap(&php -> a[1], &php -> a[php -> size]);php -> size --;int parent = 1;int child = 2 * parent;while (child <= php -> size){// 假设左节点最大,如果右结点比左节点大,就child存右节点下标if (child + 1 <= php -> size && php -> a[child + 1] > php -> a[child]){child += 1;}// 判断孩子结点和父节点的值if (php -> a[parent] < php -> a[child]){Swap(&php -> a[parent], &php -> a[child]);}else {// 不需要则退出break;}parent = child;child = 2 * parent;}
}

 

谢谢大家! 

 

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

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

相关文章

MySQL中order by是怎么工作的?

在如上图中所示的explain的执行结果中&#xff0c;Extra字段中的“Using filesort”表示的就是需要排序&#xff0c;MySQL会给每个线程分配一块内存用于排序&#xff0c;称为sort_buffer。 索引city如上图所示 上述语句的执行流程如下&#xff1a; 1、初始化sort_buffer&…

e2studio开发磁力计LIS2MDL(2)----基于中断信号获取加速度数据

三轴加速度计LIS2DW12开发.2--轮基于中断信号获取加速度数据 概述视频教学样品申请源码下载新建工程工程模板保存工程路径芯片配置工程模板选择时钟设置UART配置UART属性配置设置e2studio堆栈e2studio的重定向printf设置R_SCI_UART_Open()函数原型回调函数user_uart_callback …

5个不买后悔的云服务器推荐(2024年更新)

作为多年站长使市面上大多数的云厂商的云服务器都使用过&#xff0c;很多特价云服务器都是新用户专享的&#xff0c;本文有老用户特价云服务器&#xff0c;阿腾云atengyun.com有多个网站、小程序等&#xff0c;国内头部云厂商阿里云、腾讯云、华为云、UCloud、京东云都有用过&a…

【Python基础】一文搞懂:Python 中 csv 文件的写入与读取

文章目录 1 引言2 CSV 文件简介3 Python 中的 csv 模块4 写入 CSV 文件4.1 基本用法4.2 高级用法 5 读取 CSV 文件5.1 基本用法5.2 高级用法 6 实例演示7 注意事项8 总结 1 引言 在数据处理和数据分析领域&#xff0c;CSV (逗号分隔值) 文件是一种常见的文件格式&#xff0c;用…

2.【CPP】入门(宏||内联函数||拷贝构造||析构函数||构造函数)

0x01.引言 1.实现一个宏函数ADD #define ADD(x,y) ((x)(y))//宏是预编译阶段完成替换&#xff0c;注意括号2.宏的优缺点 优点&#xff1a; 1.增强代码的复用性 2.宏函数不用建立栈帧&#xff0c;提高性能 缺点&#xff1a; 1.不方便调试 2.没有安全检查 0x02.内联函数 1.以空…

漫画演绎策略设计模式

引言 本篇主要通过一小篇漫画的形式给大家讲讲策略模式&#xff0c;由于策略模式本身不是很难&#xff0c;这里就不花太多的言辞描述了&#xff0c;一起看漫画吧 普通设计 从前有一个妈妈&#xff0c;她有一个叛逆的儿子&#xff0c;妈妈每天除了上下班就是要教育儿子&#…

闩锁效应(Latch-up)

闩锁效应&#xff08;Latch-up&#xff09;原理解析 什么是闩锁效应&#xff08;Latch-up&#xff09;&#xff1f; 在CMOS N阱设计中&#xff0c;实际上是由于CMOS电路中基极和集电极相互连接的两个PNP和NPN双极性BJT管子(下图中&#xff0c;侧面式NPN和垂直式PNP)的回路放大…

从无到有:AI绘画API在插画与游戏设计中的应用

引言 随着人工智能技术的快速发展&#xff0c;AI绘画API已经逐渐成为插画和游戏设计领域的新宠。这些API能够将创意与技术完美结合&#xff0c;帮助设计师快速生成高质量的图像&#xff0c;为插画和游戏产业带来了巨大的变革。 AI绘画API的工作原理 AI绘画API基于深度学习和…

Groove闭包

Groovy闭包 - 简书# 闭包 闭包的基础知识 闭包的使用 闭包 this,owner,delegate 的理解 总结 ## 闭包的基础知识 闭包就是一段可以使用参数的代码片段&#xff0c;每个闭包会被编译成...https://www.jianshu.com/p/c73b03cdf986

RK3399平台入门到精通系列讲解(驱动篇)eventpoll结构体详解

🚀返回总目录 文章目录 一、eventpoll 结构体二 、epitem 结构体三、eppoll_entry 结构体eventpoll 结构体:eventpoll 结构体是 epoll 在内核中的核心结构epitem 结构体:epitem 结构体用于表示 epoll 实例中的事件项eppoll_entry 结构体:它的作用就是关联Socket等待队列中…

全网第一篇教你怎么总结多线程知识

于「全景图」&#xff0c;我之前也有一直在构建&#xff0c;可是因为知识储备不够&#xff0c;确实很难构建出来。稍微了解过并发领域知识的人都知道&#xff0c;里面的知识点、概念多而散&#xff1a;线程安全、锁、同步、异步、阻塞、非阻塞、死锁、队列(为什么并发要跟队列扯…

Springboot+vue的毕业论文管理系统(有报告)。Javaee项目,springboot vue前后端分离项目

演示视频&#xff1a; Springbootvue的毕业论文管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的毕业论文管理系统&#xff0c;采用M&#xff08;model&…