【算法学习】 堆排序算法

完全二叉树:在一个满二叉树中,在最下层从最右侧起,去掉相邻的若干叶子结点,得到的二叉树称为完全二叉树。

堆其实就是一棵完全二叉树。

大顶堆

堆顶元素(即第一个元素)为最大项,并且二叉树的父结点都大于子结点。

小顶堆

堆顶元素为最小项,并且二叉树的父结点都小于子结点。

堆排序

堆排序就是利用堆进行排序的算法,它的基本思想是,将待排序的序列构成一个大顶堆。此时整个序列的最大值就是堆顶的根结点。将它移走,然后将剩余的n-1个序列重新构造成一个堆,这样就可以得到n个元素中的次大值。如此反复循环就能得到有序序列。

例子 

假设我们要排序的序列是{50,10,90,30,70,40,80,60,20},一共9个数,我们第一步就是构建一个堆,也就是完全二叉树:

第二步,将该堆变为一个大顶堆,也就是说,如果子结点的值大于父结点,那么就将该子结点与父结点交换位置: 

第三步:将最上面的堆顶元素与堆末尾的元素进行交换:

第四步,将除了最后一个元素以外的剩余8个元素再排成一个大顶堆:

再将最上面的堆顶元素与堆末尾的元素进行交换,然后再把剩下的7个元素重新排成大顶堆...重复下去,最终就可以排序成功。

代码实现

import java.util.Arrays;

public class HeapSort {

	public static void main(String[] args) {
		int[] arr = {50,10,90,30,70,40,80,60,20};
		heapsort(arr);
		System.out.println(Arrays.toString(arr));
	}
	
	public static void heapsort(int[] arr) {
		int len = arr.length;
		for(int i=len/2-1; i>=0; i--) { //把arr[]构造成大顶堆
			heapAdjust(arr, i, len);
		}
		//对调,然后再次成为大顶堆
		for(int i=len-1;i>=0;i--) {
			swap(arr, 0, i);
			heapAdjust(arr, 0, i);
		}
	}
	
	/**
	 * 
	 * @param arr  要处理的数组
	 * @param i    父结点下标
	 * @param size 要处理数组部分的长度
	 */
	public static void heapAdjust(int[] arr,int i,int size) { 
		int largest = i; //largest为最大值的下标
		int left = i * 2 + 1; //左孩子
		int right = i* 2 + 2; // 右孩子
		if(left < size && arr[left] > arr[largest]) {
			largest = left;
		}
		if(right < size && arr[right] > arr[largest]) {
			largest = right;
		}
			
		if(largest != i) { 父结点不是最大值
			swap(arr, largest ,i);
			//对子树进行调整
			heapAdjust(arr, largest, size);
		}
		
	}
	
	public static void swap(int[] arr, int a, int b)
	{
		int temp = arr[a];
		arr[a] = arr[b];
		arr[b] = temp;
	}

}

特点

  • 由于它在直接选择排序的基础上利用了比较结果形成。效率提高很大。它完成排序的总比较次数为O(nlog2n)。
  • 堆排序需要两个步骤,一个建堆,而是交换重新建堆。比较复杂,所以一般在小规模的序列中不合适,但对于较大的序列,将表现出优越的性能
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程芝士

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值