堆排序是一种原地排序算法,不使用额外的数组空间,运行时间为O(nlgn)。本篇文章我们来介绍一下堆排序的实现过程。

要了解堆排序。我们首先来了解一个概念,全然二叉树。

堆是一种全然二叉树或者近似全然二叉树。

什么是全然二叉树呢?百度百科上给出定义:全然二叉树:除最后一层外,每一层上的节点数均达到最大值;在最后一层上仅仅缺少右边的若干结点。以下用两个小图来说明全然二叉树与非全然二叉树。

(图片来自百度,大家能够忽略水印…..)



二叉堆满足二个特性:

1.父结点的键值总是大于或等于(小于或等于)不论什么一个子节点的键值。

2.每一个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。

当父结点的键值总是大于或等于不论什么一个子节点的键值时为最大堆。

当父结点的键值总是小于或等于不论什么一个子节点的键值时为最小堆。

堆排序也是基于分治思想的。主要有以下三步:

  1. 初始化,从第一个非叶结点開始遍历,使以其为根的树为大根堆;
  2. 交换堆顶元素与堆尾元素。筛选出最大的值。调整新的堆为大根堆。
  3. 反复2,每次筛选出堆中的最大元素,堆排序完毕。

    本次。我们举例的数组例如以下:数组长度length=10。



    相应的堆结构:

从第一个非叶结点開始。建初堆

void BUILD_MAX_HEAP(int A[],int length)
{
int i;
for(i=((length/2)-1);i>=0;i--)//length/2-1,为第一个非叶结点
MAX_HEAPIFY(A,i); }

保持堆的性质

void MAX_HEAPIFY(int A[],int i)
{
int l,r,largest,middle;
l=LEFT(i);
r=RIGHT(i);
if(l<heap_size && A[l]>A[i])
largest = l;
else
largest= i;
if(r<heap_size && A[r]>A[largest])
largest = r;
if(largest!=i)
{
middle=A[largest];
A[largest]=A[i];
A[i]=middle;
MAX_HEAPIFY(A,largest); }
}

堆排序的详细实现

void heap_sort(int A[],int length)
{
BUILD_MAX_HEAP(A,length); int i,middle;
for(i=length-1;i>0;i--)
{
middle=A[0];
A[0]=A[i];
A[i]=middle;
heap_size--;
MAX_HEAPIFY(A,0); }
}

以下为程序运行的简单的过程。分析不够全面,可是足以说明问题。

1.分析步骤4中的for循环,BUILD_MAX_HEAP(A,length);即建初堆的过程。i从length/2-1循环到0,即从4循环到0。(4为第一个非叶结点)

(1)i=4。MAX_HEAPIFY(A,i)。MAX_HEAPIFY(A,4);

<1>计算左叶子节点的编号l=LEFT(i)=(2*i+1)=9; 计算右叶子节点的编号r=RIGHT(i)=(2*i+2)=10;

注:此处计算左右叶子节点的编号时,要注意数组是从0还是从1開始的。若从0開始。左叶子节点为(2*i+1),右叶子节点为(2*i+2)。若从1開始,左叶子为2*i;右叶子为2*i+1

<2>推断左右叶子节点与根节点的大小,将当中节点编号的较大值赋值给largest;

heap_size为堆的大小,開始heap_size=length=9

if(l<heap_size && A[l]>A[i])
largest = l;
else
largest= i;
if(r<heap_size && A[r]>A[largest])
largest = r;

当i=4时,largest=4

<3>推断largest是否等于根节点,若不为根节点。说明当中左叶节点或者右叶节点比根节点的值大,则此时交换根节点与largest节点的值。

if(largest!=i)
{
middle=A[largest];
A[largest]=A[i];
A[i]=middle;
MAX_HEAPIFY(A,largest); }

由于此处largest=i,因此不运行这一步,运行下一次for循环

(2)i=3;MAX_HEAPIFY(A,i);MAX_HEAPIFY(A,3);

<1>计算左叶子节点的编号l=LEFT(i)=(2*i+1)=7; 计算右叶子节点的编号r=RIGHT(i)=(2*i+2)=8;

<2>推断左右叶子节点与根节点的大小。将当中节点编号的较大值赋值给largest;

largest=7

<3>推断largest是否等于根节点,若不为根节点。说明当中左叶节点或者右叶节点比根节点的值大,则此时交换根节点与largest节点的值。

<4>运行MAX_HEAPIFY(A,largest);MAX_HEAPIFY(A,7);将以largest为根的树调整为大根堆

(3)i=2;步骤与2中的<1>~<4>同样。largest=6,发生交换。

此处不再分析。

(4)i=1;时分析过程參考步骤与2中的<1>~<4>。

运行后的结果

(5)i=0;

2.步骤6中的for循环分析。即筛选出最大的值。缩小堆的规模,保持堆的性质的过程。

length=10,i从length-1到1。即从9循环到1

for(i=length-1;i>0;i--)
{
middle=A[0];
A[0]=A[i];
A[i]=middle;
heap_size--;
MAX_HEAPIFY(A,0); }

(1)i=9;交换A[i]与A[0]。此时i是堆的最末的那个元素,A[0]是堆顶元素,即最大的元素,将最大元素交换到堆尾。而且堆的规模缩小一个,即此时待又一次排序的堆是红框框起来的部分,此时运行MAX_HEAPIFY(A,0);上面已经分析,此处不再赘述。

(2)i=8;交换A[i]与A[0];heap_size–;MAX_HEAPIFY(A,0);

