使用堆求数组第K大的数

在上一篇博文中,O(n)复杂度,求数组中第2大的数 ,ansjsun同学留下一个非常有价值的回复:

ansjsun 写道
大概看了下代码...
这么排啊...其实答案应该是堆排...

第二大是 O(2*logn) = O(n)

 

感谢ansjsun提供的思路,下面是我实现的代码 

 

import java.util.Arrays;


public class MaxHeap {
	private int[] array;
	private int size;
	public MaxHeap(int[] array){
		this.array = Arrays.copyOf(array, array.length);
		this.size = this.array.length;
	}
	//求第K大的数值
	public int kmax(int k){
		if(k<1 || k>size){
			throw new IllegalArgumentException("k must be between 1 and " + size);
		}
		this.buildMaxHeap();
		for(int count=1,i=size-1;i>=1;i--,count++){
			if(k == count){
				break;
			}
			swap(0,i);
			maxHeapify(0,i);
		}
		return array[0];
	}
	
	//建立最大堆
	public void buildMaxHeap(){
		for(int i=parent(size-1);i>=0;i--){
			maxHeapify(i,size);
		}
	}
	
	//排序
	public void sort(){
		this.buildMaxHeap();
		for(int i=size-1;i>=1;i--){
			swap(i,0);
			maxHeapify(0,i);
		}
	}
	//使i节点比左节点和右节点都要大。
	//@param i 节点下标
	//@param size 堆的元素个数
	private void maxHeapify(int i, int size){
		int maxIndex = i;
		int left = left(i);
		int right = right(i);
		if(left<size && array[left]>array[maxIndex]){
			maxIndex = left;
		}
		if(right<size && array[right]>array[maxIndex]){
			maxIndex = right;
		}
		if(maxIndex != i){
			swap(i,maxIndex);
			//子节点发生了变化,需要重新计算最大值
			maxHeapify(maxIndex,size);
		}
	}
	
	private void swap(int i,int j){
		int tmp  = array[i];
		array[i] = array[j];
		array[j] = tmp;
	}
	
	private int left(int i){
		return (i<<1) + 1;
	}
	
	private int right(int i){
		return (i<<1) + 2;
	}
	private int parent(int i){
		return (i-1)>>1;
	}
	
	public void print(){
		int i=0;
		for(int width=1;;width*=2){
			for(int count=0;count<width;count++){
				System.out.print(array[i]+ " ");
				i++;
				if(i==size){
					System.out.println();
					return;
				}
			}
			System.out.println();
		}
	}
	
	public static void main(String[] args){
		int[] a = new int[]{1,2,3,4,5};
		MaxHeap heap = new MaxHeap(a);
		//第二大的数
		System.out.println(heap.kmax(2));
	}
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值