目录

一、堆的性质

二、堆的相关基础操作

堆的创建

堆的插入

堆的删除

获取堆顶元素

堆的判空

堆的有效元素个数

堆的销毁

三、堆排序

建堆


一、堆的性质


只要满足以下两点,它就是一个堆:

堆是一个完全二叉树;

第一点,堆必须是一个完全二叉树。完全二叉树要求,除了最后一层,其他层的节点个数都是满的,最后一层的节点都靠左排列,自然堆也具有完全二叉树的所有性质。

堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值。

第二点,堆中的每个节点的值必须大于等于(或者小于等于)其子树中每个节点的值。实际上,我们还可以换一种说法,堆中每个节点的值都大于等于(或者小于等于)其左右子节点的值。这两种表述是等价的。

每个结点的值都大于或等于其左右孩子结点的值,我们叫做“大顶堆”。

每个结点的值都小于或等于其左右孩子结点的值,我们叫做“小顶堆”。


二、堆的相关基础操作


堆的创建


// 堆的构建
void HeaPCreate(Heap* hp, HPDataType* a, int n)
{//申请一个和传入的数组一样大的空间保存堆hp->arry = (HPDataType*)malloc(sizeof(HPDataType)*n);if (NULL == hp->arry){assert(hp);return;}memcpy(hp->arry, a, n * 4);hp->capacity = n;hp->size = n;for (int root = (n - 2) / 2; root >= 0; root--){//用向下调整从下向上(从第一个非叶子节点开始)依次对堆中的节点进行调整AjustdownHeap(hp,root);}
}

堆的插入

只能在尾插入然后进行向上调整

