八大排序(二)-----堆排序

基本思想

1):将带排序的序列构造成一个大顶堆,根据大顶堆的性质,当前堆的根节点(堆顶)就是序列中最大的元素

2):将堆顶元素和最后一个元素交换,然后将剩下的节点重新构造成一个大顶堆;

3):重复步骤2,如此反复,从第一次构建大顶堆开始,每一次构建,我们都能获得一个序列的最大值,然后把它放到大顶堆的尾部。最后,就得到一个有序的序列了

构造堆

在构造有序堆时,我们开始只需要扫描一半的元素(n/2-1 ~ 0)即可,为什么?

因为(n/2-1)~0的节点才有子节点,如图1,n=8,(n/2-1) = 3  即3 2 1 0这个四个节点才有子节点

                  (图1:初始状态)

 

所以代码4~6行for循环的作用就是将3 2 1 0这四个节点从下到上,从右到左的与它自己的子节点比较并调整最终形成大顶堆,过程如下:

 

第一次for循环将节点3和它的子节点7 8的元素进行比较,最大者作为父节点(即元素60作为父节点)

【红色表示交换后的状态】

 

第二次for循环将节点2和它的子节点5 6的元素进行比较,最大者为父节点(元素80作为父节点)

 

第三次for循环将节点1和它的子节点3 4的元素进行比较,最大者为父节点(元素70作为父节点)

第四次for循环将节点0和它的子节点1 2的元素进行比较,最大者为父节点(元素80作为父节点)

(注意这里,元素20和元素80交换后,20所在的节点还有子节点,所以还要再和它的子节点5 6的元素进行比较,这就是28行代码 i = j 的原因)

至此有序堆已经构造好了!如下图:

 

调整堆

下面进行while循环

(1)堆顶元素80和尾40交换后-->调整堆

(2)堆顶元素70和尾30交换后-->调整堆

(3)堆顶元素60尾元素20交换后-->调整堆

(4)其他依次类推,最终已排好序的元素如下:

 

代码实现

public class 堆排序 {
public static void main(String[] args) {
	int[] arr = {1,9,7,5,3,8};
	for(int p = arr.length-1;p>=0;p--) {
		adjestHeap(arr, p,arr.length);
	}
	// 堆顶元素和堆底元素互换,维护大顶堆
	for(int i = arr.length-1;i>0;i--) {
		int temp = arr[i]; 
		arr[i] = arr[0];
		arr[0] = temp;
		// 维护大顶堆
		adjestHeap(arr, 0,i);	
	}
	System.out.print(Arrays.toString(arr));
	
}

public static void  adjestHeap(int[] arr,int parent,int length) {
	int temp = arr[parent];// temp代表父节点的值
	int lChild = 2 * parent + 1;// 左孩子
	while (lChild < length) {
		int rChild = lChild+1;//右孩子
		
		if(rChild < length && arr[lChild] < arr[rChild]) {
			lChild++;
		}// 如果父节点的值大于孩子节点的值,方法结束
		if(temp >= arr[lChild]) {
			break;
		}
		arr[parent] = arr[lChild];
		//将孩子节点的值附给父节点
		parent = lChild;
		lChild = 2 * lChild+1;
	}
	
	arr[parent] = temp;
	

}

             
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值