堆排序(HeapSort)的实现与应用

注:数据结构的堆,与jvm中的堆意义完全不同!栈也是- -

堆排序,顾名思义就是利用数据结构"堆"的特性,进行排序。堆的定义引用维基百科:

heap is a specialized tree-based data structure that satisfies the heap property: If A is a parentnode of B, then the key (the value) of node A is ordered with respect to the key of node B with the same ordering applying across the heap. A heap can be classified further as either a "max heap" or a "min heap".

大意是:堆是“树”状数据结构的一种,满足每个根节点与它的子(叶)节点之间key(value)的值都是一致的,分为“大根堆”与“小根堆”。1991年的计算机先驱奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德(Robert W.Floyd)和威廉姆斯(J.Williams)在1964年共同发明了著名的堆排序算法( Heap Sort ) (同时也是提出堆数据结构)

堆排序使用的树是完全二叉树,若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层从右向左连续缺若干结点(即先满左树)

计算机中堆的实现,一般是用数组(Heaps are usually implemented in an array , wikipedia.org),如果使用链表那么做树的旋转效率太低。假如一个节点的下标为n,那么它的子节点下标为:

2n+1,2n+2  #在以0为起点的数组中
2n,2n+1 #在以1为起点的数组中

    

大根堆的分析:

1.在输入的数组a 上建立树状属性 root leftChild=a[2i+1] rightChild=a[2i+2]

2.进行排序,以满足大根堆的性质 root > leftChile root >rightChild

大根堆的实现:

1.堆排序的核心是递归,类似数学归纳法,

归纳内容(递归内容):对任意root节点为 a[i] 的子树进行root节点最大值的排序,则全树可有序当本层节点进行值交换时候,会影响被交换的子树排序。过程:

if (leftChild>rightChild) 
   largest = leftChild
else
   largest = rightChild 

#找到最大值,与现在的根节点大小比较,如果大于root交换节点值
if (largest > root )
   exchange(root , largest )
#由于交换了值,所以受影响的子树需要重新排序
   heapSortOne( a[] , a[laegestTag])

2.实现递归入口部分:递归入口可以是 a[ length -1 ],但是这样效率很低。由root下标为0的数组a,a[n]的子节点为a[2n+1], 2[2n+2] 可得a[ length-1 ]的父节点为 a[ length-1 -1 ] /2 

for ( fartherNodeTag = (a.length-2)/2  >= 0 ;  fartherNodeTag--)
    heapSortOne(a,fartherNodeTag );
#自底向上的树遍历

由以上很清晰地写出代码如下:

public class HeapSort {

    //自底向上遍历方法
	public void iterateHeap(int[] a){		
		for(int deep=(a.length-2)/2;deep>=0;deep--){
			heapSortOne(a,deep);
		}
	}
	
    //递归方法
	public void heapSortOne(int[] a,int i){
		int leftChild=i;
		int rightChild=i;
		int largestChildTag=i;
		if((2*i+1)<a.length)
			leftChild=a[2*i+1];
		if((2*i+2)<a.length)			
			rightChild=a[2*i+2];
		if(leftChild>rightChild)
			largestChildTag=2*i+1;
		else
			largestChildTag=2*i+2;
		if(compare(a, i, largestChildTag))
			heapSortOne(a, largestChildTag);
	}
	
    //数据交换方法
	private boolean compare(int[] a, int i, int t){
		if(t<a.length && a[t]>a[i]){
			if(a[t]>a[i]){
				int temp=a[t];
				a[t]=a[i];
				a[i]=temp;
			}
			return true;
		}
		return false;
	}
	
	public static void main(String[] args) {
		int[] a = {1,2,3,4,43,4,7,8,3,21,4,56,7,9,0,3534,7,8,9,213,346,67};
		HeapSort hs =new HeapSort();
		hs.iterateHeap(a);
		for(int s : a){
			System.out.print(s + " ");
		}
	}
}

 K小问题

有一个文件共有1E行,每行都是int值,且文件大于内存大小,请写出该文件中前K小个数。

K小问题使用大根堆,先建立长度为K的A[]大根堆,读入一个值Read判断Read<A[0],则继续调用heapSortOne(A , 0),即可维持大根堆。读完文件即可找出K小数。

 

转载于:https://my.oschina.net/lemonfight/blog/854208

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值