堆排序算法

堆是一种完全二叉树,且具有以下性质:

        大顶堆:每个节点的值都大于或者等于其左右孩子节点的值;

        小顶堆:每个节点的值都小于或者等于其左右孩子节点的值。

堆排序是利用堆来设计的一种排序算法,其最好、最坏和平均时间复杂度均为O(nlogn)。该排序算法是一种选择排序算法,不稳定。

堆排序的基本思路:

1)首先建堆,升序排序选择大顶堆,降序排序选择小顶堆;

2)将堆顶元素与当前堆的最后一个元素进行交换,将最大(最小)元素沉到数组末尾,相当于从堆中删除当前最大(最小元素)。

3)重新调整当前堆(删除最大或者最小元素后)的结构。

4)反复执行交换+调整的步骤,直到整个序列有序。

 

public class HeapSort {

	public static void main(String[] args) {
		int[ ] nums = new int[ ]{
				-2, 1, -3, 4, -1, 2, 1, -5, 4	
		};
		//创建最大堆
		int length = nums.length;
		for( int i = length / 2 - 1; i >= 0; i-- ){
			//从最后一个非叶子节点开始,将以i为根节点的完全二叉树调整为最大堆
			adjHeap( nums, i, length );
		}
		
		//交换+调整最大堆
		for( int i = length - 1; i > 0; i-- ){
			//交换
			swap( nums, 0, i );
			//调整
			adjHeap( nums, 0, i );
		}
		
		//输出
		System.out.println( Arrays.toString( nums ) );
	}
	
	//将以i为根节点的完全二叉树调整为最大堆
	public static void adjHeap( int[ ] nums, int i, int length ){
		//将根节点的值暂时存储起来
		int temp = nums[ i ];
		int parent, child;
		
		for( parent = i; parent * 2 + 1 < length; parent = child ){
			child = parent * 2 + 1;  //左孩子
			//如果存在右孩子,且右孩子的值更大,child指向右孩子
			if( child + 1 < length && nums[ child + 1 ] > nums[ child ] ){
				child++;
			}
			//如果较大的孩子节点比父节点更大,需要交换节点的值,否则,就找到根节点的位置
			if( temp < nums[ child ] ){
				nums[ parent ] = nums[ child ];
			}
			else{
				break;
			}
		}
		//找到根节点i的位置
		nums[ parent ] = temp;
	}
	
	//交换数组中两个数的值
	public static void swap( int[ ] nums, int a, int b ){
		int temp = nums[ a ];
		nums[ a ] = nums[ b ];
		nums[ b ] = temp;
	}

}

在实际中,可以利用优先队列来设计最大堆和最小堆。优先队列默认从小到大排序,即最小堆。

最大堆:

PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>( ( a, b ) -> b - a );

最小堆:

PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>( ( a, b ) -> a - b );

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值