文章目录
背景构建最大堆代码实现测试
通过最大堆实现优先队列成语汉字频率统计案例统计四字成语文件中的汉字出现频率的前5位项目结构汉字频率的类优先队列测试类成语汉字统计主程序
背景
在《自已做动画及编写程序搞清楚最大堆的实现原理》这篇文章中,我们通过动图分析编 码自行实现了最大堆的数据结构,并在文章末尾提到了最大堆的应用–优先队列。该文将通过“四字成语汉字频率统计”的实际应用,把最大堆与优先队列的原理再次进行深入剖析。
构建最大堆
由于堆是一种特殊的完全二叉树,可以利用数组集合形成线性存储的数据结构。通过每个父结点与左右子结点大小的比较,使得根结点最大,且每个父结点都大于左右结点。
代码实现
public class MaxHeap<E
extends Comparable<E>> {
private ArrayList
<E> list
;
MaxHeap() {
this.list
= new ArrayList<>();
}
private int getLeftChildIndex(int i
) {
return (2 * i
+ 1);
}
private int getRightChildIndex(int i
) {
return (2 * i
+ 2);
}
private int getParentIndex(int i
) {
if (i
== 0) {
throw new IllegalArgumentException("非法索引值");
} else {
return ((i
- 1) / 2);
}
}
public void heapify(E
[] arr
){
this.list
.addAll(Arrays
.asList(arr
));
for (int i
=getParentIndex(this.list
.size()-1);i
>=0;i
--){
shiftDown(i
);
}
}
public void add(E e
) {
this.list
.add(e
);
shiftUp(this.list
.size() - 1);
}
private void shiftUp(int i
){
while (i
> 0) {
E current
= this.list
.get(i
);
E parent
= this.list
.get(getParentIndex(i
));
if (parent
.compareTo(current
) < 0) {
Collections
.swap(this.list
, i
, getParentIndex(i
));
} else {
break;
}
i
= getParentIndex(i
);
}
}
public E
findMax() {
if (this.list
.size() == 0) {
return null
;
}
return this.list
.get(0);
}
public E
getMax() {
if (findMax() != null
) {
E e
= findMax();
int i
= 0;
Collections
.swap(this.list
, i
, this.list
.size() - 1);
this.list
.remove(this.list
.size() - 1);
shiftDown(i
);
return e
;
} else {
return null
;
}
}
private void shiftDown(int i
){
while (getLeftChildIndex(i
) < this.list
.size()) {
int leftIndex
= getLeftChildIndex(i
);
int index
= leftIndex
;
if (getRightChildIndex(i
) < this.list
.size() &&
this.list
.get(getRightChildIndex(i
)).compareTo(this.list
.get(leftIndex
)) > 0) {
index
= getRightChildIndex(i
);
}
if (this.list
.get(i
).compareTo(this.list
.get(index
)) >= 0) {
break;
}
Collections
.swap(this.list
, i
, index
);
i
= index
;
}
}
public int getSize(){
return this.list
.size();
}
public E
replace(E e
){
E ret
= findMax();
this.list
.set(0,e
);
shiftDown(0);
return ret
;
}
}
测试
public class MaxHeapTest {
public static void main(String
[] args
) {
MaxHeap
<Integer> maxHeap
= new MaxHeap<>();
Integer
[] arrays
= {19,29,4,2,27,0,38,15,12,31};
maxHeap
.heapify(arrays
);
for (int i
= 0; i
< arrays
.length
; i
++) {
System
.out
.println("第"+(i
+1)+"次取出堆目前的最大值:"+maxHeap
.getMax());
}
}
}
通过最大堆实现优先队列
具有优先级最高的元素最先出队。
public class PriorityQueue<E
extends Comparable<E>> {
private MaxHeap
<E> mhp
;
PriorityQueue() {
mhp
= new MaxHeap<>();
}
public void enqueue(E e
) {
mhp
.add(e
);
}
public E
dequeue() {
return mhp
.getMax();
}
public E
getFront() {
return mhp
.findMax();
}
public int getSize() {
return mhp
.getSize();
}
}
成语汉字频率统计案例
统计四字成语文件中的汉字出现频率的前5位
通过最大堆的数据结构实现优先队列,优先队列具有入队、出队、查看最先出队元素的功能;建立一个汉字频率的类,并实现比较大小的方法:出现频率越低认为优先级越高。编写优先队列测试类,设置汉字出现的次数,验证汉字出现频率越低的最先出队。编写成语汉字统计主程序: – 读取四字成语的文件,形成字符串; – 将字符串转换成汉字数组,通过HashMap统计汉字及其出现频率; – 将HashMap中每个汉字与出现频率,依次放入优先队列中,若后续放入的汉字频率高于队列优先级最高的汉字频率,则进行替换。
项目结构
汉字频率的类
public class CharFrequency implements Comparable<CharFrequency> {
private char c
;
private int frequency
;
CharFrequency(char c
, int frequency
) {
this.c
= c
;
this.frequency
= frequency
;
}
@Override
public int compareTo(CharFrequency o
) {
if (this.frequency
< o
.frequency
) {
return 1;
} else if (this.frequency
> o
.frequency
) {
return -1;
} else {
return 0;
}
}
public char getC() {
return c
;
}
public void setC(char c
) {
this.c
= c
;
}
public int getFrequency() {
return frequency
;
}
public void setFrequency(int frequency
) {
this.frequency
= frequency
;
}
@Override
public String
toString() {
return c
+", 出现频率=" + frequency
;
}
}
优先队列测试类
public class PriorityQueueTest {
public static void main(String
[] args
) {
PriorityQueue
<CharFrequency> priorityQueue
= new PriorityQueue<>();
priorityQueue
.enqueue(new CharFrequency('二',2));
priorityQueue
.enqueue(new CharFrequency('五',5));
priorityQueue
.enqueue(new CharFrequency('三',3));
priorityQueue
.enqueue(new CharFrequency('四',4));
priorityQueue
.enqueue(new CharFrequency('一',1));
System
.out
.println(priorityQueue
.dequeue());
System
.out
.println(priorityQueue
.dequeue());
System
.out
.println(priorityQueue
.dequeue());
System
.out
.println(priorityQueue
.dequeue());
System
.out
.println(priorityQueue
.dequeue());
}
}
成语汉字统计主程序
public class IdiomFreqCount {
public final static int count
= 5;
public static void main(String
[] args
) throws IOException
{
InputStreamReader inputStreamReader
= new InputStreamReader(new FileInputStream("c:\\四字成语.txt"), "GBK");
BufferedReader bufferedReader
= new BufferedReader(inputStreamReader
);
StringBuilder stringBuilder
= new StringBuilder();
String idiom
;
int len
= 0;
while ((idiom
= bufferedReader
.readLine()) != null
) {
stringBuilder
.append(idiom
);
len
++;
}
bufferedReader
.close();
System
.out
.println("总共成语" + len
+ "个");
char[] array
= stringBuilder
.toString().toCharArray();
HashMap
<Character, Integer> hashMap
= new HashMap<>();
for (int i
= 0; i
< array
.length
; i
++) {
if (!hashMap
.containsKey(array
[i
])) {
hashMap
.put(array
[i
], 1);
} else {
hashMap
.put(array
[i
], hashMap
.get(array
[i
]) + 1);
}
}
System
.out
.println("总共出现汉字" + hashMap
.keySet().size() + "个");
PriorityQueue
<CharFrequency> priorityQueue
= new PriorityQueue<>();
for (char key
: hashMap
.keySet()) {
if (priorityQueue
.getSize() < count
) {
priorityQueue
.enqueue(new CharFrequency(key
, hashMap
.get(key
)));
} else {
if (hashMap
.get(key
) > priorityQueue
.getFront().getFrequency()) {
priorityQueue
.repalcePriority(new CharFrequency(key
, hashMap
.get(key
)));
}
}
}
int index
= Math
.min(priorityQueue
.getSize(), count
);
for (int i
= 0; i
< index
; i
++) {
System
.out
.println(priorityQueue
.dequeue().toString());
}
}
}
输入文件: 输出结果: