独特好解之排序方法--简单基础堆排序

文章已获作者授权转载,版权归原作者所有,如有侵权,与本账号无关,可联系删除。 原文作者:creative_mind

引入

当前我们已经学过一些排序方法,如冒泡排序,选择排序,还有链表(单双),qsort()等一系列进行排序的方法。那么,你真的了解排序的各种方法吗?今天,我将介绍一种新的巧解–堆排序,从时间复杂度和空间复杂度上看,堆排序并不比以上我们所说的那些方法复杂,甚至有时它更为常见!

也许你会感觉很陌生,不知道如何下手?其实我想说的是:堆排序也并非很难****。****

1 解读理解加复习

首先,堆排序的物理结构是数组,逻辑结构为二叉树。

对于物理结构,相信数组大家都不陌生,我们再学习栈的时候,就是通过数组来实现的,我们创建的结构体,数组指针,以及入栈(扩容),出栈(空间是否为1的分情况讨论)等操作其实在堆排序中也能遇到!

**那对于逻辑结构,**我们将要讲一下关于树以及二叉树的概念!

1.1 复习

1.是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合,树是递归定义的。

2.树的相关概念,如下:

节点的度:一个节点含有的子树的个数称为该节点的度;
叶节点或终端节点:度为0的节点称为叶节点;
非终端节点或分支节点:度不为0的节点;
双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点

孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;

兄弟节点:具有相同父节点的节点互称为兄弟节点;
树的度:一棵树中,最大的节点的度称为树的度;
节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
树的高度或深度:树中节点的最大层次;
堂兄弟节点:双亲在同一层的节点互为堂兄弟;
节点的祖先:从根到该节点所经分支上的所有节点;
子孙:以某节点为根的子树中任一节点都称为该节点的子孙。
森林:由m(m>0)棵互不相交的树的集合称为森林;

1.2 二叉树的概念

二叉树(binary tree)是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树。

1.3 二叉树分为满二叉树,完全二叉树

满二叉树:如果一棵二叉树只有度为0的节点和度为2的节点,并且度为0的节点在同一层上,则这棵二叉树为满二叉树。

完全二叉树:深度为k,有n个节点的二叉树当且仅当其每一个节点都与深度为k的满二叉树中编号从1到n的节点一一对应时,称为完全二叉树

1.4 二叉树的性质

  1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1) 个结点.
  2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是 2^(k)-1.
  3. 对任何一棵二叉树, 如果度为0其叶结点个数为 , 度为2的分支结点个数为 ,则有 n0=n2+1.
  4. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:log2(n+1)
  5. 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
  6. 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
  7. 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子

2 新解

堆(heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:

  • 堆中某个结点的值总是不大于或不小于其父结点的值
  • 堆总是一棵完全二叉树。

将根结点最大的堆叫做最大堆最大堆或大根堆,根结点最小的堆叫做最小堆或小根堆。画图如下:

img

我们以小根堆为例子!

img

我们分析一下:首先我们定义parent和chlid节点!

我们不难得知:10为20和30的父亲节点,20为49与60的父亲节点 ,80为30的leftchlid节点!

总结一下:我们不难得知(以父亲与孩子的数组下标)推出以下关系:

leftchlid=parent*2+1;

rightchlid=parent*2+2;

parent=(chlid-1)/2;注意:“/”得出的结果为int 型!

那我们该如何插入一个数据呢?我们画图解决!(以我们push(5)为例)

以下是堆排序演变过程!

img

以下是我挑选的一道题,有助于大家理解!(大家把答案打在评价区)

最小堆[0,3,2,5,7,4,6,8],在删除堆顶元素0之后,其结果是()
A[3,2,5,7,4,6,8]
B[2,3,5,7,4,6,8]
C[2,3,4,5,7,8,6]
D[2,3,4,5,6,7,8]

3 代码实现

我们主要实现一下一些基础接口!

`**typedef int HPDataType;
typedef struct Heap
{
   HPDataType\* _a;//数组指针
   int _size;
   int _capacity;
}Heap;**`
**// 堆的初始化
void Heapinit(Heap\* hp);
// 堆的销毁
void HeapDestory(Heap\* hp);
// 堆的插入
void HeapPush(Heap\* hp, HPDataType x);
// 堆的删除
void HeapPop(Heap\* hp);
// 取堆顶的数据
HPDataType HeapTop(Heap\* hp);
// 堆的数据个数
int HeapSize(Heap\* hp);
// 堆的判空
int HeapEmpty(Heap\* hp);**

铁汁们,不要着急,我们一步一步来!

首先,我们从最简单的开始,不难的!

**// 堆的初始化
void Heapinit(Heap\* hp)
{
   assert(hp);
   hp->_a = NULL;
   hp->_capacity = hp->_size = 0;
}
// 堆的销毁
void HeapDestory(Heap\* hp)
{
   assert(hp);
   free(hp->_a);
   hp->_a = NULL;
   hp->_capacity = hp->_size = 0;
}**

考虑到我们频繁进行交换操作,所以我们先定义一个函数!

void Swap(HPDataType* px, HPDataType* py)//注意要传实参!
{
   HPDataType tmp = *px;
   *px = *py;
   *py = tmp;
}

好 ,接下来我们来写push;*重点为定义为向上调整法*

img

我们接着往下:void HeapPop(Heap* hp);重点是向下调整!

img

*这个要注意的是:(看注释,铁子们!)*

然后向下继续写!

**// 取堆顶的数据
HPDataType HeapTop(Heap\* hp)
{
   assert(hp);
   assert(hp->_size > 0);
   return hp->_a[0];
}
// 堆的数据个数
int HeapSize(Heap\* hp)
{
   assert(hp);
   assert(hp->_size > 0);
   return hp->_size;
}
// 堆的判空
bool HeapEmpty(Heap\* hp)
{
   assert(hp);
   return hp->_size == 0;
}**

我们要调试一下!

img

拿下,拿下,拿下,你看铁子们,不难的!

关注我,懂得更多!

原文链接:https://blog.csdn.net/creative_mind/article/details/136534278

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值