简单排序算法实现——堆排序

本文详细介绍了堆排序算法的基本原理和实现过程,包括最大堆调整、创建最大堆及堆排序操作等核心步骤,并给出了完整的Java代码实现。

堆排序 (Heap Sort) 是利用了数据结构:完全二叉树来进行排序的算法。其基本原理先要将完全二叉树以数组的形式实现出来。再者,用于堆排序的完全二叉树必须满足最大堆(Max Heap) 的性质,即任意一个非叶子节点上的值都应该比其左孩子和右孩子的值小,满足该性质的即称为最大堆。

先阐述在数组上实现完全二叉树的原理:

对于数组下标从0开始的java语言,对于给定的节点下标 i ,其父节点下标为 (i-1)/2, 左孩子节点下标为 2*i+1, 右孩子的节点下标为 2*(i+1).

另外,一个重要的结论是,最后一个非叶子节点的下标是a.length/2-1, 从a.length/2开始后面的下标对应的都是叶子节点,没有孩子。


堆排序的实现需要三个操作。

第一个是最大堆调整操作 (MAX_HEAPIFY) , 接收参数 a[i], i 将以 i 为根节点的子树做调整,使得子节点永远小于父节点,从而满足最大堆性质。

第二个操作是创建最大堆操作 (BUILD_MAX_HEAP),将待排序数组中的元素排列成最大堆的数组实现。调用时,从最后一个非叶子节点的下标a.length/2-1开始向前遍历使用最大堆调整操作。

第三个操作是堆排序操作 (HeapSortOnMaxHeap),每次移除整个堆的根节点 (即当前的最大元素),然后进行堆调整的递归运算。

为了实现原地排序,加入指标heapSize,与a.length区别开来,在堆排序操作中,移除最大元素的操作实现为将第一个元素交换到数组的最后,然后heapSize减一,表明该元素已经不在堆中了。


下面给出全部的java代码实现,其中加了一个公共类的HeapSort作为驱动,依次调用创建最大堆操作和堆排序操作,同时加入了计算父亲/孩子节点对应下标的辅助方法。

public class HeapSort{
	private static int heapSize;
	
	
	private static int indexOfLeft(int root){
		return (2*root+1); 
	}
	
	private static int indexOfRight(int root){
		return 2*(root+1);
	}
	
	private static int indexOfParent(int root){
		return (root-1)/2;
	}
	
	//This method will examine node at position i and its two childs.
	//If i is smaller than one of its child, it will adjust it to maintain it as 
	//a max heap
	private static <AnyType extends Comparable<? super AnyType>>
	void MAX_HEAPIFY(AnyType[] a, int i){
		int l=indexOfLeft(i);
		int r=indexOfRight(i);
		int indexOfMax;
		
		//Condition l,r<=heapSize ensures that operation on leaf nodes will be tolerated.
		if(l<=heapSize-1&&a[l].compareTo(a[i])>0) indexOfMax=l;
		else indexOfMax=i; //If max==a[i], no operation at last;
		
		if(r<=heapSize-1&&a[r].compareTo(a[indexOfMax])>0)
			indexOfMax=r;
		
		if(indexOfMax!=i){
			AnyType temp=a[i];
			a[i]=a[indexOfMax];
			a[indexOfMax]=temp;
			
			MAX_HEAPIFY(a, indexOfMax);	
		}
		
	}
	
	private static <AnyType extends Comparable<? super AnyType>>
	void BUILD_MAX_HEAP(AnyType[] a){
		heapSize=a.length;
		for(int i=a.length/2-1;i>=0;i--){
			MAX_HEAPIFY(a,i);
		}
	}
	
	private static <AnyType extends Comparable<? super AnyType>>
	void HeapSortOnMaxHeap(AnyType[] a){
		AnyType temp;
		for(int i=a.length-1;i>=1;i--){
			temp=a[0];
			a[0]=a[i];
			a[i]=temp;
			
			heapSize--;
			
			MAX_HEAPIFY(a,0);
		}
	}
	
	public static <AnyType extends Comparable<? super AnyType>>
	void HeapSort(AnyType[] a){
		BUILD_MAX_HEAP(a);
		HeapSortOnMaxHeap(a);
		
	}
	
	public static void main(String[] args){
		System.out.println("Heap Sort:");
		
		Integer[] elements={3,4,1,8,10,2,0,6,5};
		
		System.out.print("Original elements: ");
		for(int i=0;i<elements.length;i++) System.out.print(elements[i]+" ");
		System.out.println();
		
		HeapSort(elements);
		
		System.out.print("After sorting: ");
		for(int i=0;i<elements.length;i++) System.out.print(elements[i]+" ");
		System.out.println();
	}

}


堆排序的平均时间复杂度为O(nlogn), 该复杂度同时也为最优时间复杂度。


附图一张:


至今基本排序算法的实现练习暂时告一段落,这些排序算法的一些高级优化或特性,以及其他高级排序算法,留待以后再做研究。

接下来开始一些基本数据结构的实现练习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值