排序算法之堆排序

堆排序就是在初始时把要排序的n个数的序列看作是一棵顺序存储的二叉树(一维数组存储二叉树),调整它们的存储序,使之成为一个堆,将堆顶元素输出,得到n个元素中最小(或最大)的元素,这时堆的根节点的数最小(或者最大)。然后对前面(n-1)个元素重新调整使之成为堆,输出堆顶元素,得到n个元素中次小(或次大)的元素。依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。

实现堆排序需解决两个问题:
1. 如何将n个待排序的数建成堆;
2. 输出堆顶元素后,怎样调整剩余n-1个元素,使其成为一个新堆。


步骤1的建堆方法:对初始序列建堆的过程,就是一个反复进行筛选的过程。

1.n 个结点的完全二叉树,则最后一个结点是第n/2个结点的子树。

2.筛选从第n/2个结点为根的子树开始,该子树成为堆。

3.之后向前依次对各结点为根的子树进行筛选,使之成为堆,直到根结点。

步骤2的建堆方法

调整大顶堆的方法:

1.设有n个元素的堆,输出堆顶元素后,剩下n-1个元素。将堆底元素送入堆顶((最后一个元素与堆顶进行交换),堆被破坏,其原因仅是根结点不满足堆的性质。

2.将根结点与左、右子树中较大元素的进行交换。

3.若与左子树交换,如果左子树堆被破坏,即左子树的根结点不满足堆的性质,则重复方法 (2).

4.若与右子树交换,如果右子树堆被破坏,即右子树的根结点不满足堆的性质。则重复方法 (2).

5.继续对不满足堆性质的子树进行上述交换操作,直到叶子结点,堆被建成。

代码:

package com.creditease.menu.sort;

import java.util.Arrays;

public class HeapSort {

	public static void main(String[] args) {
		int[] array = { 1, 8, 5, 2, 8, 4, 9, 2, 3, 7, 0, 6 };
		heapSort(array, array.length);
		System.out.println(Arrays.toString(array));
	}
	/**
	 * 调整array[index]使其成为大顶堆
	 * @param array
	 * @param index
	 * @param length
	 */
	public static void heapAdjust(int[] array, int index, int length){
		int temp = array[index];// 父结点的值,用来和其子结点比较大小
		int child = 2*index+1;// 左子结点的位置
		while(child < length){
			if(child+1 < length && array[child] < array[child+1]){// 如果左子结点小于右子结点,则用较大的右子结点与其父结点进行比较
				child++;
			}
			if(array[index] < array[child]){// 如果较大的子结点大于其父结点
				array[index] = array[child];// 对他们进行交换
				index = child;// 重新设置等待调整的结点的位置
				child = 2*index+1;
			}else{// 如果父结点大于它的左右子结点,则不需要调整,直接退出
				break;
			}
			array[index] = temp;// 当前等待调整的结点放到比其大的孩子结点位置上
		}
	}
	/**
	 * 初始堆进行调整
	 * @param array
	 */
	public static void heapBuild(int[] array){
		for(int i = (array.length-1)/2; i >= 0;i--){// 最后一个有子结点的位置
			heapAdjust(array, i, array.length);
		}
	}
	/**
	 * 堆排序算法
	 * @param array
	 * @param length
	 */
	public static void heapSort(int[] array, int length){
		heapBuild(array);// 初始堆
		for(int i = length-1; i > 0; i--){// 交换堆顶元素与最后一个元素
			int temp = array[i];
			array[i] = array[0];
			array[0] = temp;
			heapAdjust(array, 0, i);// 重新对堆进行调整
		}
	}
}

时间复杂度:

时间复杂度为 T(n) <=  O(n)  + (n - 1)*O(log2(n)),即等于第一次构造最大堆操作 加上  后面n-1次构造堆操作   其实由于n的减小,后面的O(log2(n))中的n也会减小,所以这里用小于等于号 。最后得到的T(n) =O(nlog2(n)).


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值