第六章——堆排序

一 堆

 堆给人的感觉是一个二叉树,但是其本质是一种数组对象,因为对堆进行操作的时候将堆视为一颗完全二叉树,树种每个节点与数组中的存放该节点值的那个元素对应。所以堆又称为二叉堆,堆与完全二叉树的对应关系如下图所示:

二叉堆可以分为两种形式:最大堆和最小堆。在这两种堆中,结点的值都要满足堆的性质。

在最大堆中,最大堆的性质是指除了根以外的所有结点i都要满足:

A[PARENT(i)]>=A[i]

也就是说,某个结点的值至多与其父结点一样大。因为,堆中的最大元素存放在根结点中;并且,在任一子树中,该子树所包含的的所有结点的值都不大于该子树根结点的值。最小堆的组织方法正好相反:最小堆性质是指除了根以外的所有结点i都有

A[PARENT(i)]<=A[i]

最小堆中的最小元素存放在根结点中。

在堆排序算法中,我们使用的是最大堆。最小堆通常用于构造优先队列、

如果把堆看成一棵树,我们定义一个堆中的结点的高度就为该结点到叶结点最长简单路径上边的数目;进而我们可以把堆的高度定义为根结点的高度。既然一个包含n个元素的堆可以看成是一颗完全二叉树,那么该堆的高度是O(lgn)。我们会发现,堆结构上的一些基本操作的运行时间至多与树的高度成正比,即时间复杂度为O(lgn)。

  • MAX-HEAPIFY 过程:其时间复杂度为O(lgn),它是维护最大堆性质的关键。
  • BUILD-MAX-HEAP过程:具有线性时间复杂度,功能是从无序的输入数据数组中构造一个最大堆。
  • HEAPSORT过程:其时间复杂度O(lgn),功能是对一个数组进行原址排序。
  • MAX-HEAP-INSERT、HEAP-EXTERACT-MAX、HEAP-INCREASE-KEY和HEAP-MAXIMUM过程:时间复杂度为O(lgn),功能是利用堆实现一个优先队列。

二 维护堆的性质

MAX-HEAPIFY是用于维护最大堆性质的重要过程。它的输入是一个数组arr和一个下标i和数组长度。通过让arr[i]的值在最大堆中”逐级下降“,从而使得以下标i为根结点的子树重新遵循最大堆的性质。

//递归的调整堆
void MaxHeapity(int arr[],int i,int n)
{
    int lchild,rchild;
    int largest;
    lchild=LEFT(i);
    rchild=lchild+1;
    if(lchild<=n-1&&arr[i]<arr[lchild])
        largest=lchild;
    else
        largest=i;
    if(rchild<=n-1&&arr[rchild]>arr[largest])
    {
        largest=rchild;
    }
    //largest==i既可以判断要调整的点是否还存在左子树和右子树也可以判断要调整的节点的值是否大于其子树
    if(largest!=i)
    {
        swap(&arr[largest],&arr[i]);
        MaxHeapity(arr,largest,n);
    }
}

三 建堆


我们可以用自底向上的方法利用过程MAX-HEAPIFY把一个大小为n的数组arr[0..n]转换为最大堆。我们指定,子数组arr[n/2]...a[n-1]中的元素都是叶子节点。每个叶节点都可以看成只含有一个元素的堆。过程BUILD-MAX-HEAP对树中的其他结点都调用一次MAX-HEAPIFY。

//建堆
void BuildMaxHeap(int arr[],int n)
{
    int i;
    for((i=(n-1)/2);i>=0;i--)
    {
        MaxHeapity(arr,i,n);
    }
}

四 堆排序算法

初始时候,堆排序算法利用BUILD-MAX-HEAP将输入数组arr[0...n-1]建成最大堆。因为数组中的最大元素总在根结点arr[0]中,通过把它与arr[n-1]进行交换,我们可以让该元素放到正确的位置。这时候,如果我们从堆中去掉结点n-1,剩余的结点中,原来根的孩子结点仍然是最大堆,而新的根结点可能会违背最大堆的性质。为了维护最大堆的性质,我们要做的是调用MAX-HEAPIFY(arr,0,n-1),从而在arr[0..n-2]上构造一个新的最大堆。堆排序算法会不断重复这一过程。直到堆的大小从n-1降到1.

//堆排序
void HeapSort(int arr[],int n)
{
    int i;
    BuildMaxHeap(arr,n);
    for(i=n-1;i>0;i--)
    {
        swap(&arr[0],&arr[i]);
        MaxHeapity(arr,0,i);
    }
}

  