(3)以下的循环不再举例,我们能够看出。每次都筛选出当前堆中最大的元素。

3.最后给出程序运行的截图:

程序源码下载地址:堆排序实现代码

算法分析之——heap-sort堆排序的更多相关文章

  1. [Unity][Heap sort]用Unity动态演示堆排序的过程(How Heap Sort Works)

    [Unity][Heap sort]用Unity动态演示堆排序的过程 How Heap Sort Works 最近做了一个用Unity3D动态演示堆排序过程的程序. I've made this ap ...

  2. 算法 Heap sort

    // ------------------------------------------------------------------------------------------------- ...

  3. 堆排序 Heap Sort

    堆排序虽然叫heap sort,但是和内存上的那个heap并没有实际关系.算法上,堆排序一般使用数组的形式来实现,即binary heap. 我们可以将堆排序所使用的堆int[] heap视为一个完全 ...

  4. 数据结构 - 堆排序(heap sort) 具体解释 及 代码(C++)

    堆排序(heap sort) 具体解释 及 代码(C++) 本文地址: http://blog.csdn.net/caroline_wendy 堆排序包括两个步骤: 第一步: 是建立大顶堆(从大到小排 ...

  5. 堆排序(Heap Sort)的C语言实现

    堆排序(Heap Sort)具体步骤为 将无序序列建成大顶堆(小顶堆):从最后一个非叶子节点开始通过堆调整HeapAdjust()变成小顶堆或大顶堆 将顶部元素与堆尾数组交换,此是末尾元素就是最大值, ...

  6. PAT A1098 Insertion or Heap Sort (25 分)——堆排序和插入排序,未完待续。。

    According to Wikipedia: Insertion sort iterates, consuming one input element each repetition, and gr ...

  7. PAT甲题题解1098. Insertion or Heap Sort (25)-(插入排序和堆排序)

    题目就是给两个序列,第一个是排序前的,第二个是排序中的,判断它是采用插入排序还是堆排序,并且输出下一次操作后的序列. 插入排序的特点就是,前面是从小到大排列的,后面就与原序列相同. 堆排序的特点就是, ...

  8. 算法----堆排序(heap sort)

    堆排序是利用堆进行排序的高效算法,其能实现O(NlogN)的排序时间复杂度,详细算法分析能够点击堆排序算法时间复杂度分析. 算法实现: 调整堆: void sort::sink(int* a, con ...

  9. PAT甲级——1098 Insertion or Heap Sort (插入排序、堆排序)

    本文同步发布在CSDN:https://blog.csdn.net/weixin_44385565/article/details/90941941 1098 Insertion or Heap So ...

  10. Python入门篇-数据结构堆排序Heap Sort

    Python入门篇-数据结构堆排序Heap Sort 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.堆Heap 堆是一个完全二叉树 每个非叶子结点都要大于或者等于其左右孩子结点 ...

随机推荐

  1. python学习之assert语句

    assert语句用于代码检测并报警. 语法 assert code... 例子 # -*- coding: utf-8 -*- # assert语句说明 a,b= 1,23 a == 2 assert ...

  2. CCNA2.0笔记_TCP/IP概述

    主机到主机层(传输层) TCP与UDP UDP的特点 运行于 OSI 模型和 TCP/IP 模型的传输层 为应用程序提供网络层接入而无需为可靠性机制付出多余开销 属无连接协议 提供有限的错误检查 提供 ...

  3. poj1182食物链--并查集

    动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种.有人用两种说 ...

  4. python 差分包制作-如何来制作差分包?

    继百度网盘爬虫,百度图片爬虫后这是本人第三篇有关python的文章了,由于本人之前做过嵌入式的一些东西,其中会涉及到差分包的制作,所以这篇文章想谈谈如何利用python来制作差分包,如果你对嵌入式的东 ...

  5. TCP超时重传、滑动窗口、拥塞控制、快重传和快恢复

    TCP超时重传 原理是在发送某一个数据以后就开启一个计时器,在一定时间内如果没有得到发送的数据报的ACK报文,那么就重新发送数据,直到发送成功为止. 影响超时重传机制协议效率的一个关键参数是重传超时时 ...

  6. node.js和前端js有什么区别

    进行前端开发工作需要掌握技能有html. css.js以及各种前端框架,把这些技术玩6就可以成为一名合格的前端开发工作者 而进行nodejs开发,需要掌握js.web服务器原理.关系数据使用, 如果玩 ...

  7. WCF系列 基础概念

    WCF全称Windows Communication Foundation,是微软构建面向服务的分布式编程框架.而它其实是统一了COM和.Net Remoting等分布式技术提供一个完整,通用,可靠的 ...

  8. 【转】MFC OnIdle的详细说明

    转载出处:http://blog.csdn.net/tsing_best/article/details/25055707 CWinApp::OnIdlevirtual BOOL OnIdle( LO ...

  9. poj 2987(最大权闭合图+割边最少)

    题目链接:http://poj.org/problem?id=2987 思路:标准的最大权闭合图,构图:从源点s向每个正收益点连边,容量为收益:从每个负收益点向汇点t连边,容量为收益的相反数:对于i是 ...

  10. 主流数据文件类型(.dat/.txt/.json/.csv)导入到python

    手写很累,复制的同学请点赞犒劳下在下哦 ^_^ 一.对于.CSV类型的数据 它们的数据导入都很简单 且看下面一顿操作: 我平时一般是读取整个文件,直接这样就可以了: import pandas as ...