堆(heap)、堆排序(heapSort)、优先级队列

7 篇文章 0 订阅
5 篇文章 0 订阅

1. 堆数据结构: 堆是一种数据结构。分为大根堆和小根堆。  

         对堆数组,其分布与一个完全二叉树对应,其下标的几个关系:  

        当i的取值满足区间[1, n]时; 数组的小标从1开始;

          parent(i) = i  >> 1; 

          left(i) = 2*i;

          right(i) = 2*i +1;


          对于C语言的数组的小标从0开始,稍作调整如下:

           parent(i) = ( ( (i) - 1  ) >> 1);  // i >= 1;                               
           left(i)       = ( ( (i) << 1 ) + 1);   // i >= 0;                                  
           right(i)    = ( ( (i) << 1 ) + 2)    // i >= 0;                      

 

parent(i) = ( ( (i) - 1  ) >> 1);  // i >= 1;  
left(i)   = ( ( (i) << 1 ) + 1);   // i >= 0;  
right(i)  = ( ( (i) << 1 ) + 2)    // i >= 0;


堆的性质:

  对于大根堆数组a: 满足: a[parent(i)] >= a[i];

  对于小跟堆数组a :   满足: a[parent(i)] <= a[i];


2.堆的构建: 通过堆的调整,完成堆的构建。

 堆的构建的两种方式: 

 1)像插入排序的方式那样进行增量(incremental)求解, 即其满足循环不变式的性质:

总的描述: 数组a[0...j-1]是一个堆,将a[j]加入,通过堆调整,数组a[0...j]也是一个堆。

        满足循环不变式的3个条件:

          (1)初始化:只有一个a[0]数组a是一个堆。

          (2) 保持: 数组a[0...j-1]是一个堆,将a[j]加入,通过堆调整,数组a[0...j]也是一个堆。

          (3)终止: 当数组中所有的元素都加入完毕式,整个数组满足堆的性质,是一个堆。

  2)合并求解: 以a[i] 为根的拟堆,除a[i] 以外其他所有的元素都满足堆的性质,即除了a[i]以外是以它的两个孩子为根的两个堆。通过堆调整将a[i]加入,形成以a[i]为根的堆。

在数组a中,若数组的元素个数为n,则从a[n/2]、a[n/2 +1] ... a[n-1]满足堆的性质。

     满足循环不变式的三个性质:

        (1)初始化: 则从a[n/2]、a[n/2 +1] ... a[n-1]满足堆的性质。

        (2)保持: 将a[n/2-1] 加入,通过堆调整,a[n/2-1]、a[n/2]、a[n/2 +1] ... a[n-1]满足堆的性质。

        (3)终止:形成以a[0]为根的堆。

算法实现是基于第二种。



3. 堆排序算法: 采用大根堆。首先对数组a[0...n-1]通过2中的方法建立大根堆。

      方法: 将a[0...n-1]  中 根元素a[0] 与 a[n-1]交换,则最大元素a[n-1]确定了,

                  通过堆调整,形成新的堆数组a[0...n-2].  重复上述过程,最终完成排序。

     上述过程是一个循环不变式:

         (1)初始化: a[0...n-1] 是个大根堆。

         (2)保持:在大根堆a[0...i] 中,将a[i]与a[0]交换确定a[i], 通过调整a[0...i-1]形成新的大根堆。

         (3)终止:确定最小的元素a[0].

   算法的实现:

   

/**
 * \file    heapSort.c
 *
 * \brief  Heap Sort test file
 */


#include <stdio.h>
#include <stdlib.h>

#define MaxLen  100
#define parent(i) (((i)-1)>>1)
#define left(i)   (((i)<<1) + 1)
#define right(i)  (((i)<<1) + 2)

/**
 * \brief      exchange the value of tow integers.
 *
 * \param  a   integer point.
 * \param  b   integer point.
 */
void exchange(int* a, int* b);

/**
 * \brief       print an integer array.
 *
 * \param  a    integer array point.
 * \param  len  total # of elements of the array.
 */
void printArray(int* a, int len);

