基于java优先队列(PriorityQueue)的多路排序算法(含代码)

[size=medium]归并排序用来合并排好序的数组,常用于外部排序,常见的归并排序是对两个数组进行归并,如果两个数组长度为m和n的话,比较的时间最大是m+n。

新的问题是,如果有多个排好序的数组,如果进行归并? 一种可以想到的方法是:逐个进行归并排序(第一个数组和第二个数组合并,合并和的数组再和第三个数组合并...),这种情况下时间复杂度是O(n*n)。

算法导论里提到过一个用堆来进行多路排序的算法,时间复杂度是nlogn,java里面的PriorityQueue就是现成的堆的结构,实现起来还是比较方便的,代码如下:[/size]

用到的内部数据结构:

// 如果用链表存储数据,就不用这么麻烦了,
// 用数组的话,使用一个内部类保存当前值对应的数组即其在数组中的索引
// 需要实现Comparable接口,否则PriorityQueue无法对对象进行比较
private static class Element implements Comparable<Element> {
int value;
int whichArray;
int whichIndex;

Element(int value, int whichArray, int whichIndex) {
this.value = value;
this.whichArray = whichArray;
this.whichIndex = whichIndex;
}

@Override
public int compareTo(Element o) {
if (value < o.value)
return -1;
if (value > o.value)
return 1;
return 0;
}
}


主运行程序
	// 程序比较丑陋是因为java不支持基本类型的泛型和动态变量名
public static void main(String[] args) {
// The arrays used for multi merge sort
Integer[] a = { 6, 19, 24, 31 };
Integer[] b = { 2, 5, 9, 67 };
Integer[] c = { 8, 20, 76, 389, 399 };
Integer[] d = { 266, 388, 736, 736, 3923 };
Integer[] e = { 38, 234, 1021, 7136, 39342 };

HashMap<Integer, Integer[]> map = new HashMap<Integer, Integer[]>();
map.put(0, a);
map.put(1, b);
map.put(2, c);
map.put(3, d);
map.put(4, e);

int arrSize = map.size();
// The PriorityQueue used for sort
PriorityQueue<Element> pq = new PriorityQueue<Element>(arrSize);

// Put the first element of each array to the PriorityQueue
for (int i = 0; i < arrSize; i++) {
pq.offer(new Element(map.get(i)[0], i, 0));
}

Element tem = null;
int i = 1;
while ((tem = pq.poll()) != null) {
System.out.print(tem.value + "\t");
if (i % 6 == 0)
System.out.println();
i++;
// Put the next element to array if have
if (tem.whichIndex + 1 < map.get(tem.whichArray).length)
pq.offer(new Element( map.get(tem.whichArray)[tem.whichIndex + 1], tem.whichArray, tem.whichIndex + 1));
}
}

运行结果:
2 5 6 8 9 19
20 24 31 38 67 76
234 266 388 389 399 736
736 1021 3923 7136 39342


[size=medium]原理很简单: 先把每个数组的首元素取出来,形成一个堆结构。然后取出堆顶元素(目前的最小值),再将堆顶元素所在数组的后一个元素加入到堆中。如此循环直到所有元素被处理。

这个算法有个可以优化的地方,在从优先队列取出堆顶元素和重新加入元素这两步是可以合并的,没有合并的原因是java的PriorityQueue没有提供相应的接口。

附件是源码。[/size]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值