目录
前言
我们学习完树的知识之后就需要了解堆的知识,堆在树的衬托下,展现出来了强大的作用,它帮助我们解决很多的问题,在堆中,我们也会了解到和快排的时间复杂度相同的堆排知识。接下来就让我们了解一下堆的知识
一、堆是什么?
堆的数据结构是完全二叉树或一堆数组,因为堆在逻辑上是一棵完全二叉树,在物理结构上是一个一维数组。堆将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。 堆是非线性数据结构,相当于一维数组,有两个直接后继。(这里是百度中的堆定义,我们利用数组来模拟二叉树,进行大小堆的知识介绍,并且完成堆排序)
1.大根堆
1.定义
顾名思义,就是在二叉树中,他的父亲节点数值都比左右孩子节点数值大。
从图中可以看出,我们定义一个数组,然后利用层次排序,把他排成二叉树的类型,在排列的过程中,我们需要符合二叉树的性质。
2.小根堆
1.定义
顾名思义,就是在二叉树中,他的父亲节点数值都比左右孩子节点数值小。
从图中可以看出,我们定义一个数组,然后利用层次排序,把他排成二叉树的类型,在排列的过程中,我们需要符合二叉树的性质。
二、堆排序
接下来我们直接了解堆排序,然后通过堆排序,我们学习如何对堆进行建立,排序,然后输出。我们了解他的原理,和本质。
1.堆的建立
我们需要先创建数组。arr[13]为下面的数据
接下来我们就可以利用层序遍历的方法对他进行二叉树的构建
接下来我们就是需要把这个二叉树转换成堆的类型,我们就以小根堆来举例子吧。
我们需要从最后一个数组非叶子的根节点,进行操作,判断他是否有子节点,判断两个子节点的大小,我们用它和它最小的子节点进行交换,如果它的子节点都比他大的话,就不进行交换,就是把1和7进行交换。
这就是我们第一次交换,就这样,我们需要把所有的进行交换
这个就是我们最后的一个排序结果
2.堆排序的实现
我们现在已经把堆进行了实现,从图中我们可以看出来,他的根节点是最小的,接下来我们就是利用一个数组或者其他的记录,让这个根节点输出,接着把最后的的最后一个,换到前面,这样的话就可以帮助我们进行输出,还有后面的排序,一下接着一个,这样下来就可以输出所有的,我们每次输出的都是最小的,可以帮助我们完成堆排序。
这些就是堆排序的重要思想,我们可以画图解决这些问题,帮助我们可以更好的理清这个思路。
三、堆排序的代码实现
#include<stdio.h>
//定义全局变量数组和数组个数
int h[101] = {0}, n;
void creat();//创建堆
void sitdown(int i);//向下调正函数
void swap(int x, int y);//交换函数
void heapsort();//堆排序
int main()
{
int num, i;
//输入我们需要的进行排序数的个数
scanf("%d", &num);
//输入需要排序的数据
for(i = 1; i <= num; i++){
scanf("%d", &h[i]);
}
//将个数赋值给我们之前的全局变量,方便我们后面的操作
n = num;
//创建我们的堆
creat();
heapsort();
printf("\n");
for(i = 1; i <= num; i++){
printf("%d\n",h[i]);
}
}
void creat()
{
int i;
//对我们的堆进行创建,对最后一个数据先放入堆中
for(i = n/2; i >= 1; i--){
sitdown(i);
}
}
void sitdown(int i)
{
int t, flag = 0;
//判断他的左子树是否存在,并且这个数是否已经到位置了,不需要再经行移动
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){
swap(t, i);
i = t;
//如果相等的话,说明这个节点不在需要交换,则让这个循环结束,接着下一个节点的排序
} else {
flag = 1;
}
}
return;
}
void swap(int x, int y)
{
//利用中间值进行数值的交换
int t;
t = h[x];
h[x] = h[y];
h[y] = t;
return;
}
void heapsort()
{
//对每一个数进行排序
while(n > 1){
//我们先把最后一个数和第一个数进行交换,方便后续的排序
swap(1, n);
//进行了一个数的排序,就要对整体需要排的数减一
n--;
//进行下滑排序
sitdown(1);
}
return;
}
这个是升序的代码实现,我们可以更换其中的比较符号,来完成他的降序的代码实现 。
总结
我们了解了一下堆的基础知识,还有大根堆,小根堆,最重要的是要掌握堆排序,这样可以帮助进行很多问题解决,在很多实际应用需要用到。