堆排序(很重要!!!!!!)

其实完全二叉树只是人们脑子里抽象出来的一种数据结构,实际情况下,我们是利用数组+一个限定规则来实现二叉树的结构的。

限定规则是:下标为i的数组元素是下标为2i+1与下标为2i+2的父节点,且下标为i的数组元素的父节点的数组下标为(i-1)/2。

构建大顶堆的思路:给我一个数组arr,这个数组依次把i位置上的数加进来,让它0~i位置上的数形成大顶堆。(大致过程就是:新加入的数字与其父节点的大小进行比较,如果大于其父节点则将它与其父节点进行交换,若其父节点还有父节点,则再去与其父节点的父节点进行比较,以此类推;如果新加入的数字小于等于其父节点的值,则不做交换。)故i从0开始,依次i++,直到 i=arr.length-1。

建立大顶堆的时间复杂度:
把第i个数插入到0~i-1的数中建立大顶堆,因为前面的0到i-1个节点已经形成一个完全二叉树了,它的高度就是我的调整代价是log(i-1),同理,加入第i+1个节点建立大顶堆的调整代价就是logi。那么如果一共有N个节点,你的调整代价就是log1+log2+log3+…+log(N-1)=O(N)。

堆排序的思路:

1)先让这个数组整体变成一个大顶堆(变成大顶堆的数组并不一定会有序),然后把最后一个位置的数与堆顶位置的数做交换,堆顶位置的数一开始是数组的最大值,换完之后最大值就来到了数组最后的位置,此时让堆大小heapSize减1,最大值就永远不动了。

2)在剩下的范围中,从0开始做heapify的下沉操作重新调整成大顶堆。然后把调整好的堆顶位置的数再与现在的最后一个位置的数交换,此时,倒数第二个位置上的数就是第二大的数了。
3)每次搞定一个末尾的数,再让heapSize减1,以此类推,减完之后,整个数组就是有序的了。

public class Test{
	public static void heapSort(int [] arr) {
		if(arr==null||arr.length<2) {
			return;
		}
		for(int i=0;i<arr.length;i++) {
			heapInsert(arr,i);//依次将数组中i位置上的数加进来,让它0~i之间的数形成大顶堆
		}
		int heapSize=arr.length;//堆大小heapSize一开始等于数组的全部
		swap(arr,0,--heapSize);//最后一个位置上的数与第一个位置上的数(堆顶元素)交换,堆大小减1,即最后一个位置上的数不动了
		while(heapSize>0) {
			heapify(arr,0,heapSize);//从0位置开始,将当前形成的堆继续调整为一个大顶堆
			swap(arr,0,--heapSize);//最后一个位置上的数与第一个位置上的数(堆顶元素)交换,堆大小减1,即最后一个位置上的数不动了
		}
	}
	
	//建立大顶堆的过程
	public static void heapInsert(int[] arr,int index) {
		while(arr[index] > arr[(index-1)/2]) {//当前index位置上的数若比其父结点上的数大,则交换他俩的位置
			swap(arr,index,(index-1)/2);
			index=(index-1)/2;//然后index来到了它的父节点位置,继续上面的while
		}
	}
	//若有一个节点的值变小了,则需要往下沉(与其左右孩子中较大的数进行交换位置的)的操作
	public static void heapify(int[] arr,int index,int heapSize) {
		int left=index*2+1;//左孩子下标
		while(left<heapSize) {//未越界,即该节点并非叶子节点,存在左孩子
			//该节点有右孩子,让largest作为左右孩子较大值的下标
			int largest=(left+1 < heapSize) && arr[left+1] > arr[left] ? left+1 : left;
			//让largest成为该节点与该节点左右孩子中较大值的下标
			largest=arr[largest] > arr[index] ? largest : index;
			if(largest==index) {
				break;
			}
			swap(arr,largest,index);//largest!=index
			index=largest;//该节点下标变成了较大孩子的下标
			left=index*2+1;//继续往下走,重复上面的while
		}
	}
	
	public static void swap(int[] arr,int i,int j) {
		int temp=arr[i];
		arr[i]=arr[j];	
		arr[j]=temp;
	}
	public static void main(String[] args) {
		int[] arr= {6,3,4,3,1,3,8,5};
		heapSort(arr);
		for(int i:arr) {
			System.out.print(i+" ");
		}
	}
}

输出:1 3 3 3 4 5 6 8

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值