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

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

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

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


用到的内部数据结构:
	// 如果用链表存储数据,就不用这么麻烦了,
	// 用数组的话,使用一个内部类保存当前值对应的数组即其在数组中的索引
	// 需要实现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	


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

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

附件是源码。

你可能感兴趣的:(java,数据结构,C++,c,算法)