算法练习——堆排序应用(优先队列)

优先队列作为堆排序的高级应用具有十分广泛的应用场景,其中一个就是在共享计算机系统的作业调度。最大优先队列记录将要执行的各个作业以及它们之间的相对优先级.

当一个作业完成或者被中断后,调度器调用  EXTRACT-MAX  从所有的等待作业中,选出具有最高优先级的作业来执行。

在任何时候,调度器可以调用 INSERT() 把一个新作业加入到队列中来。

下面就讨论一下关于优先队列的基本操作:

优先队列(priority queue)是一种用来维护由一组元素构成的集合S的数据结构,其中的每一个元素都有一个相关的值,称为关键字( key).一个最大优先队列支持以下操作:

  INSERT(S , x): 把元素x插入集合S中。

  MAXIMUM(S):返回S中具有最大键字的元素.

  EXTRACT-MAX(S):去掉并返回S中的具有最大键字的元素。

  INCREASE-KEY(S , x,k):将元素x的关键字值增加到k,这里假设k的值不小于x的原关键字值。
  HeapDelete(A,i)    :删除第 i 个位置的元素

  

下面分别给出各自的伪代码描述:

1     INSERT(S,x) 

    把元素x插入到集合S中

1 MaxHeapInsert(A,key)
2     A.heapsize = A.heapsize+1
3     A[A.heapsize] =-无穷大
4     HeapIncreaseKey(A,A[A.heapsize],key)

     此时时间复杂度主要消耗在    HeapIncreaseKey()   上,而后者的时间复杂度为   O(logn)

2   INCREASE_KEY(S,x,k)

    将元素x的关键字值增加为k(前提:k>=x)     整体的算法:从开始增大的那个值开始往根节点循环调用。(自低向顶) 

      该方法的时间复杂度为    O(logn)     因为第三行做关键字更新的结点到根节点的路径长度为  O(logn)

1 HeapIncreaseKey(A,x,key)
2     if key <= A[i]
3         error "请输入更大的key值"
4     A[i] = key
5     while i >=0 && A[Parent(i)] <= A[i]
6         Exchange A[i] with A[Parent(i)]
7         i = Parent(i)

    HEAP-INCREASE-KEY的操作过程.(a)图6-4(a)中的最大堆,其中下标为i的结点以深色阴影显示.
    (b)该结点的关键字增加到15.
    (c)经过第 4--6 行的 while 循环的一次迭代,该结点与其父结点交换关键字,
    同时下标i的指示上移到其父结点.(d)经过再一次迭代后得到的最大堆.此时,
    A[PARENT(i)]≥A[f].现在,最大堆的性质成立,程序终止

3    EXTRACT_MAX(S)

    去掉并且返回S中的最大关键字元素

HeapMaxImum(A)
    max = A[0]
    A[0] = A[A.heapsize] 
    A.heapsize = A.heapsize-1
    MaxHeap(A,0)
    return max

       EXTRACT_MAX(S)   的时间复杂度为   O( log(n) ),因此除了MaxHeap(A,i)的时间复杂度为O(logn)之外,其余的时间复杂度均为常数。

4   MaxIMUM(S)

    取得S集合中的最大值

HeapMaxImum(A)
    return A[0]

5   HeapDelete(A,i)    

    删除第 i 个位置的元素

1 HeapDelete(A,i)
2     temp = A[i]
3     A[i] = A[A.heapsize]
4     A.heapsize = A.heapsize-1
5     MaxHeap(A,i)
6     return temp

具体的代码实现:

 1 /*
 2  * 优先队列主要通过四个函数来实现
 3  */
 4 public class Priorityqueue {
 5     
 6     static int[] a={15,13,9,5,21,8,7,4,0,6,2,1};
 7     public static int [] heap =a ;
 8     public static int heapsize = heap.length;
 9     
10     //给优先队列插入某一个值   数组大小不容易控制     可以考虑使用链表
11     public void MaxHeapInsert(int[] A,int key){
12         heapsize = heapsize+1;
13         a[heapsize-1] = -1000;
14         HeapIncreaseKey(a,heapsize,key);
15     }
16     
17     //增加第i个元素的数值
18     public void HeapIncreaseKey(int[] a2, int i, int key) {
19         if (key <= a[i]) 
20             System.out.println("请输入更大的值------");
21         a[i] = key;
22         //这里也可以用递归
23         while(i > 0 && a[HeapSort.findParent(i)]<a[i] ){
24             swap(a,HeapSort.findParent(i) , i);
25             i = HeapSort.findParent(i);
26         }
27         
28     }
29 
30     //交换数组中的两个元素
31     private void swap(int[] a2, int parent, int i) {
32         int temp = a[i];
33         a[i] = a[parent];
34         a[parent] = temp;
35     }
36     
37     //取得优先队列的最大值
38     public int HeapMaximum(){
39         return a[0];
40     }
41     
42     //去掉并且返回最大值最大值
43     public int HeapExtractMax(int[] b){
44         int max = b[0];
45         b[0] = b[heapsize-1];
46         heapsize--;
47         HeapSort.maxHeap(b , 0);
48         return 0;
49     }
50 
51     //删除优先队列中第i个位置的元素     这里面调用的HeapSort.maxHeap(a,i)  主要来自于上一篇文章中的maxHeap() 在于维持最大堆的性质
52     public void MaxHeapDelete(int[] b,int i){
53         int temp = b[i];
54         b[i] = b[heapsize-1];
55         heapsize--;
56         HeapSort.maxHeap(b, i);
57     }
58     
59     public void printMy(int[] a){
60         for (int i = 0; i < heapsize; i++) 
61             System.out.print(a[i]+" ");
62         System.out.println();
63     }
64 
65     
66     public static void main(String[] args){
67         Priorityqueue pqueue = new Priorityqueue();
68         System.out.print("原数组:  ");
69         pqueue.printMy(a);
70         
71         HeapSort.createHeap(a);
72         System.out.print("最大堆:  ");
73         pqueue.printMy(a);
74         
75         pqueue.HeapIncreaseKey(a, 7, 11);
76         System.out.print("增加数值  ");
77         pqueue.printMy(a);
78         
79         int max = pqueue.HeapMaximum();
80         System.out.print("返回最大值  ");
81         System.out.println(max);
82         
83         int extracte = pqueue.HeapExtractMax(a);
84         System.out.print("去掉最大值:  ");
85         pqueue.printMy(a);
86     }
87     
88 }

总之,对于优先队列中所有的操作都可以在   O(logn)  的时间复杂度内完成。

原文地址:https://www.cnblogs.com/xiaxj/p/7410046.html