堆排序的Java实现

堆排序一种时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn)的原址排序,其实现可以只利用常数级的额外空间。其详细介绍可参考《算法导论》中的介绍。本文主要记录堆排序的Java实现过程。

Heap抽象类

一般有两种常见的堆的实现方式:最大堆和最小堆。其区别在与根节点是比子节点大还是小。若根节点不小于子节点,则为最大堆,若根节点不大于子节点,则为最小堆。这两种堆的实现方式的区别在与建堆的过程,其他的地方基本一致,因此为了提高代码的重复利用率,可以先构造一个抽象类Heap,一些重复的方法可以直接在Heap中实现,而建堆时需要调用的关键函数heapify(int i)可以设置成抽象方法,最后在MaxHeap类和MinHeap类中实现。为了应对多种数据类型的需要,这里实现了泛型的版本。

public abstract class Heap<T extends Comparable<T>> {
	public int heapSize;
	public T[] list;  // 保存元素的数组
	
	public Heap() {
		heapSize = 0;
	}
	
	// 建堆所需要的子函数
	// 根据是最大堆还是最小堆,分别有两种实现方式
	public abstract void heapify(int i);
	
	// 建堆
	public void buildHeap(T[] list) {
		heapSize = list.length;
		this.list = list;
		
		for(int i=(heapSize-1)/2; i>=0; i--) {
			heapify(i);
		}
	}
	
	public int parentIndex(int i) {
		return (i-1)/2;
	}
	
	public int leftChildIndex(int i) {
		return 2*i+1;
	}
	
	public int rightChildIndex(int i) {
		return 2*i+2; 
	}
	
	public String toString() {
		String str = "  ";
		for(int i=0; i<heapSize; i++) {
			str = str + list[i] + "  ";
		}		
		return str;
	}
}

最大堆实现

通过继承Heap类,这里只需要把heapify(int i)方法实现一下就可以了。

public class MaxHeap<T extends Comparable<T>> extends Heap<T>{
	
	public MaxHeap() {
		super();
	}

	@Override
	public void heapify(int i) {
		// TODO Auto-generated method stub
		int left = leftChildIndex(i);
		int right = rightChildIndex(i);
		
		int max = i;
		if(left<heapSize && list[left].compareTo(list[i])>0) {
			max = left;
		}
		if(right<heapSize && list[right].compareTo(list[max])>0) {
			max = right;
		}
		
		if(max != i) {
			T temp = list[i];
			list[i] = list[max];
			list[max] = temp;
			heapify(max);
		}
		
	}
	
	public static void main(String[] args) {
		Heap<Integer> heap = new MaxHeap<>();
		Integer[] nums = {4, 1, 3, 2, 16, 9, 10, 14, 8, 7};
		heap.buildHeap(nums);
		System.out.println(heap);
	}

}

main方法中,加了一个测试用例

4, 1, 3, 2, 16, 9, 10, 14, 8, 7

其测试输出为

 16  14  10  8  7  9  3  2  4  1  

画出这个堆的结构如下

最大堆

最小堆实现

与最大堆类似,其实现代码如下

public class MinHeap<T extends Comparable<T>> extends Heap<T> {
	
	public MinHeap() {
		super();
	}

	@Override
	public void heapify(int i) {
		// TODO Auto-generated method stub
		int left = leftChildIndex(i);
		int right = rightChildIndex(i);
		
		int min = i;
		if(left<heapSize && list[left].compareTo(list[i])<0) {
			min = left;
		}
		if(right<heapSize && list[right].compareTo(list[min])<0) {
			min = right;
		}
		
		if(min != i) {
			T temp = list[i];
			list[i] = list[min];
			list[min] = temp;
			heapify(min);
		}
	}
	
	public static void main(String[] args) {
		Heap<Integer> heap = new MinHeap<>();
		Integer[] nums = {4, 1, 3, 2, 16, 9, 10, 14, 8, 7};
		heap.buildHeap(nums);
		System.out.println(heap);
	}

}

同样,我们用4, 1, 3, 2, 16, 9, 10, 14, 8, 7作为测试用例,得到的结果为

 1  2  3  4  7  9  10  14  8  16

其对应的堆结构为

最小堆

堆排序

接下来,就可以调用堆数据结构实现堆排序了。

public class HeapSort<T extends Comparable<T>> {
	
	/**
	 * 默认从小到大排序
	 * @param nums
	 */
	public void sort(T[] nums) {
		Heap<T> heap = new MaxHeap<>();
		heap.buildHeap(nums);
		
		for(int i=nums.length-1; i>0; i--) {
			T temp = nums[0];
			nums[0] = nums[i];
			nums[i] = temp;
			heap.heapSize--;
			heap.heapify(0);  // 重新调整堆
		}
	}
	
	/***
	 * 降序排序
	 * @param nums
	 */
	public void descendSort(T[] nums) {
		Heap<T> heap = new MinHeap<>();
		heap.buildHeap(nums);
		for(int i=nums.length-1; i>0; i--) {
			T temp = nums[0];
			nums[0] = nums[i];
			nums[i] = temp;
			heap.heapSize--;
			heap.heapify(0);  // 重新调整堆
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Integer[] nums = {4, 1, 3, 2, 16, 9, 10, 14, 8, 7};
		HeapSort<Integer> obj = new HeapSort<>();
		
		// 升序排序
		System.out.println("升序:");
		obj.sort(nums);
		for(int i=0; i<nums.length; i++) {
			System.out.print(nums[i] + "  ");
		}
		System.out.println();
		
		// 降序排序
		System.out.println("降序:");
		obj.descendSort(nums);
		for(int i=0; i<nums.length; i++) {
			System.out.print(nums[i] + "  ");
		}
		System.out.println();
	}

}

4, 1, 3, 2, 16, 9, 10, 14, 8, 7作为测试用例的排序结果为

升序:
1  2  3  4  7  8  9  10  14  16  
降序:
16  14  10  9  8  7  4  3  2  1  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值