堆排序

堆排序的java实现代码以及详细的注释(不喜勿喷,嘿嘿)

(1)时间复杂度为O(n*log2(n))的建堆方式(自顶向下)。

        这种建堆方式采用了自上而下的方法。从根结点开始,然后一个一个的把结点插入堆中。当把一个新的结点插入堆中时,需要对结点进行调整,以保证插入结点后的堆依然是大根堆。如图1所示,是采用自顶向下的方法建立的大根堆。假设总共有n个结点

 

                                                                                                图1
     其中h = log2(n+1)-1,第k层结点个数为2k个(当然最后一层结点个数可能小于2h)。第k层的一个结点插入之后需要进行的比较(移动)次数为k。于是总的比较(移动)次数为∑k*2k(k = 0,1,2,...,h)。可以求得∑k*2k(k = 0,1,2,...,h)=(log2(n+1)-2)*(n+1)+2 = O(n*log2n)
     
     (2)时间复杂度为O(n)的建堆方式(自底向上)。
      上面的自顶向下的建堆方式的时间复杂度为O(n*log2n)。下面我将描述一下采用自底向上的建堆(这里假设为大根堆)方式,这种建堆方式的时间复杂度为O(n)。如图2所示。

                                                                                          图2

    首先,我们把第0层的结点排好。然后,加入第一层的结点,对第一层的每个结点来说,将要和下面的两个结点比较,找出最大的结点,然后放置在每棵子树的根部。对于第k(0<=k<=log2n)层的每一个结点,其将要进行的比较次数是2*k。第k层的结点数为(n+1)/(2(k+1))。则总的比较次数为∑2*k*(n+1)/(2(k+1))=(n+1)*∑k/2k=2(n+1) = O(n)


package com.dlut.sort;
import org.junit.Test;

public class HeapSort {
	private int[] aa = {9,0,1,3,2,5,4,7,6,8,10,12,11,13,14,17,16,15,34};
	@Test
	public void heapSort()
	{
		buildHeap(aa);
		
		/*
		 *自底向上建堆
		 * 忍不住给个注释:aa[0]存放的是最大值,每一次循环都会找出剩余未排序的元素的最大值,
		 * aa[0]与尾部元素交换,交换之后调用下虑函数,使剩余的仍然是最大堆。
		 */
		for (int i = aa.length-1; i > 0; i--) {
			swap(aa,0,i);
			percoDown(aa, 0,i);
		}
		for (int i = 0; i < aa.length; i++) {
			System.out.println(aa[i]);
		}
	}
	
	public void swap(int[] arr, int m,int n)
	{
		int temp = arr[m]^arr[n];
		arr[m] = temp^arr[m];
		arr[n]=temp^arr[m];
	}
	/**
	 * 建堆函数
	 * 建堆有技巧:从下往上建,优点是,对任何一个节点可知它的左右子树都是堆,只需该节点下虑即可。
	 * 从上往下建,可以想一下,每一个结点都要找出它的左右子树中的最大值,很麻烦的说。。。
	 * arr.length/2之后的元素一定是叶节点。
	 * @param arr
	 */
	public void buildHeap(int[] arr)
	{
		for(int i = arr.length/2; i>=0 ;i--)
			percoDown(arr, i,arr.length);
	}
	/**
	 * 下虑函数:小于左右儿子的结点下虑
	 * 看代码理解思想:比较左右儿子大小,谁大指向谁,然后较大的儿子与父节点比较,如果发生交换,则较大的儿子下虑。
	 * @param arr
	 * @param location
	 * @param arrSize
	 */
	public void percoDown(int[] arr,int location,int arrSize)
	{
		int temp = 0 ,leftchild =0 ;
		for (temp = arr[location];(2*location +1) < arrSize ;location = leftchild) {
			leftchild = 2*location +1;
			if (leftchild != arrSize -1 && arr[leftchild] < arr[leftchild+1]) {
				leftchild++; 
			}
			if (temp < arr[leftchild]) {
				arr[location] =arr[leftchild];
			}
			else
				break;
		}
		arr[location] = temp;
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值