/**
 * \brief       Max(big) root heap adjust without recurrence.
 *
 * \param  a    array point.
 * \param  i    element location.
 * \param  len  total # of elements of the array.
 */
void maxHeapify(int* a, int i, int len);

/**
 * \brief       Min(small) root heap adjust without recurrence.
 *
 * \param  a    array point.
 * \param  i    element location.
 * \param  len  total # of elements of the array.
 */
void minHeapify(int* a, int i, int len);


/**
 * \brief       Max(big) root heap adjust with recurrence.
 *
 * \param  a    array point.
 * \param  i    element location.
 * \param  len  total # of elements of the array.
 */
void maxHeapify_r(int* a, int i, int len);

/**
 * \brief       Min(small) root heap adjust with recurrence.
 *
 * \param  a    array point.
 * \param  i    element location.
 * \param  len  total # of elements of the array.
 */
void minHeapify_r(int* a, int i, int len);

/**
 * \brief       build max(big) root heap.
 *
 * \param  a    integer array point.
 * \param  len  total # of elements of the array.
 */
void buildMaxHeap(int* a, int len);

/**
 * \brief       build min(small) root heap.
 *
 * \param  a    integer array point.
 * \param  len  total # of elements of the array.
 */
void buildMinHeap(int* a, int len);

/**
 * \brief       heap sort in ascending order.
 *
 * \param  a    integer array point.
 * \param  len  total # of elements of the array.
 */
void heapSort(int* a, int len);

/**
 * \brief       heap sort in decending order.
 *
 * \param  a    integer array point.
 * \param  len  total # of elements of the array.
 */
void heapSort_reverse(int* a, int len);




int main(int argc, char* argv[])
{
    int a[] = {3, 4, 8, 6, 7, 1, 2, 5, 9};
    int len = 9;
    heapSort(a, len);
    //heapSort_reverse(a, len);
    printArray(a, len);
    return 0;
}

void exchange(int* a, int* b) {
    int tmp;

    tmp = *a;
    *a = *b;
    *b = tmp;
}
void printArray(int* a, int len) {
    int i;

    for(i=0; i<len; i++) {
        printf("%d\t", a[i]);
    }

    printf("\n");

}

void maxHeapify_r(int *a, int i, int len) {
    int l;
    int r;
    int largest;

    l = left(i);
    r = right(i);
    largest = i;

    if(l<len && a[largest]<a[l]) largest = l;
    if(r<len && a[largest]<a[r]) largest = r;

    if(largest!=i) {
        exchange(a+largest, a+i);
        maxHeapify_r(a, largest, len);
    }
}

void maxHeapify(int *a, int i, int len) {
    int l;
    int r;
    int largest;
    int tag;    //to indicate the changeable.

    do{
        tag = 0;
        l = left(i);
        r = right(i);
        largest = i;

        if(l<len && a[largest]<a[l]) largest = l;
        if(r<len && a[largest]<a[r]) largest = r;

        if(largest!=i) {
            exchange(a+largest, a+i);
            i = largest;
            tag = 1;
        }
    }while(tag);

}

void minHeapify_r(int* a, int i, int len) {
    int l;
    int r;
    int least;

    l = left(i);
    r = right(i);
    least = i;

    if(l<len && a[least]>a[l]) least = l;
    if(r<len && a[least]>a[r]) least = r;

    if(least!=i) {
        exchange(a+least, a+i);
        minHeapify_r(a, least, len);
    }
}


void minHeapify(int *a, int i, int len) {
    int l;
    int r;
    int least;
    int tag;    //to indicate the changeable.

    do{
        tag = 0;
        l = left(i);
        r = right(i);
        least = i;


        if(l<len && a[least]>a[l]) least = l;
        if(r<len && a[least]>a[r]) least = r;

        if(least!=i) {
            exchange(a+least, a+i);
            i = least;
            tag = 1;
        }
    }while(tag);

}

void buildMaxHeap(int* a,  int len) {
    int i;
    int half = (len>>1) -1;

    for(i=half; i>=0; i--) {
       maxHeapify(a, i, len);
       //maxHeapify_r(a, i, len);
    }
}

