堆 最小堆 最大堆 堆排序(小到大,大到小)

简介: 堆 最小堆 最大堆 堆排序(小到大,大到小)

导航


1.了解什么是堆

2.如何创建最小堆,最大堆

3.新增值在堆中如何进行

4.完整的堆排序,升序和降序(两种方式)


——————————————————————————————————————


1.了解什么是堆


树型结构与图型结构的差别:


看是否有回路,无回路的是树型,有回路的是图型



满二叉树可以用数组进行存储,层次遍历顺序存储

设置其中父节点为k,儿子节点(左结点,右节点) 其中左节点 为2*k, 右节点为 2 * k+1

高度为log2^N


其中最典型的应用就是堆(也就是完全二叉树)



完全二叉树:




——————————————————————————————————————


2.如何将堆转化为最小堆,最大堆


有两层的直接用父结点来比较

三层的应该有倒数一层的右边节点开始依次往下



代码如下:(创建最小堆)


//这里用的是数组的方式存储堆
void siftdown(int i)  //输入的是从i点往下找
{
  int t,flag=0;  //flag用来表示无需再进行往下查找 
  //从i位置开始,判断是否有左孩子,并且没有找到最佳位置 
  while(i*2<=n&&flag==0)
  {
  if(h[i]>h[i*2]) //比较父节点与左节点的大小 
    t = i*2;
  else
    t = i;
  if(i*2+1<=n){   //判断是否存在右孩子 
    if(h[t]>h[i*2+1])  //比较上一次父节点与左节点的最小值与右孩子大小 
    t = i*2+1;
  }
  if(t!=i){  //判断得到最小值是否为父节点,是的话flag标志1,不是的话交换,继续往下找 
    swap(t,i);
    i=t;
  }
  else
    flag = 1;
  }
}


创建最大堆:只需要将父节点与左右孩子节点的判大小符号换一下就可以了


——————————————————————————————————————


3.新增值在堆中如何进行


先插入到堆中最后一个位置,在进行与父节点依次比对,找到最合适的位置



整个都用数组保存

代码:


//这里弄得是最小堆 
void siftup(int i)
{
  int i,flag=0;   //flag等于0表示当前子节点比父节点小 
  if(i==1) return;   //如果为根节点直接返回 
  while(i!=1&&flag==0)   
  { 
  if(h[i]<h[i/2])
    swap(i,i/2);
  else
    flag=1;
  i=i/2;    //让子节点等于父节点的位置 
  }
}


——————————————————————————————————————


4.完整的堆排序,升序和降序


输入提示:
14
99 5 36 7 22 17 46 12 2 19 25 28 1 92
升序:
#include <stdio.h>
int h[101]; //用来存放堆的数组
int n;  //存放堆的个数
void swap(int x,int y)
{
  int t;
  t = h[x];
  h[x] = h[y];
  h[y] = t;
} 
void siftdown(int i)
{
  int t,flag=0;  //flag用来表示无需再进行往下查找 
  //从i位置开始,判断是否有左孩子,并且没有找到最佳位置 
  while(i*2<=n&&flag==0)
  {
  if(h[i]>h[i*2]) //比较父节点与左节点的大小 
    t = i*2;
  else
    t = i;
  if(i*2+1<=n){   //判断是否存在右孩子 
    if(h[t]>h[i*2+1])  //比较上一次父节点与左节点的最小值与右孩子大小 
    t = i*2+1;
  }
  if(t!=i){  //判断得到最小值是否为父节点,是的话flag标志1,不是的话交换,继续往下找 
    swap(t,i);
    i=t;
  }
  else
    flag = 1;
  }
}
void create()
{
  int i;
  for(i=n/2;i>=1;i--)
  siftdown(i);
}
//用于返回最小值
int deletemax()
{
  int t;
  t=h[1];
  h[1]=h[n];
  n--;   //删除一位
  siftdown(1);  //进行最小堆
  return t;
}
int main()
{
  int i,num;
  scanf("%d",&num);
  for(i=1;i<=num;i++)
  scanf("%d",&h[i]);
  n = num;
  //建立最小堆
  create();
  //删除顶部元素,接着将最后一个元素放入第一个顶点中,输出删除的元素
  for(i=1;i<=num;i++)
  printf("%d ",deletemax()); 
  return 0;
}



其中deletemax()函数作用是每次返回最小值,并且将最后一个值移入到根节点再次进行最小堆,这样结束时数组中数据已不再是原来的。

若想用这样的来求降序也是可以的,只需要建立最大堆就行了,其余都一样


另一种方式来求解升序和降序


//之前创建的是最大堆 
void headsort()
{
  while(n>1)
  {
  swap(1,n);     //将第一个与最后一个进行交换,此时最后一个点为最大值 
  n--;     //下次建立最大堆不带上最后一个值 
  siftdown(1);  //进行最大堆 
  }
}