void HeapPush(HP* php, HPDataType x)
{assert(php);if (php->size == php->capacity){//申请新空间size_t newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType* tmp = realloc(php->a, sizeof(HPDataType) * newCapacity);if (tmp == NULL){printf("realloc failed\n");exit(-1);}//把a指向新的地址php->a = tmp;//更新容量php->capacity = newCapacity;}//将x放在堆尾php->a[php->size] = x;++php->size;// 向上调整,控制保持是一个小堆AdjustUp(php->a, php->size - 1);
}void AdjustUp(HPDataType* a, size_t child)
{//找到他的父亲size_t parent = (child - 1) / 2;//到堆顶了就不需要再进行调整while (child > 0){//如果孩子比父亲小,那就进行交换if (a[child] < a[parent])//if (a[child] > a[parent]){Swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}void Swap(HPDataType* pa, HPDataType* pb)
{HPDataType tmp = *pa;*pa = *pb;*pb = tmp;
}

堆的删除

只能删除堆顶的元素,其方法是将堆顶的元素和堆尾进行交换,删除堆尾的元素,然后将堆顶元素进行向下调整

// 删除堆顶的数据。(最小/最大)
void HeapPop(HP* php)
{assert(php);assert(php->size > 0);//交换堆顶  堆尾元素Swap(&php->a[0], &php->a[php->size - 1]);//删除堆尾元素--php->size;AdjustDown(php->a, php->size, 0);
}void AdjustDown(HPDataType* a, size_t size, size_t root)
{size_t parent = root;//默认是左孩子size_t child = parent * 2 + 1;//走到堆尾就结束,不用再进行调整while (child < size){// 1、选出左右孩子中小的那个if (child + 1 < size && a[child + 1] < a[child]){++child;}// 2、如果孩子小于父亲,则交换,并继续往下调整if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}

获取堆顶元素

HPDataType HeapTop(HP* php)
{assert(php);//数组长度大于0 才能运行,否则非法访问assert(php->size > 0);return php->a[0];
}

堆的判空

bool HeapEmpty(HP* php)
{assert(php);return php->size == 0;
}

堆的有效元素个数

size_t HeapSize(HP* php)
{assert(php);return php->size;
}

堆的销毁

void HeapDestroy(HP* php)
{assert(php);free(php->a);php->a = NULL;php->size = php->capacity = 0;
}

三、堆排序

建堆

升序:建大堆(不能建小堆)

如果建小堆,选出最小的元素之后,剩下的数据全乱了,需要再次建堆,才能选出次小的数据,时间复杂度高O(n^2)

大堆排序思想:将第一个元素和最后一个元素交换,然后把最后一个元素看做数组外的元素(n-1),对第一个元素进行向下调整,找出次大的数,继续上述操作

降序:建小堆

我们可以直接对数组建堆,使数组满足堆的性质

例如:

int main()
{int a[] = { 4, 2, 7, 8, 5, 1, 0, 6 };HeapSort(a,sizeof(a)/sizeof(a[0]));for (int i = 0; i < sizeof(a) / sizeof(int); ++i){printf("%d ", a[i]);}printf("\n");
}void HeapSort(int* a, int n)
{assert(a);//我们可以把数组看成依次插入n个数//每次对他们进行向上调整就可以形成一个堆/*for(int i = 1;i<n;i++){AdjustUp(a, i);}*///向下调整//找到最后一个数的父亲,然后进行向下调整//依次往上走,直到走到根节点for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(a, n, i);}size_t end = n - 1;while (end > 0){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);--end;}
}

2.top-k问题:

TOP-K 问题:即求数据结合中前 K 个最大的元素或者最小的元素,一般情况下数据量都比较大 。
比如:专业前 10 名、世界 500 强、富豪榜、游戏中前 100 的活跃玩家等。
对于 Top-K 问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了 ( 可能数据都不能一下子全部加载到内存中 ) 。最佳的方式就是用堆来解决,

基本思路如下:

这次文章到这里结束了,谢谢大家观看

点个赞吧!

浅谈——堆(数据结构)相关推荐

  1. BZOJ 4152 浅谈堆优化的SPFA算法

    世界真的很大 其实这道题一看就能想到最短路 关键是怎么建边 看一下数据,200000个点 每个点两两建边的话肯定会超时 好像说多了先看一下题吧: description 给定平面上的n个点,定义(x1 ...

  2. 浅谈算法和数据结构: 五 优先级队列与堆排序

    原文:浅谈算法和数据结构: 五 优先级队列与堆排序 在很多应用中,我们通常需要按照优先级情况对待处理对象进行处理,比如首先处理优先级最高的对象,然后处理次高的对象.最简单的一个例子就是,在手机上玩游戏 ...

  3. 浅谈数据结构和数据类型

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u012540337/article/details/80499226 最近总是被这两个概念混淆,抽出 ...

  4. php链表和联表的区别,PHP_浅谈PHP链表数据结构(单链表),链表:是一个有序的列表,但 - phpStudy...

    浅谈PHP链表数据结构(单链表) 链表:是一个有序的列表,但是它在内存中是分散存储的,使用链表可以解决类似约瑟夫问题,排序问题,搜索问题,广义表 单向链表,双向链表,环形链表 PHP的底层是C,当一个 ...

  5. php mysql 链表_浅谈PHP链表数据结构(单链表)

    链表:是一个有序的列表,但是它在内存中是分散存储的,使用链表可以解决类似约瑟夫问题,排序问题,搜索问题,广义表 单向链表,双向链表,环形链表 PHP的底层是C,当一个程序运行时,内存分成五个区(堆区, ...

  6. 【python】数据结构和算法 + 浅谈单链表与双链表的区别

    有这么一句话说"程序=数据结构+算法",也有人说"如果把编程比作做菜,那么数据结构就好比食材(菜),算法就好比厨艺(做菜的技巧)". 当然这是笼统的说法,不过也 ...

  7. 浅谈Java中的栈和堆

    人们常说堆栈堆栈,堆和栈是内存中两处不一样的地方,什么样的数据存在栈,又是什么样的数据存在堆中? 这里浅谈Java中的栈和堆 首先,将结论写在前面,后面再用例子加以验证. Java的栈中存储以下类型数 ...

  8. 浅谈python高级数据结构—— 字符串(str)

    浅谈python高级数据结构-- 字符串(str) 在python中字符串可以说的运用的特别多了.在当我们input 输入的时候,也是一个str字符串类型,我们今天就来简单的说一下(字符串)类型的一些 ...

  9. java程序的装载与检查_浅谈Java类型装载、连接与初始化

    类型装载.连接与初始化 Java虚拟机通过装载.连接和初始化一个Java类型,使该类型可以被正在运行的Java程序所使用.其中装载就是把二进制形式的Java class文件读入Java虚拟机中去;连接 ...

最新文章

  1. AIoT成功的关键要素
  2. window下从硬盘安装ubuntu双系统
  3. 更改android AVD模拟器创建路径位置的方法
  4. ASP.NET中application对象的用法(面试题)
  5. Python中模块(Module)和包(Package)的区别
  6. Web前端必备-Nginx知识汇总
  7. 无人值守的自动 dump(二)
  8. 编程之美----子数组的最大乘积
  9. php 所有子类,php获取分类以下的全部子类方法
  10. 【本人秃顶程序员】SpringMVC工作原理详解
  11. 力扣——分数排名(数据库的题
  12. vue富文本编辑器wangeditor必填判断
  13. 光遇挂_创作者与一束光的七年之约:陈星汉的Sky光遇详解
  14. 一、Netflix Eureka
  15. echarts地图api series_使用echarts结合百度地图API做迁徙图
  16. kafka安装和相关命令操作——修改中
  17. PIC16F877A单片机 (中断与定时器Timer1)
  18. Windows 安装Docker碰到 cannot enable hyper-v service
  19. Integration using Feynman technique
  20. imx6 vpu程序分析

热门文章

  1. 二叉树的编程与实现(C语言)
  2. C语言中比较大小的函数模板,关于C++中定义比较函数的三种方法
  3. [源码]Delphi源码免杀之函数动态调用 实现免杀的下载者
  4. 东芝存储器公司将收购台湾光宝科技的SSD业务
  5. SLAM/VIO学习总结
  6. labelme生成的json文件批量转化为label图片
  7. C#ToolStrip
  8. 计算机修改wif教程,如何把笔记本电脑设置wifi热点教程
  9. 接口调用常见异常处理方案
  10. 机器学习工程师 - Udacity 项目 0: 预测你的下一道世界料理