void buildMinHeap(int* a,  int len) {
    int i;
    int half = (len>>1) -1;
    for(i=half; i>=0; i--) {
        minHeapify(a, i, len);
        //minHeapify_r(a,i, len);
    }
}

void heapSort(int *a, int len) {
    int i;

    buildMaxHeap(a, len);
    //printArray(a, len);

    for(i=len-1; i>0; i--) {
        exchange(&a[i], &a[0]);
        len--;
        maxHeapify(a, 0, len);
    }

}

void heapSort_reverse(int *a, int len) {
    int i;

    buildMinHeap(a, len);
    //printArray(a, len);

    for(i=len-1; i>0; i--) {
        exchange(&a[i], &a[0]);
        len--;
        minHeapify(a, 0, len);
    }

}



// usage for priority queue.
int maxHeapMaximum(int* a, int len) {
    return a[0];
}

int minHeapMinimum(int* a, int len) {
    return a[0];
}


int maxHeapExtractMax(int* a, int* len) {
    int max;
    if(*len<1) return -1;  //heap empty

    max = a[0];
    a[0] = a[*len-1];
    *len--;
    maxHeapify(a, 0, *len);

    return max;
}

int minHeapExtractMin(int* a, int* len) {
    int min;
    if(*len<1) return -1;  //heap empty

    min = a[0];
    a[0] = a[*len-1];
    *len--;
    minHeapify(a, 0, *len);

    return min;
}

int maxHeapIncreaseKey(int* a, int i, int len, int key){
   if(i>len || key<=a[i]) return -1;
   int p;

   a[i] = key;
   p = parent(i);

   while(i>0 && a[i]>a[p]) {
        exchange(a+i, a+p);
        i = p;
        p = parent(i);
   }

    return 0;
}

int minHeapDecreaseKey(int* a, int i, int len, int key){
   if(i>len || key>=a[i]) return -1;
   int p;

   a[i] = key;
   p = parent(i);

   while(i>0 && a[i]<a[p]) {
        exchange(a+i, a+p);
        i = p;
        p = parent(i);
   }

    return 0;
}

int  maxHeapInsert(int* a, int *len, int key) {
    int i;
    int p;

    *len += 1;
    if(*len > MaxLen) return -1;

    i = *len - 1;
    p = parent(i);
    a[i] = key;

    while(i>0 && a[i]>a[p]) {
        exchange(a+i, a+p);
        i = p;
        p = parent(i);
    }

    return 0;
}


int  minHeapInsert(int* a, int *len, int key) {
    int i;
    int p;

    *len += 1;
    if(*len > MaxLen) return -1;

    i = *len - 1;
    p = parent(i);
    a[i] = key;

    while(i>0 && a[i]<a[p]) {
        exchange(a+i, a+p);
        i = p;
        p = parent(i);
    }

    return 0;
}


int maxHeapDelete(int* a,  int i, int* len) {
    int p;

    if(i> *len ) return -1;

    a[i] = a[*len -1];

    *len --;
    maxHeapify(a, i, *len);

    p = parent(i);
    while(i>0 && a[i]>a[p]) {
        exchange(a+i, a+p);
        i = p;
        p = parent(i);
    }

    return 0;
}


int minHeapDelete(int* a,  int i, int* len) {
    int p;

    if(i> *len ) return -1;

    a[i] = a[*len -1];

    *len --;
    minHeapify(a, i, *len);

    p = parent(i);
    while(i>0 && a[i]<a[p]) {
        exchange(a+i, a+p);
        i = p;
        p = parent(i);
    }

    return 0;
}



4.  用堆数据结构构造优先级队列。


5.用堆构造的优先级队列构造栈、和队列数据结构。


6. 算法分析

  堆排序的时间,主要由建立初始堆和反复重建堆这两部分的时间开销构成,它们均是通过调用Heapify实现的。
  堆排序的最坏时间复杂度为 O(nlogn) 。堆序的平均性能较接近于最坏性能。
  由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。
  堆排序是就地排序,辅助空间为O(1),
  它是 不稳定 的排序方法。


以上参见《算法导论》的第6章。。。


 

 

                  


     



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值