zoukankan      html  css  js  c++  java
  • 堆排序和优先级队列

    堆排序和优先级队列

      堆排序:和合并排序一样,时间复杂度为O(nlgn);同时和插入排序一样,在原序列中进行;这样堆排序集合了合并排序和插入排序的优点。

      堆排序的另一个特点是利用了"堆"这种数据结构. 堆数据结构还不止在堆排序中有用,还可以构成一个有效的优先队列.

      堆: 是一种数据结构,也是一种数组对象,如图 1-1所示: 

    图 1-1 最大堆(图片来源《算法导论》)

      如上图1-1 所示, 可以被看成一棵完全二叉树,二叉树的的每个节点和数组中存放该节点的那个元素对应.在使用"堆"数据机构的时候,其实并不需求真正构建一棵完全二叉树, 数据的存储依然是在一个数组中,操作也在数组中,只是数组中数据的存放,位置关系如完全二叉树所示,我们在构造堆的时候其实是在构建数组中数据的关系. 上图所示一个最大堆(父节点大于两个子节点), 最小堆同理.

      由于我们将数组中的数据关系对应成了一块完全二叉树,所以对数组的各种操作时间复杂度也应该和完全二叉树操作向对应,即O(nlgn). 下文所以的堆即代指"最大堆"

      堆排序

      根据堆的性质,父节点大于子节点,那么根节点一定是最大的,继而数组中第一个数据也应该是最大的. 根据冒泡排序和选择排序的原理, 如果将每次数组中的第一个元素和最后一个元素进行交换,再让第一个到倒数第二个形成的新数组重新形成最大堆,再次将新数组第一个和最后一个交换;需要重新建堆的数组长度不断减小.如此循环下去,最后原数组成了一个有小到大的有序序列.

      根据上面的论述,如何让无序的元素,构建成一个符合(最大/最小)堆性质的堆才是关键.

      保持堆(最大堆)性质原理: 将父节点和两个子节点进行比较,找到那个最大;如果父节点最大,该节点符合最大堆性质;如何是两个子节点中某个最大,将最大子节点和父节点位置进行交换; 在查看新的子节点作为父节点是否符合最大堆的性质,以此循环.

      代码如下:

     1 //子节点和父节点在数组中位置的对应关系(数组从0开始)
     2 int parent(int i)
     3 {
     4     return (int)((i-1)/2); 
     5 }
     6 //父节点和左子节点在数组中的位置对应关系
     7 int Left(int i)
     8 {
     9     return 2*i+1;
    10 }
    11 //父节点和右子节点在数组中的位置对应关系
    12 int Right(int i)
    13 {
    14     return 2*i+2;
    15 }
    16 
    17 //保持最大堆性质,循环控制的形式
    18 void MaxHeapify(int A[], int  i,int length)
    19 {
    20     int left,right,largest;
    21     left=Left(i);
    22     right=Right(i);
    23 
    24     largest=length;
    25 
    26     while(largest!=i){
    27 
    28     if(left<length && A[left]>A[i]) 
    29         largest=left;
    30     else
    31         largest=i;
    32     if(right<length && A[right]>A[largest])
    33         largest=right;
    34         int temp;
    35         temp=A[largest];
    36         A[largest]=A[i];
    37         A[i]=temp;        
    38     }
    39 
    40 }
    41 
    42 //保持最小堆性质,递归的形式
    43 void MinHeapify(int A[], int  i,int length)
    44 {
    45     int left,right,minmun;
    46     left=Left(i);
    47     right=Right(i);
    48 
    49     if(left<length && A[left]<A[i]) 
    50         minmun=left;
    51     else
    52         minmun=i;
    53     if(right<length && A[right]<A[minmun])
    54         minmun=right;
    55 
    56     if(minmun!=i)
    57     {
    58         int temp;
    59         temp=A[minmun];
    60         A[minmun]=A[i];
    61         A[i]=temp;
    62 
    63         MaxHeapify(A,minmun,length);
    64     }
    65 
    66 }

      建堆以及堆排序算法: 

      堆排序的基本原理就是对一个无序数组建立堆关系,再利用堆的性质不断重数组中查找最值元素.

      建堆的代码如下:

    1 void BuildMaxHeapify(int A[], int length)
    2 {
    3     int i;
    4     for(i=(int)((length-1)/2);i>=0;i--)
    5         MaxHeapify(A,i,length);
    6 }

      堆排序的算法代码如下: 

     1 void Heapsort(int A[],int Length)
     2 {
     3     int i;
     4     int temp;
     5     BuildMaxHeapify(A,Length);
     6 
     7     for(i=Length;i>=1;i--)
     8     {
     9         MaxHeapify(A,0,i);
    10 
    11         temp=A[i-1];
    12         A[i-1]=A[0];
    13         A[0]=temp;
    14 
    15     }
    16 
    17 }

      优先级队列

      优先级队列分为最大优先级队列和最小优先级队列.(应用举例摘于《算法导论》)

      最大优先级队列应用:其一,一台分时计算机上进行作业调度,如何从具有优先级标示的队列中选择优先级最高的任务.

      最小优先级队列应用: 其一, 被用在基于事件驱动的模拟器中. 在这种应用中,队列中的各项是要模拟的事件,每一个都有一个发生时间作为关键字。事件模拟按照各事件的发生时间的顺序进行,因为模拟某一事件可能导致稍后对其他事件的模拟。模拟程序都使用EXTRACT-MIN来选择下一个事件,而使用INSERT将一个新事件插入队列中。

      最大优先级队列提取操作代码如下:

     1 int HeapExtractMax(int A[], int length)
     2 {
     3     int max;
     4 
     5     if(length<1)
     6         printf("the heap underflow!
    ");
     7     else
     8     {
     9         max=A[0];
    10         A[0]=A[length-1];
    11 
    12         MaxHeapify(A,0,length);
    13     }
    14 
    15     return max;
    16 }

      最大优先级队列提高或减小优先级操作代码如下:

     1 void HeapIncreaseKey(int A[],int i,int key)
     2 {
     3     int temp;
     4     
     5     if(key<A[i])
     6     {
     7         printf("The new key can not be smaller than current key!
    ");
     8     }
     9     else
    10     {
    11         while(i>=0 && A[parent(i)]<key)
    12         {
    13             temp=A[parent(i)];
    14             A[parent(i)]=key;
    15             key=temp;
    16 
    17             i=parent(i);
    18         }
    19     }
    20 }
    21 
    22 //减小某一元素的关键字
    23 void  HeapDecreaseKey(int A[],int i,int key,int length)
    24 {
    25     int temp;
    26 
    27     if(key>A[i])
    28     {
    29         printf("The new key can not be bigger than current key!
    ");
    30     }
    31     else
    32     {
    33         while(i<length && (key<A[Left(i)] || key<(Right(i))))
    34         {
    35             if(key<A[Left(i)])
    36             {
    37                 temp=A[Left(i)];
    38                 A[Left(i)]=key;
    39                     key=temp;
    40 
    41                     i=Left(i);
    42             }
    43             else
    44             {
    45                 temp=A[Right(i)];
    46                 A[Right(i)]=key;
    47                     key=temp;
    48 
    49                     i=Right(i);
    50             }
    51 
    52         }
    53     }
    54     
    55 }

      最大优先级队列插入新元素操作代码如下:

    1 void MaxHeapInsert(int A[],int key,int length)
    2 {
    3     length=length+1;
    4     A[length-1]=-1;//假设数组内的整数全部大于0
    5     
    6     HeapIncreaseKey(A,length-1,key);
    7 }
  • 相关阅读:
    框架-前端框架:layui
    开发模式-敏捷开发:什么是敏捷开发
    公司-便利蜂:便利蜂
    人物-IT-周鸿祎:百科
    公司-人人网:人人网
    未来-YLB-二手市场:二手市场
    未来-YLB-跳蚤市场:跳蚤市场(flea market)
    公司-浪潮:浪潮/inspur
    禁止CloudStack删除Xenserver原有虚拟机
    2.6.33中关于at91sam9260的i2c controller驱动的问题
  • 原文地址:https://www.cnblogs.com/zhengyou/p/3582369.html
Copyright © 2011-2022 走看看