算法分析之——heap-sort堆排序

堆排序是一种原地排序排序算法,不使用额外的数组空间,运行时间为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.最后给出程序运行的截图:

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

时间: 2024-10-19 18:49:13

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

Heap Sort (堆排序)

Heap sort is common in written exams. First of all, what is heap? Heap is a kind of data struct that can be seen as a complete binary tree. The object to indicate heap is an array A that have two attributes: length[A] shows the number of elements in

经典排序算法 - 堆排序Heap sort

经典排序算法 - 堆排序Heap sort 堆排序有点小复杂,分成三块 第一块,什么是堆,什么是最大堆 第二块,怎么将堆调整为最大堆,这部分是重点 第三块,堆排序介绍 第一块,什么是堆,什么是最大堆 什么是堆 这里的堆(二叉堆),指得不是堆栈的那个堆,而是一种数据结构. 堆可以视为一棵完全的二叉树,完全二叉树的一个"优秀"的性质是,除了最底层之外,每一层都是满的,这使得堆可以利用数组来表示,每一个结点对应数组中的一个元素. 数组与堆之间的关系 二叉堆一般分为两种:最大堆和最小堆. 什么

[Unity][Heap sort]用Unity动态演示堆排序的过程

[Unity][Heap sort]用Unity动态演示堆排序的过程 How Heap Sort Works 最近做了一个用Unity3D动态演示堆排序过程的程序. I've made this heap sort demo to show how heap sort works recently. 效果图(Demo) 一图抵千言. A picture paints a thousand words. 您可以在此查看完整的动态GIF效果图.博客园里放不下这么大的GIF图. 链接:http://p

算法 Heap sort

// -------------------------------------------------------------------------------------------------------------------- // <copyright file="Program.cs" company="Chimomo's Company"> // // Respect the work. // // </copyright>

Bubble, Insertion, Selection, Quick and Heap Sort

Bubble, Insertion, Selection, Quick and Heap Sort Bubble Sort 冒泡排序是基本的排序算法之一,时间复杂度为,空间复杂度也为.该算法不常被使用,因为和插入排序相比较,插入排序的时间复杂度为,而空间复杂度为.属于稳定排序. 有三种方法可以改进Bubble Sort,①当一轮比较却没有发生交换时,认为数据已经有序,停止排序.②当进行i轮排序后,数据序列后的N-i个元素已经有序,可以不考虑.③假设Data[i]与Data[i+1]是发生的最后一

算法分析-堆排序 Heap Sort

堆排序的是集合了插入排序的单数组操作,又有归并排序的时间复杂度,完美的结合了2者的优点. 堆的定义 n个元素的序列{k1,k2,…,kn}当且仅当满足下列关系之一时,称之为堆. 情形1:ki <= k2i 且ki <= k2i+1 (最小化堆或小顶堆) 情形2:ki >= k2i 且ki >= k2i+1 (最大化堆或大顶堆) 其中i=1,2,…,n/2向下取整; 若将和此序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终

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

堆排序是利用堆进行排序的高效算法,其能实现O(NlogN)的排序时间复杂度,具体算法分析可以点击堆排序算法时间复杂度分析. 算法实现: 调整堆: void sort::sink(int* a, const int root, const int end) { int i=root; while(2*i +1 <= end) { int k = 2*i+1; if(k+1<=end && a[k]<a[k+1]) k++; if(a[k] < a[i]) break;

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

堆排序(Heap Sort)具体步骤为 将无序序列建成大顶堆(小顶堆):从最后一个非叶子节点开始通过堆调整HeapAdjust()变成小顶堆或大顶堆 将顶部元素与堆尾数组交换,此是末尾元素就是最大值,顶部元素不满足堆,故要将顶部元素在剩余的i-1个元素中调整为堆 反复第2步.直至所有顶点被输出,序列变成从小到大的有序序列 C语言实现(编译器Dev-c++5.4.0,源代码后缀.cpp) 原创文章,转载请注明来自钢铁侠Mac博客http://www.cnblogs.com/gangtiexia 1

堆排序 Heap Sort

堆排序是一种选择排序,其时间复杂度为O(nlogn). 堆的定义 n个元素的序列{k1,k2,…,kn}当且仅当满足下列关系之一时,称之为堆. 情形1:ki <= k2i 且ki <= k2i+1 (最小化堆或小顶堆) 情形2:ki >= k2i 且ki >= k2i+1 (最大化堆或大顶堆) 其中i=1,2,…,n/2向下取整; 若将和此序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端结点的值均不大于(或不小于)其左

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

题目就是给两个序列,第一个是排序前的,第二个是排序中的,判断它是采用插入排序还是堆排序,并且输出下一次操作后的序列. 插入排序的特点就是,前面是从小到大排列的,后面就与原序列相同. 堆排序的特点就是,后面是从小到大排列的最大的几个数p~n-1,前面第一位则是p-1. 所以只要先按照插入排序的特点来判断是否为插入排序,接下来再进行操作就可以了,这里要手动写下最大堆的更新操作. 代码: #include <iostream> #include <cstdio> #include <