算法分析:

堆排序和归并排序一样,实践时间复杂度是O(nlgn),不同于归并排序的是,堆排序是一种原址排序。本文介绍最大堆。

代码中关键操作:

maxHepify:时间复杂度是O(lgn),是维护堆性质的关键。

buildMaxHeap:建立最大堆,时间复杂度是O(n);

heapSort:通过调用exactMax,按顺序得到一个排序的数组,时间复杂度是O(nlgn);

insert:插入新元素,通过调用increseKey私有方法操作,时间复杂度是O(lgn);

当然,还有max(),exactMax()方法。更加具体分析请参见《算法导论》,下面是我的实现代码和测试代码:


import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Comparator;

// 逻辑上堆是从index = 1开始,实际上从index = 0开始,
// 故各方法中常见index - 1;
public class MaxHeap<T extends Comparable<T>> {
	Object[] array;
	private final int DEFAULT_CAPACITY = 100;
	private final float LOAD = 0.75F;
	private int size = 0;
	private Comparator<T> comparator;

	// 构建一个空堆
	public MaxHeap() {
		array = new Object[DEFAULT_CAPACITY];
	}

	// 构建一个堆,包含array中的数据,array初始容量是array长度两倍
	public MaxHeap(T[] array) {
		this(array, null);
	}

	// 构建一个堆,包含array中的数据,array初始容量是array长度两倍,并按提供的比较器大小比较
	public MaxHeap(T[] array, Comparator<T> comparator) {
		this.array = Arrays.copyOfRange(array, 0, array.length * 2);
		size = array.length;
		this.comparator = comparator;
		buildMaxHeap();
	}

	// 代理堆中对象的比较方法
	@SuppressWarnings("unchecked")
	private int compare(Object o1, Object o2) {
		if (comparator == null)
			return ((T) o1).compareTo((T) o2);
		else
			return comparator.compare((T) o1, (T) o2);
	}

	// 使得初始化堆满足最大堆性质
	private void buildMaxHeap() {
		for (int i = size / 2; i >= 1; i--)
			maxHeapify(i);
	}

	// 假设i+1, i+2...已经满足最大堆性质,执行此方法后,
	// 使得i, i+1,i+2.....满足最大堆性质
	private void maxHeapify(int i) {
		int l = left(i);
		int r = right(i);
		int largest;
		if (l <= size && compare(array[l - 1], array[i - 1]) > 0)
			largest = l;
		else
			largest = i;
		if (r <= size && compare(array[r - 1], array[largest - 1]) > 0)
			largest = r;
		if (largest != i) {
			swap(i, largest);
			maxHeapify(largest);
		}
	}
	// 交换i1,i2处的值
	private void swap(int i1, int i2) {
		Object temp = array[i1 - 1];
		array[i1 - 1] = array[i2 - 1];
		array[i2 - 1] = temp;
	}

	// 返回左孩子位置
	private int left(int parent) {
		return 2 * parent;
	}

	// 返回右孩子位置
	private int right(int parent) {
		return 2 * parent + 1;
	}

	// 返回父节点位置
	private int parent(int child) {
		return child / 2;
	}

	// 返回堆中最大值
	@SuppressWarnings("unchecked")
	public T max() {
		return (T)array[0];
	}

	// 返回并删除堆中最大值
	@SuppressWarnings("unchecked")
	public T exactMax() {
		if(size < 1)
			throw new IndexOutOfBoundsException("堆中没有元素");
		T max = (T)array[0];
		array[0] = array[size - 1];
		size = size - 1;
		maxHeapify(1);
		return max;
	}

	// 插入一个值,如果堆已达到负载,将堆容量扩大一倍
	public void insert(T obj) {
		array[size] = obj;
		size = size + 1;
		if((float)size / array.length >= LOAD) {
			array = Arrays.copyOfRange(array, 0, array.length * 2);
		}
		increseKey(size, obj);	
	}

	// 按顺序返回堆中元素的数组,将堆变成空堆
	public T[] heapSort() {
		if(size == 0)
			return null;
		else {
			@SuppressWarnings("unchecked")
			T[] result = (T[])Array.newInstance(array[0].getClass(), size);
			int len = size;
			for(int i = 0; i < len; i++)
				result[i] = exactMax();
			return result;
		}
	}

	// 判断堆是否是空堆
	public boolean empty() {
		return size == 0;
	}
	// 增加堆中指定index处的数据
	private void increseKey(int i, T key) {
		if(compare(array[i - 1], key) > 0)
			throw new UnsupportedOperationException("新值不能比原值小");
		array[i - 1] = key;
		while(i > 1 && compare(array[parent(i) - 1], array[i - 1]) < 0) {
			swap(parent(i), i);
			i = parent(i);
		}
	}

}

测试代码(其中涉及到的SortComparble和Point类,请参见我的上一篇博客:):

import java.util.Arrays;

import NearestPoints.Point;
import NearestPoints.PointGenerator;
import NearestPoints.PointYComparaotr;
import NearestPoints.SortComparable;
// SortComparble 已被确认正确
public class TestMaxHeap {
	private static final int SIZE = 100;
	public static void main(String[] args) {
		// 生成点数组
		Point[] points = new Point[SIZE];
		for(int i = 0; i < points.length; i++)
			points[i] = new PointGenerator(1000).next();
		// 建立默认堆,并得到堆排序的数组heap1Sort
		MaxHeap<Point> heap1 = new MaxHeap<>();
		for(int i = 0; i < points.length; i++)
			heap1.insert(points[i]);
		Point[] heap1Sort = heap1.heapSort();
		// 调用SortComparable,将points从小到大按默认比较方法排序
		SortComparable.sort(points);
		// 逐个比较SortComparble排序和MaxHeap排序结果,有不一致输出 “error”
		for(int i = 0; i < points.length; i++)
			if(!points[i].equals(heap1Sort[heap1Sort.length - i - 1]))
				System.out.println("error" + i + points[i] + heap1Sort[heap1Sort.length - i - 1]);
		
		// 建立有比较器的堆,并得到堆排序的数组heap2Sort
		MaxHeap<Point> heap2 = new MaxHeap<>(points, new PointYComparaotr());
		Point[] heap2Sort = heap2.heapSort();
		// 逐个比较SortComparble排序和MaxHeap排序结果,有不一致输出 “error”
		SortComparable.sort(points, new PointYComparaotr());
		for(int i = 0; i < points.length; i++)
			if(!points[i].equals(heap2Sort[heap2Sort.length - i - 1]))
				System.out.println("error" + i + points[i] + heap2Sort[heap2Sort.length - i - 1]);
	}

}