堆排序

来源:互联网 发布:西游之路坐骑进阶数据 编辑:程序博客网 时间:2024/06/06 13:01

1.堆

堆排序集合了归并排序的优点:时间复杂度位O(nlgn)

                       插入排序的优点:具有空间原址性(任何时候只需要常数个额外的元素空间存储临时数据)


              堆是一个数组,可以被看成是一个近似的完全二叉树。堆上的每个节点对应数组中的一个元素。除了最底层外,该树是完全充满的。这样给定一个结点的下标 i,我们很容易计算得到它的父结点、左孩子和右孩子的下标。

          PARENT(i)

               return ⌊i/2⌋

LEFT(i)

return 2i

RIGHT(i)

return 2i+1

最大堆性质:除了根节点以外的结点 i 都要满足:A [PARENT(i)] >= A[ i ],堆中最大元素存放在根结点 中

最小堆性质:除了根节点以外的结点 i 都要满足:A [PARENT(i)] <= A[ i ],堆中最小元素存放在根结点中

排序一般用最大堆实现,最小堆常用来构造优先队列。

2.维护堆的性质

堆中结点的高度:就是该结点到叶结点最长简单路径上边的数目。包含n个元素的堆高度为 lgn。

MAX-HEAPIFY过程:调整堆为最大堆,时间复杂度为 O(nlgn)。

BUILD-MAX-HEAP过程:从无序的输入数据数组中构造一个最大堆,具有线性时间复杂度。

HEAPSORT过程 :对一个数组进行原址排序,时间复杂度为 O(nlgn)

MAX-HEAP-INSERT、HEAP-EXTRACT-MAX、HEAP_INCREASE-KEY和HEAP-MAXIMUM过程:利用堆实现一个优先队列,时间复杂度为O(lgn)。


 MAX-HEAPIFY(A,i)//MAX-HEAPIFY通过让A[i]的值在最大堆中“逐级下降”,从而使下标i为根节点的子树重新遵循最大堆的性质。l=LEFT(i)r=RIGHT(i)if l<=A.heap-size and A[l]>A[i]    largest=lelse largest=iif r<=A.heap-size and A[r]>A[largest]    largest=rif largest !=i    exchange A[i] with A[largest]    MAX-HEAPIFY(A,largest)

  在程序的每一步中,从A[i]、A[LEFT(i)]、A[RIGHT(i)]中选出最大的,并将其下标存储在largest中。如果A[i]是最大的,那么以i为根节点的子树已经是最大堆,程序结束,否则,最大元素是i的某一个孩子节点,交换A[i]和A[largest]的值,使其孩子都满足最大堆的性质。交换后,下标为largest的结点的值是原来的A[i],于是以该节点为根的子树又有可能会违反最大堆的性质。因此需对该子树递归调用MAX-HEAPIFY。过程如下图:







3.建堆

我们可以用自底向上的方法利用MAX-HEAPIFY把一个大小为n的数组转化为最大堆。每个叶结点都可以看成是只包含一个元素的堆。过程BUILD-MAX-HEAP堆树中其他节点都调用一次MAX-HEAPIFY

BUILD-MAX-HEAP(A )A.heap-size = A.lengthfor i = ⌊A.length/2⌋ downto 1  //从第一个非叶结点开始调整,直到根节点    MAX-HEAPIFY(A,i)


4.堆排序算法

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

HEAPSORT(A)    //时间复杂度为O(nlgn)BUILD-MAX-HEAP(A)for i = A.length downto 2        //n-1次调用<font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">MAX-HEAPIFY</span></span></span></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font>    exchange A[1] with A[i]    A.heap-size = A.heap-size - 1    MAX-HEAPIFY(A,1)                //时间复杂度为O(lgn)


以下是堆排序的完整实现:

#include <stdio.h>#include <stdlib.h>#include <malloc.h>#include <time.h>void PrintArr(int *pnArr, int nLen){    for (int i = 0; i < nLen; i++)    {        printf("%d ", pnArr[i]);    }    printf("\n");}//返回i父节点下标int Parent(int i)                 //下标从0开始{    return (i - 1) / 2;}//返回i左孩子下标int LeftChild(int i){    return i * 2 + 1;}//返回i右孩子下标int RightChild(int i){    return i * 2 + 2;}void Swap(int *a, int *b){    int nTmp = *a;    *a = *b;    *b = nTmp;}void MaxHeapify(int *pnArr, int nLen, int i){    int LChild = LeftChild(i);    int RChild = RightChild(i);    int nMaxPos;    if (LChild < nLen && pnArr[LChild] > pnArr[i])    {        nMaxPos = LChild;    }    else    {        nMaxPos = i;    }    if (RChild < nLen && pnArr[RChild] > pnArr[nMaxPos])    {        nMaxPos = RChild;    }        if (nMaxPos != i)    {        Swap(&pnArr[nMaxPos], &pnArr[i]);        MaxHeapify(pnArr, nLen,nMaxPos);    }    }void BuildMaxHeap(int *pnArr, int nLen){    for (int i = Parent(nLen -1); i >= 0; i--)    {        MaxHeapify(pnArr, nLen, i);    }}void HeapSort(int *pnArr, int nLen){    BuildMaxHeap(pnArr, nLen);    for (int i = nLen - 1; i > 0; i--)    {        Swap(&pnArr[i], &pnArr[0]);        nLen--;        MaxHeapify(pnArr, nLen, 0);    }}int main(){    int nArr[10] = {4,1,3,2,16,9,10,14,8,7};  //下标从0开始        PrintArr(nArr, 10);    HeapSort(nArr, 10);    PrintArr(nArr, 10);system("pause");    return 0;}















1 0