求解升序另一种方法完整:


#include <stdio.h>
int h[101]; //用来存放堆的数组
int n;  //存放堆的个数
void swap(int x,int y)
{
  int t;
  t = h[x];
  h[x] = h[y];
  h[y] = t;
} 
void siftdown(int i)
{
  int t,flag=0;  //flag用来表示无需再进行往下查找 
  //从i位置开始,判断是否有左孩子,并且没有找到最佳位置 
  while(i*2<=n&&flag==0)
  {
  if(h[i]<h[i*2]) //比较父节点与左节点的大小 
    t = i*2;
  else
    t = i;
  if(i*2+1<=n){   //判断是否存在右孩子 
    if(h[t]<h[i*2+1])  //比较上一次父节点与左节点的最小值与右孩子大小 
    t = i*2+1;
  }
  if(t!=i){  //判断得到最小值是否为父节点,是的话flag标志1,不是的话交换,继续往下找 
    swap(t,i);
    i=t;
  }
  else
    flag = 1;
  }
}
//开始创建堆 
void create()
{
  int i;
  for(i=n/2;i>=1;i--)
  siftdown(i);
}
//之前创建的是最大堆 
void headsort()
{
  while(n>1)
  {
  swap(1,n);     //将第一个与最后一个进行交换,此时最后一个点为最大值 
  n--;     //下次建立最大堆不带上最后一个值 
  siftdown(1);  //进行最大堆 
  }
}
int main()
{
  int i,num;
  scanf("%d",&num);
  for(i=1;i<=num;i++)
  scanf("%d",&h[i]);
  n = num;
  //建立最小堆
  create();
  headsort(); 
  //删除顶部元素,接着将最后一个元素放入第一个顶点中,输出删除的元素
  for(i=1;i<=num;i++)
  printf("%d ",h[i]); 
  return 0;
}



相关文章
|
存储 算法
【堆】数据结构堆的实现(万字详解)
【堆】数据结构堆的实现(万字详解)
855 0
|
4月前
|
存储 物联网 数据中心
拒绝玄学炼丹:大模型微调显存需求精确计算指南,全参数微调与LoRA对比全解析
本文揭秘大模型微调显存消耗的本质,系统拆解模型权重、梯度、优化器状态、激活值四大组成部分的计算逻辑,推导可复用的显存估算公式;对比全量微调、LoRA、QLoRA等方案的显存需求,提供实用工具与配置建议,助开发者告别“玄学估算”,精准规划GPU资源。
|
机器学习/深度学习 人工智能 监控
PPO落地避坑指南:从环境配置到训练监控的全流程实操
RLHF(基于人类反馈的强化学习)是大模型对齐的核心技术,而PPO(近端策略优化)是其实现的关键引擎。它以稳定、高效、易调优的优势,克服了TRPO等算法的工程瓶颈,广泛应用于GPT-4、Claude等模型的对齐训练。尽管面临显存压力与超参敏感等挑战,借助模型并行、量化、自动调参等方案,PPO已日趋实用化。
PPO落地避坑指南:从环境配置到训练监控的全流程实操
数据结构堆排序中堆的建立、调整、插入、删除等操作的详解(题目讲解 简单易懂)
数据结构堆排序中堆的建立、调整、插入、删除等操作的详解(题目讲解 简单易懂)
1416 0
|
编译器 C++ 开发者
C++一分钟之-C++20新特性:模块化编程
【6月更文挑战第27天】C++20引入模块化编程,缓解`#include`带来的编译时间长和头文件管理难题。模块由接口(`.cppm`)和实现(`.cpp`)组成,使用`import`导入。常见问题包括兼容性、设计不当、暴露私有细节和编译器支持。避免这些问题需分阶段迁移、合理设计、明确接口和关注编译器更新。示例展示了模块定义和使用,提升代码组织和维护性。随着编译器支持加强,模块化将成为C++标准的关键特性。
1393 3
|
存储 算法 搜索推荐
图解堆排序(一次弄懂堆结构以及堆排序)
图解堆排序(一次弄懂堆结构以及堆排序)
|
存储 索引
【数据结构】核心数据结构之二叉堆的原理及实现
【数据结构】核心数据结构之二叉堆的原理及实现
【数据结构】核心数据结构之二叉堆的原理及实现
|
Dubbo Java 应用服务中间件
Dubbo两小时快速上手教程(直接代码、Spring、SpringBoot)
最近项目中需要用到dubbo,虽然我知道dubbo是一个RPC框架,但是没有去详细了解这个框架。既然项目要用,那就先把Dubbo的应用给学会,等熟练使用之后,再去了解Dubbo内部的原理。如果想要项目代码,直接联系我即可。如果想要demo代码,直接联系我即可。
8611 1
|
Python
联合概率 边缘概率 条件概率 贝叶斯定理
联合概率 边缘概率 条件概率 贝叶斯定理
679 0