首页 > 代码库 > 算法导论第六章 堆排序

算法导论第六章 堆排序

主要内容:

堆、最大堆、最小堆的基本概念

堆的操作:调整、创建、排序

采用堆实现优先级队列

基本概念

heap)亦被称为:优先队列priority queue

逻辑定义:

n个元素序列{k1,k2...ki...kn},当且仅当满足下列关系时称之为堆:

(ki <= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4...n/2)

堆的实现通过构造二叉堆(binary heap),实为二叉树的一种。

性质

1、任意节点小于或大于它的所有后裔,最小元或最大元在堆的根上(堆序性)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。

2、堆总是一棵完全树。堆只需要满足父节点大于两个子节点,而子节点之间没有要求。作为一颗完全树,一层中的节点是从左到右填满的。如果一个节点没有左儿子,那么它一定没有右儿子。并且在第h层中如果存在节点,那么第h-1层必须是填满的。

堆的操作

调整堆

void adjust_max_heap_recursive(int *datas, int length, int i)//递归调用,最大堆调整

{

    int left,right,largest;

    int temp;

    left = LEFT(i);//left child

    right = RIGHT(i);//right child

    //find the largest value among left and right and i

    if(left<=length && datas[left]>datas[i]) largest = left;

    else largest = i;

    if(right <= length && datas[right] >datas[largest]) largest = right;

    //exchange i and largest

    if(largest != i)

    {

        temp = datas[i];

        datas[i] = datas[largest];

        datas[largest] = temp;

        //recursive call the function, adjust from largest

        adjust_max_heap(datas, length, largest);

    }

}

void adjust_max_heap(int *datas,int length,int i)//非递归调用,最大堆调整
{
    int left,right,largest;
    int temp;
    while(1)
    {
        left = LEFT(i);   //left child
        right = RIGHT(i); //right child
        //find the largest value among left and rihgt and i.
        if(left <= length && datas[left] > datas[i])
            largest = left;
        else
            largest = i;
        if(right <= length && datas[right] > datas[largest])
            largest = right;
        //exchange i and largest
        if(largest != i)
        {
            temp = datas[i];
            datas[i] = datas[largest];
            datas[largest] = temp;
            i = largest;
            continue;
        }
        else
            break;
    }
}

创建堆

思路:逐个加入元素,调整为最大堆或最小堆,直到将所有的元素全部处理完。

void build_max_heap(int *datas,int length)//创建最大堆
{
    int i;
    //build max heap from the last parent node
    for(i=length/2;i>0;i—)//从最后一个非叶子节点(n/2)开始到第一个非叶子(1)结束
        adjust_max_heap(datas,length,i);
}

堆排序

思路:创建堆,然后从后往前调整堆。

void heap_sort(int *datas,int length)
{
    int i,temp;
    //bulid max heap
    build_max_heap(datas,length);//创建最大堆
    i=length;
    //exchange the first value to the last unitl i=1
    while(i>1)
    {
        temp = datas[i];
        datas[i] = datas[1];
        datas[1] =temp;
        i--;
        //adjust max heap,make sure the fisrt value is the largest
        adjust_max_heap(datas,i,1);
    }
}

堆排序算法时间复杂度:调整堆过程满足递归式T(n)<=T(2n/3)+θ(1),有master定义可以知道T(n) = O(lgn),堆排序过程中执行一个循环,调用最大堆调整函数,总的时间复杂度为O(nlgn)。

优先级队列

优先级队列有两种:最大优先级队列和最小优先级队列,这两种类别分别可以用最大堆和最小堆实现。

优先级队列操作(最大优先级队列--最大堆)

插入:返回最大(优先级)元素:返回最大堆的第一个元素

最大(优先级)元素出队:删除最大堆的第一个元素,然后把最后一个移动到第一个位置,从第一个位置开始调整堆。

提高优先级:增加优先级,然后从该节点父节点开始向上调整堆。

入队:插入堆尾部,然后从该节点父节点开始向上调整堆。

优先级队列应用

实现FIFO队列:优先级递增

实现FILO:优先级递减