堆的基础知识以及堆排序

目录

前言

一、堆是什么?

1.大根堆

1.定义

2.小根堆

1.定义

二、使用步骤

1.引入库

2.读入数据

总结



前言

我们学习完树的知识之后就需要了解堆的知识,堆在树的衬托下,展现出来了强大的作用,它帮助我们解决很多的问题,在堆中,我们也会了解到和快排的时间复杂度相同的堆排知识。接下来就让我们了解一下堆的知识


一、堆是什么?

     堆的数据结构是完全二叉树或一堆数组,因为堆在逻辑上是一棵完全二叉树,在物理结构上是一个一维数组。堆将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。 堆是非线性数据结构,相当于一维数组,有两个直接后继。(这里是百度中的堆定义,我们利用数组来模拟二叉树,进行大小堆的知识介绍,并且完成堆排序)

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

这个是升序的代码实现,我们可以更换其中的比较符号,来完成他的降序的代码实现 。


总结

我们了解了一下堆的基础知识,还有大根堆,小根堆,最重要的是要掌握堆排序,这样可以帮助进行很多问题解决,在很多实际应用需要用到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值