堆及堆排序(超超超超超详细讲解~~~~)-----数据结构
文章目录
- 1.堆的概念及结构
- 2.堆的实现
- 2.1 堆的两种基本算法
- 2.1.1堆的向下调整算法
- 2.1.2堆的向上调整算法
- 2.2 堆的创建
- 2.3堆的插入
- 2.4堆顶元素的删除
- 2.4建堆的时间复杂度
- 3.堆的应用
- 3.1堆排序
1.堆的概念及结构
将一个关键码的集合K={k0,k1,k2, … ,k n-1},把它所有元素按照完全二叉树的顺序存储方式存储在一个一维数组中,且该完全二叉树满足每个父节点大于(小于)其左右孩子节点,则称为大堆(小堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆
堆的性质:
~堆中每个节点的值总是不大于或不小于其父节点的值
~堆总是一棵完全二叉树
2.堆的实现
补充:代码中的传参的CpSize compare为比较函数的函数指针变量
typedef int HeapType;//堆中元素类型的重命名(利于修改堆中元素类型的修改)
typedef int (*CpSize)(HeapType x, HeapType y);//比较函数的函数指针类型重命名
int Max(HeapType x, HeapType y)
{return x > y;
}
int Min(HeapType x, HeapType y)
{return x < y;
}
//函数传参根据建大堆或小堆传Max或Min即可
2.1 堆的两种基本算法
堆的两种的基本算法:堆的向下调整算法(用于建堆和堆删除),堆的向上调整算法(用于元素插入)
2.1.1堆的向下调整算法
前提:左右子树必须是一个堆,才能调整
给定一个数组,其逻辑上看做一棵完全二叉树,从根节点开始的向下调整算法可以把它调整为一个小堆。
int array [] = { 18 , 14 , 56 , 16 , 17 }; (建小堆)
//向下调整算法
//假设下标以parent的父节点,左右子树均满足堆结构的情况下,而实现的算法
void AdjustDown(Heap* hp, int parent,CpSize compare)
{assert(hp);int child = parent * 2 + 1;int size = hp->size;while (child<size){if (child+1<size&&hp->compare(hp->arr[child+1],hp->arr[child])){child += 1;}if (hp->compare(hp->arr[child],hp->arr[parent])){Swap(hp->arr + child, hp->arr + parent);parent = child;child = parent * 2 + 1;}else{return;}}
}
2.1.2堆的向上调整算法
向上调整算法,意在与插入元素于数组末尾会破坏堆结构,因而从底至上调整元素位置
int arr [] ={ 5, 10 , 15 , 19};
插入元素 1 之后
//从最后一个非叶子节点开始,向上调整
void AdjustUp(Heap* hp,int child,CpSize compare)
{assert(hp);int parent = (child - 1) / 2;//child从最后一个元素下标(可得最后一个非叶子节点的下标)开始递减while (parent>=0){if (hp->compare(hp->arr[child], hp->arr[parent])){Swap(hp->arr + child, hp->arr + parent);child = parent;parent = (child - 1) / 2;}else{return;}}
}
2.2 堆的创建
由二叉树本身的递归构造性质以及向下调整算法可知,我们可由最后一个非叶子节点(落实于n元素数组中,即下标为(n-1)/2的元素)开始——即满足了堆左右子树堆结构的前提条件,进行向下调整算法,逐步构成大堆的子结构(建大堆)
int array []={ 1, 5, 3 , 8, 7, 6};(大堆)
//堆的构建
void HeapCreate(Heap* hp, HeapType* arr, int n,CpSize compare)
{assert(hp);hp->capacity = n;hp->size = 0;HeapType* a_ = (HeapType*)malloc(sizeof(HeapType) * hp->capacity);if (a_ == NULL){assert(a_);return;}hp->arr = a_;memcpy(hp->arr,arr,sizeof(HeapType)*n);hp->size = n;hp->compare = compare;for (int root = (hp->size - 2) / 2; root >= 0; root--){AdjustDown(hp, root,compare);}
}
2.3堆的插入
思想:将元素插入数组中的最后一个元素(即完全二叉树中的最后一个节点),在进行向上调整算法,直到满足堆
图片信息可参照向上调整内容!!!
注:不知道是否有铁铁产生过为什么不能使用向下调整法来解决插入问题的疑惑!!!!
实则因为在插入元素之后破坏了堆左右子树为堆结构的前提条件,故便不能是向下调整法来解决插入问题
//扩容
void HeapCheakCapacity(Heap* hp)
{assert(hp);if (hp->size == hp->capacity){HeapType* cur = (HeapType*)realloc(hp->arr, sizeof(HeapType) * hp->capacity * 2);if (cur == NULL){printf("realloc");return;}hp->arr = cur;hp->capacity *= 2;}
}
//堆的插入
void HeapPush(Heap* hp, HeapType x)
{HeapCheakCapacity(hp);hp->size++;hp->arr[hp->size - 1] = x;//向上调整AdjustUp(hp, hp->size - 1,hp->compare);
}
2.4堆顶元素的删除
将堆顶元素与最后一个元素进行置换,之后删除最后一个元素,再通过向下调整算法实现堆的删除。
//堆的删除(删除堆顶元素)
void HeapPop(Heap* hp)
{if (HeapEmpty(hp)){return;}HeapCheakCapacity(hp);Swap(hp->arr + 0, hp->arr + (hp->size - 1));hp->size--;AdjustDown(hp, 0,hp->compare);//AdjustUp(hp, hp->size - 1,hp->compare);---错误,因为修改堆顶元素和堆底元素将不满足堆结构
}
2.4建堆的时间复杂度
建堆的时间复杂度为O(n);
堆为完全二叉树,满二叉树也为完全二叉树的一种特殊情况(满二叉树不影响堆时间复杂度的计算)
3.堆的应用
3.1堆排序
堆排序即利用堆的思想来进行排序,分为两个步骤
- 建堆
-----升序:建大堆
-----降序:建小堆
2.利用堆删除思想来进行排序
图形展示
int array[]={ 1 , 5 , 3 , 8 , 7 , 6};
始图为建堆完成时,逻辑结构图(可参照上述建堆过程)
//堆排序
void HeapSort(Heap* hp,CpSize compare)
{int child = hp->size - 1;int size = hp->size;while (child){Swap(hp->arr + 0, hp->arr + child);hp->size--;AdjustDown(hp, 0, compare);child--;}hp->size = size;
}
堆及堆排序(超超超超超详细讲解~~~~)-----数据结构相关推荐
- 开关电源-反激+单级PFC超低纹波超低THD
由于时间关系,本文就做一款简单的"60W-无频闪-单级PFC-反激恒流电源"来跟大家(指初学者,高手就不用看了)一起从入门走向精通. ⊙名称:60W-无频闪-单级PFC-反激恒流电 ...
- Java基础18-String类【String类的特点对象个数常用方法】【超详细讲解】
Java基础-String类[超详细讲解] String类的特点 String在java.lang.String包中 1:特点 (1)String类型不能被继承,因为由final修饰 (2)Strin ...
- Python的零基础超详细讲解(第十三天)-Python的类与对象
基础篇往期文章如下: Python的零基础超详细讲解(第一天)-Python简介以及下载 Python的零基础超详细讲解(第二天)-Python的基础语法1 Python的零基础超详细讲解(第三天)- ...
- Python的零基础超详细讲解(第十二天)-Python函数及使用
基础篇往期文章: Python的零基础超详细讲解(第一天)-Python简介以及下载_编程简单学的博客-CSDN博客 Python的零基础超详细讲解(第二天)-Python的基础语法1_编程简单学的博 ...
- Python的零基础超详细讲解(第七天)-Python的数据的应用
往期文章 Python的零基础超详细讲解(第一天)-Python简介以及下载_编程简单学的博客-CSDN博客 Python的零基础超详细讲解(第二天)-Python的基础语法1_编程简单学的博客-CS ...
- Python的零基础超详细讲解(第五天)-Python的运算符
往期文章 Python的零基础超详细讲解(第一天)-Python简介以及下载_编程简单学的博客-CSDN博客 Python的零基础超详细讲解(第二天)-Python的基础语法1_编程简单学的博客-CS ...
- kdj超卖_kdj超买超卖是什么意思?kdj指标里说的“超买区,超卖区”什么意思?...
在分析股票的走势以及股票买卖点的时候,我们经常会使用一些指标来作为工具进行分析,比如KDJ指标等,最近有人问kdj超买超卖是什么意思?对此小编给大家搜集了有关KDJ指标和超买超卖指标的一些内容. kd ...
- python高级语法装饰器_Python高级编程——装饰器Decorator超详细讲解上
Python高级编程--装饰器Decorator超详细讲解(上篇) 送你小心心记得关注我哦!! 进入正文 全文摘要 装饰器decorator,是python语言的重要特性,我们平时都会遇到,无论是面向 ...
- everything便携版和安装版区别_什么是超极本?超极本和笔记本的区别科普知识...
众所周知,笔记本又被称为"便携式电脑",笔记本相比台式机主要区别就是在于机身小巧,便于携带.笔记本是个总称大的类别,由于定位不同,市场上分别有上网本.游戏本.商务本.超极本等,它们 ...
- 内存超频时序怎么调_电脑内存条专业科普,内存选购、内存品牌、内存安装、内存时序体质、内存超频频率详细讲解...
有很多兄弟经常问,什么牌子的内存条好啊?我用PS.剪辑软件需要多大内存条?内存条怎么超频啊? 所以,今天我们来详细讲解一下内存条. 一.什么是内存条? 内存条又叫随机存取存储器(英文缩写RAM),是与 ...
最新文章
- MIT类人机器人开始耍杂技了,看这个后空翻它漂亮吗?
- Linux下解决用户不能执行sudo的方法
- 如何将int类型数据转换成byte数组
- 黑客入侵“在线影院”全过程2
- JAVA WEB开发环境与搭建
- Deepin v20依赖错误,检测更新失败解决办法
- TensorFlow学习笔记(十一)读取自己的数据进行训练
- ubuntu16.04下面的redis desktop manger的使用
- 把Hybris安装时输出的日志重定向到一个本地文件中
- 用Hamcrest验证DateTime和日期
- (桌面虚拟化最佳实践--呼叫中心系统优化之二)存储和服务器优化项目
- java catch用法_java – 如何避免使用try … catch块
- SQL数据库中日期时间类型,按日期group by 实现
- 低代码平台-竞品分析ABP框架
- 求边界点 -- Python
- C#简单银行管理系统
- springboot+Rabit实战一:(Rabbit MQ windows 环境搭建)
- 小麦苗微信公众号文章链接地址
- SSM框架终极篇——Spring、SpringMVC、MyBatis整合练习(超级详细)
- C语言编程题:输入多个字符串,输出其中最短的字符串。