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

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

导航


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;
}



相关文章
|
2月前
|
前端开发 算法 JavaScript
最小堆最大堆了解吗?一文了解堆在前端中的应用
该文章详细解释了堆数据结构(特别是最小堆)的概念与性质,并提供了使用JavaScript实现最小堆的具体代码示例,包括堆的插入、删除等操作方法。
最小堆最大堆了解吗?一文了解堆在前端中的应用
|
5月前
|
存储
数据结构学习记录——什么是堆(优先队列、堆的概念、最大堆最小堆、优先队列的完全二叉树表示、堆的特性、堆的抽象数据类型描述)
数据结构学习记录——什么是堆(优先队列、堆的概念、最大堆最小堆、优先队列的完全二叉树表示、堆的特性、堆的抽象数据类型描述)
111 2
|
5月前
|
存储 算法
面试必知必会|理解堆和堆排序
面试必知必会|理解堆和堆排序
|
存储 算法
优先级队列(堆)&&  堆排序
优先级队列(堆)&&  堆排序
48 0
|
6月前
|
算法 C语言
堆的应用:堆排序
堆的应用:堆排序
93 0
|
11月前
|
存储 C语言
堆与堆排序操作详解
堆与堆排序操作详解
|
存储
数据结构(9)树形结构——大顶堆、小顶堆
9.1.概述 概念: 根节点是自己所在子树中的最值的完全二叉树。 根节点是所在子树的最大值,称为大顶堆。 根节点是所在子树的最小值,称为小顶堆。 堆的任何子树的根节点到子树上的任意节点,路径上的节点都是有序的,大顶堆为降序,小顶堆为升序。 此处展示一个大顶堆:
367 0
【树与二叉树】堆的时间复杂度详解以及堆的应用—堆排序、TOP - K问题
【树与二叉树】堆的时间复杂度详解以及堆的应用—堆排序、TOP - K问题