时间: 2024-10-31 18:04:56

第六章——堆排序的相关文章

第六章 堆排序 6.5 优先队列

package chap06_Heap_Sort; import static org.junit.Assert.*; import java.util.ArrayList; import java.util.Arrays; import org.junit.Test; /** * 优先队列,二叉堆数组实现,数组的size最好大一些,至少比里面的堆大一些,来实现堆的扩展(插入元素) * * @author xiaojintao * */ public class PriorityQueue {

第六章 堆排序

以后尽量能用迭代就别用递归啊,递归只是让自己轻松了,但是却增加了电脑的负担. package chap06_Heap_Sort; import static org.junit.Assert.*; import java.util.Arrays; import org.junit.Test; public class SortAlorithms { /** * 返回当前下标下父节点的下标 * * @param i * @return */ protected static int parent(

算法导论第六章 堆排序

堆的时间复杂度是建O(n),时间复杂度为堆排序O(NLogN),细节如以下的算法看到: #include <iostream> using namespace std; void swap(int &i,int &j) { int temp=i; i=j; j=temp; } void shiftDown(int *A, int start,int len) { int temp=A[start]; int i=start; int j=2*i+1; while (j<l

算法导论第六章堆排序(一)

现在来看, 堆的含义大概有两种,一种是数据结构,一种是在一些语言中所定义的“垃圾回收机制”,如Java,在书本上的开篇强调了这两者,并强调若非特殊说明,皆把堆看做是一种数据结构. (二叉)堆的定义: 1)它是一个数组,可以被看成是一棵近似的完全二叉树,树上的每一个节点看做是数组中的每一个元素. 2)堆分为最大堆和最小堆,最大堆中每一棵子树的父节点的值大于孩子节点,最小堆则相反. 3)表示堆的数组A包括两个属性:A.length和A.heap_size.前者是数组元素的个数,后者是堆元素的个数,h

算法导论 第六章 堆排序

http://blog.csdn.net/mishifangxiangdefeng/article/details/7662515 http://www.cnblogs.com/Jiajun/archive/2013/05/31/3110256.html 这里练习6.3-3看http://blog.csdn.net/sailing_lqh/article/details/7381893的比较好理解

算法导论笔记——第六七章 堆排序和快速排序

第六章 堆排序 最小堆和最大堆:近似的完全二叉树 A[parent(i)]<=A[i]或者A[parent(i)]>=A[i] 建堆复杂度O(n) 排序O(nlgn) 实际应用中,快速排序一般优于堆排序.可用于优先队列等. 在一个包含n个元素的堆中,所有优先队列的操作均可在O(lgn)时间内完成. 第七章 快速排序 与归并排序一样用分治思想 主元pivot可随机生成

算法导论 第6章 堆排序

堆数据结构实际上是一种数组对象,是以数组的形式存储的,但是它可以被视为一颗完全二叉树,因此又叫二叉堆.堆分为以下两种类型: 大顶堆:父结点的值不小于其子结点的值,堆顶元素最大 小顶堆:父结点的值不大于其子结点的值,堆顶元素最小 堆排序的时间复杂度跟合并排序一样,都是O(nlgn),但是合并排序不是原地排序(原地排序:在排序过程中,只有常数个元素是保存在数组以外的空间),合并排序的所有元素都被拷贝到另外的数组空间中去,而堆排序是一个原地排序算法. 1.在堆排序中,我们通常使用大顶堆来实现,由于堆在

算法导论 第6章 堆排序(简单选择排序、堆排序)

堆数据结构实际上是一种数组对象,是以数组的形式存储的,可是它能够被视为一颗全然二叉树,因此又叫二叉堆.堆分为下面两种类型: 大顶堆:父结点的值不小于其子结点的值,堆顶元素最大 小顶堆:父结点的值不大于其子结点的值,堆顶元素最小 堆排序的时间复杂度跟合并排序一样,都是O(nlgn),可是合并排序不是原地排序(原地排序:在排序过程中,仅仅有常数个元素是保存在数组以外的空间),合并排序的全部元素都被复制到另外的数组空间中去,而堆排序是一个原地排序算法. 1.在堆排序中,我们通常使用大顶堆来实现,因为堆

第六章 常见排序算法

上章回顾 二叉树的定义 树深度的定义 什么样的二叉树是满二叉树 中序遍历的规则 [email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git 第六章 第六章 常见排序算法 常见排序算法 [email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorith