优先级队列 - Java实现
优先级队列,是堆数据结构的典型应用。优先级队列的一个典型应用,就是排队任务的有限调度,当一个任务结束后,优先执行当前优先级最高的任务。队列一个任务是,调用INSERT方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package lhz.algorithm.chapter.six;
/**
* "优先级队列",《算法导论》6.5章节
* 原文摘要:
* A priority queue is a data structure for maintaining a set S of elements, each with an
* associated value called a key. A max-priority queue supports the following operations.
* ・ INSERT(S, x) inserts the element x into the set S. This operation could be written as S← S{x}.
* ・ MAXIMUM(S) returns the element of S with the largest key.
* ・ EXTRACT-MAX(S) removes and returns the element of S with the largest key.
* ・ INCREASE-KEY(S, x, k) increases the value of element x‘s key to the new value k,
* which is assumed to be at least as large as x‘s current key value.
* 堆的一种实际应用,可用于任务调度队列等。包含四个操作方法。
* @author lihzh(OneCoder)
* @blog http://www.coderli.com
*/
public class PriorityQueue {
private static final int DEFAULT_CAPACITY_VALUE = 16;
//初始化一个长度为16的队列(可作为构造参数),此处选择16参考HashMap的初始化值
private int[] queue;
//堆大小
private int heapSize = 0;
public static void main(String[] args) {
PriorityQueue q = new PriorityQueue();
q.insert(2);
q.insert(6);
q.insert(3);
q.insert(8);
q.insert(7);
q.insert(9);
q.insert(1);
q.insert(10);
q.insert(9);
System.out.println(q.extractMax());
System.out.println(q.extractMax());
q.insert(9);
q.insert(1);
q.insert(10);
System.out.println(q.extractMax());
System.out.println(q.extractMax());
System.out.println(q.extractMax());
System.out.println(q.extractMax());
System.out.println(q.extractMax());
System.out.println(q.extractMax());
System.out.println(q.extractMax());
}
public PriorityQueue(int capacity) {
this.queue = new int[capacity];
}
public PriorityQueue() {
this(DEFAULT_CAPACITY_VALUE);
}
/**
* 返回当前最大值
* @return
*/
public int maximum() {
return queue[0];
}
/**
* 往优先级队列出,插入一个元素
* 利用INCREASE-Key方法,从堆的最后增加元素
* 伪代码:
* MAX-HEAP-INSERT(A, key)
* 1 heap-size[A] ← heap-size[A] + 1
* 2 A[heap-size[A]] ← -∞
* 3 HEAP-INCREASE-KEY(A, heap-size[A], key)
* 时间复杂度:O(lg n)
* @param value 待插入元素
*/
public void insert(int value) {
//注意堆容量和数组索引的错位 1
queue[heapSize] = value;
heapSize++;
increaceKey(heapSize, value);
}
/**
* 增加给定索引位元素的值,并重新构成MaxHeap。
* 新值必须大于等于原有值
* 伪代码:
* HEAP-INCREASE-KEY(A, i, key)
* 1 if key < A[i]
* 2 then error "new key is smaller than current key"
* 3 A[i] ← key
* 4 while i > 1 and A[PARENT(i)] < A[i]
* 5 do exchange A[i] ↔ A[PARENT(i)]
* 6 i ← PARENT(i)
* 时间复杂度:O(lg n)
* @param index 索引位
* @param newValue 新值
*/
public void increaceKey (int heapIndex, int newValue) {
if (newValue < queue[heapIndex-1]) {
System.err.println("错误:新值小于原有值!");
return;
}
queue[heapIndex-1] = newValue;
int parentIndex = heapIndex / 2;
while (parentIndex > 0 && queue[parentIndex-1] < newValue ) {
int temp = queue[parentIndex-1];
queue[parentIndex-1] = newValue;
queue[heapIndex-1] = temp;
heapIndex = parentIndex;
parentIndex = parentIndex / 2;
}
}
/**
* 返回堆顶元素(最大值),并且将堆顶元素移除
* 伪代码:
* HEAP-EXTRACT-MAX(A)
* 1 if heap-size[A] < 1
* 2 then error "heap underflow"
* 3 max ← A[1]
* 4 A[1] ← A[heap-size[A]]
* 5 heap-size[A] ← heap-size[A] - 1
* 6 MAX-HEAPIFY(A, 1)
* 7 return max
* 时间复杂度:O(lg n),
* @return
*/
public int extractMax() {
if (heapSize < 1) {
System.err.println("堆中已经没有元素!");
return -1;
}
int max = queue[0];
queue[0] = queue[heapSize-1];
heapSize--;
maxHeapify(queue, 1);
return max;
}
/**
* 之前介绍的保持最大堆的算法
* @param array
* @param index
*/
private void maxHeapify(int[] array, int index) {
int l = index * 2;
int r = l + 1;
int largest;
//如果左叶子节点索引小于堆大小,比较当前值和左叶子节点的值,取值大的索引值
if (l <= heapSize && array[l-1] > array[index-1]) {
largest = l;
} else {
largest = index;
}
//如果右叶子节点索引小于堆大小,比较右叶子节点和之前比较得出的较大值,取大的索引值
if (r <= heapSize && array[r-1] > array[largest-1]) {
largest = r;
}
//交换位置,并继续递归调用该方法调整位置。
if (largest != index) {
int temp = array[index-1];
array[index-1] = array[largest-1];
array[largest-1] = temp;
maxHeapify(array, largest);
}
}
public int[] getQueue() {
return queue;
}
}
本文由作者按照 CC BY 4.0 进行授权