堆排序

目录

 

什么是堆?

堆排序思路:以小根堆为例

代码实现

堆排序的优缺点


什么是堆?

堆是一类特殊的数据结构,堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:

1.堆中某个节点的值总是不大于或不小于其父节点的值;

2.堆总是一棵完全二叉树。

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。堆排序是指利用堆这种数据结构所设计的一种排序算法。

根据完全二叉树的性质,如果对一颗有n个节点的完全二叉树(其深度为 log2n(向下取整)+1)的节点按层序编号,对于任意节点i有:

       如果i=1,则节点i是二叉树的根节点,无双亲;如果i>1,则其双亲节点是i/2(向下取整)
       如果2i>n,则节点i无左孩子;否则其左孩子就是2i  
       如果2i+1>n,则节点i无有右孩子;否则其右孩子就是2i+1
根据完全二叉树的性质,完全二叉树可以由数组存储数据。

 

堆排序思路:以小根堆为例

  1. 先初始化堆,构建一颗完全二叉树(节点为n)
  2. 根据堆的性质,父节点要大于或等于左孩子以及右孩子的节点,从倒数第二层第一个节点(即倒数第一个非叶子节点)开始,比较左孩子以及右孩子的值,假设左孩子的值大于右孩子的值,那就以左孩子的值以父节点的值比较,假设左孩子的值大于父节点的值,则交换父孩子以及左孩子的值,假设右孩子值大于左孩子的,则以右孩子的值与父节点比较,依次进行对比,只到遍历到根节点为止。
  3. 此时,根节点为整棵树最大的值,然后将根节点的值与最后一个叶子节点(即n节点)的值进行交换,然后重新2,然后将根节点的值与(n-1)节点的值进行交换,依次类推,直到根节点。

以数据3,2,5,7,9,4为例进行堆排序:

          1.构建完全二叉树

                      

2.以倒数第一个非叶子节点开始比较,倒数第一个非叶子节点为2,它的左孩子的值为7,右孩子的值为9,9大于7,则用9以2进行比较,2小于9,则交换父节点以及它右孩子的值。然后倒数第二个非叶子节点为5,它只有左孩子,左孩子的值为4,小于父节点,不交换。依次从树的低往上进行比较。

                        

          3.根节点为3,它的左孩子为9,右孩子为5,左孩子大于右孩子的值,则左孩子以父节点的值进行比较,左孩子大,交换连个节点的元素。继续遍历,只至二叉树具有堆的性质。

                                                   

         4.此时根节点为树最大的节点,将根节点值与树最后一个元素进行交换。

                                           

         5.重复进行2,3,4,只至排序完成

                          

                                                     

                           

                                                     

代码实现

        

public static void dump(int arr[]) {
		// 初始化堆
		for (int i = arr.length / 2 - 1; i >= 0; i--) {
			// 从第一个非叶子节点开始
			adjust(arr, i, arr.length);
		}
		// 将堆排序
		for (int i = arr.length - 1; i > 0; i--) {
			int temp = arr[0];
			arr[0] = arr[i];
			arr[i] = temp;
			// 筛选 arr[0]结点,得到i-1个结点的堆
			adjust(arr, 0, i);
		}
	}

	public static void adjust(int arr[], int parent, int size) {
		// 获取当前节点值
		int temp = arr[parent];
		// 获取左孩子
		int child = parent * 2 + 1;
		while (child < size) {
			// 判断是否有右孩子,右孩子的值是不是大于左孩子的值
			if (child + 1 < size && arr[child] < arr[child + 1]) {
				child++;
			}
			// 父节点大于他的孩子节点,不交换
			if (temp >= arr[child]) {
				break;
			}
			// 进行交换,比较新的孩子节点是否大于子孙节点
			arr[parent] = arr[child];
			parent = child;
			child = 2 * child + 1;
		}
		arr[parent] = temp;
	}

 

堆排序的优缺点

  1. 堆排序在时间方面为基于比较的排序算法效率的峰值(时间复杂度为O(nlogn))
  2. 空间方面,只需要O(1)的辅助空间了,不用辅助数组
  3. 堆排序效率相对稳定,不像快排在最坏情况下时间复杂度会变成O(n^2)),所以无论待排序序列是否有序,堆排序的效率都是O(nlogn)不变(注意这里的稳定特指平均时间复杂度=最坏时间复杂度,不是那个“稳定”,因为堆排序本身是不稳定的)
  4. 缺点在于堆维护的问题,每次数据更新,都要将堆重新维护。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值