java最小堆实现优先权队列和求最大的n个数问题

堆在实现优先权队列和求最大最小的n个数问题上,有着莫大的优势!

对于最大堆和最小堆的定义此处不再赘述,课参考网上文章:http://blog.csdn.net/genios/article/details/8157031

本文主要是对最小堆进行实现和应用,仅供新手参考。

优先权队列

优先权队列是一种非常有用的数据结构,操作系统的进程调度就有优先权队列的应用,如果用最小值表示最高的优先权,则使用最小堆,否则使用最大堆。

top-N值为问题:

对于求最大的n个数,可以用最小堆来实现,思路是:将n个数构建成一个最小堆,如果剩下的数有大于堆顶元素的值,则替换掉堆顶元素,再调整为最小堆,直到所有数字遍历完。

贴上源码:

关键类:

package com.algorithms;

/**
 * 最小堆,用数组实现,解决top-N问题
 * @author "zhshl"
 * @date	2014-10-22
 * @param <T>
 */

public class Min_Heap {

	private int heap[];
	private int maxSize; ////最多可容纳数目
	private int n;///元素数目

	/**
	 * @param num 堆的大小
	 */
	public Min_Heap(int num){
		n=0;
		maxSize=num;
		heap=new int[maxSize];
	}

	/*
	*//**
	 * 初始堆是一颗任意次序的完全二叉树,从(n-2)/2处开始向下调整
	 * @param heap
	 * @param n
	 *//*
	public void createHeap(int[] heap2,int n){

		heap=heap2;

		for(int i=(n-2)/2;i>=0;i--){
			///从(n-2)/2处开始向下调整
			adjustDown(i,n-1);
		}
	}*/

	/**
	 * 元素入堆
	 * @param v
	 */
	public void append(int v){
		if(isFull()){
			System.out.println("heap is full ,can't append elements !");
			return ;
		}
		////元素插在末尾
		heap[n]=v;
		n++;
		///向上调整
		adjustUp(n-1);

	}

	/**
	 * 取出堆顶元素
	 * @return
	 */
	public int serve(){
		if(isEmpty()){
			System.out.println("heap is empty!");
			return Integer.MIN_VALUE;
		}

		int temp=heap[0];
		////用最后一个元素取代第一个元素
		heap[0]=heap[n-1];
		n--;
		//向下调整
		adjustDown(0, n-1);

		return temp;
	}	

	/**
	 * 求最大的n个数据
	 * @param data
	 * @param n
	 * @return null if n is bigger than the heap size, otherwise
	 */
	public int[] getTopN(int []data,int n){
		heap=new int[n];
		maxSize=n;
		this.n=0;

		///构建初始堆
		for(int i=0;i<n;i++){
			append(data[i]);
		}

		for(int i=n;i<data.length;i++){
			////如果比堆顶元素大,则替换堆顶元素,并调整
			if(data[i]>heap[0]){
				heap[0]=data[i];
				adjustDown(0, n-1);
			}
		}

		return heap;
	}

	/**
	 * 对元素i进行向下调整,用于删除元素时调整
	 * @param i
	 * @param j
	 */
	private void adjustDown(int i, int j) {
		// TODO Auto-generated method stub
		int child=2*i+1;
		int temp=heap[i];///记录待调整的节点的值
		while(child<j){
			////在范围内进行遍历调整

			if(heap[child]> heap[child+1]){
				///如果左孩子比右孩子大, 则指向较小的右孩子
				child++;
			}

			if(heap[child]>temp){
				///如果较小的孩子都比自己大,则退出
				break;
			}

			heap[(child-1)/2]=heap[child];
			child=child*2+1;
		}
		////循环结束,child指向最终位置的节点的左孩子
		heap[(child-1)/2]=temp;

	}

	/**
	 * 将i处的元素向上调整为堆,用于插入时候
	 * @param i
	 */
	private void adjustUp(int i){
		int temp=heap[i];
		while(i>0&&heap[(i-1)/2]> temp){
			///当父节点的值比temp大的时候,交换值
			heap[i]=heap[(i-1)/2];
			i=(i-1)/2;
		}
		heap[i]=temp;
	}

	/**
	 * 堆是否满了
	 * @return
	 */
	public boolean isFull(){
		return n>=maxSize;
	}

	/**
	 * 是否为空堆
	 * @return
	 */
	public boolean isEmpty(){
		return 0==n;
	}
}

测试类:

package com.algorithm.test;

import com.algorithms.Min_Heap;

/**
 * 最小堆测试类
 * @author "zhshl"
 * @date	2014-10-22
 *
 */
public class Min_Heap_Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Min_Heap heap=new Min_Heap(10);
		heap.append(2);
		heap.append(2);
		heap.append(13);
		heap.append(21);
		heap.append(2);
		heap.append(2);
		heap.append(53);
		heap.append(6);

		int temp;
		while(!heap.isEmpty()){
			temp=heap.serve();
			System.out.println(temp);
		}

		System.out.println("\n\n 求top-N问题:");
		int data[]={4,51,52,12,123,52,7643,234,123,33,44,2};

		data=heap.getTopN(data, 5);
		for(int i:data){
			System.out.println(i);
		}
	}

}
时间: 2024-10-07 01:04:54

java最小堆实现优先权队列和求最大的n个数问题的相关文章

初学算法-基于最小堆的优先级队列C++实现

笔者近日实现了最小堆类及其派生的优先级队列,特将代码奉上,不足之处还请指出! 在实现优先级队列时,笔者表示萌萌哒没有用过template写派生类,结果写完了出现error: *** was not decleared in this scope..后来各种补上this->才完事,在CSDN(笔者的帖子地址? http://bbs.csdn.net/topics/391806995)上提问后才知道是模板参数依赖,笔者表示涨姿势了.. /**  * The Minimum Heap Class an

Java最小堆解决TopK问题

TopK问题是指从大量数据(源数据)中获取最大(或最小)的K个数据. TopK问题是个很常见的问题:例如学校要从全校学生中找到成绩最高的500名学生,再例如某搜索引擎要统计每天的100条搜索次数最多的关键词. 对于这个问题,解决方法有很多: 方法一:对源数据中所有数据进行排序,取出前K个数据,就是TopK. 但是当数据量很大时,只需要k个最大的数,整体排序很耗时,效率不高. 方法二:维护一个K长度的数组a[],先读取源数据中的前K个放入数组,对该数组进行升序排序,再依次读取源数据第K个以后的数据

java实现最小堆

1.堆:通常通过二叉堆,实为二叉树的一种,分为最小堆和最大堆,具有以下性质: 任意节点小于它的所有后裔,最小元在堆的根上. 堆总是一棵完全树 将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆. 2.最小堆实现: 插入: 1)  将新插入的元素,放置到队列的尾部. 2)  若该元素小于其父节点,两个元素互换.(上移操作) 3)  迭代,直至该元素没有父节点或小于其父节点. 删除: 1)  移掉顶部的节点. 2)  将队末的元素放置到顶部. 3)  该节点与其子节点中较小的那个比

Google 面试题:Java实现用最大堆和最小堆查找中位数 Find median with min heap and max heap in Java

Google面试题 股市上一个股票的价格从开市开始是不停的变化的,需要开发一个系统,给定一个股票,它能实时显示从开市到当前时间的这个股票的价格的中位数(中值). SOLUTION 1: 1.维持两个heap,一个是最小堆,一个是最大堆. 2.一直使maxHeap的size大于minHeap. 3. 当两边size相同时,比较新插入的value,如果它大于minHeap的最大值,把它插入到minHeap.并且把minHeap的最小值移动到maxHeap. ...具体看代码 1 /*********

最小堆和最大堆的JAVA实现

/** * 文件名:BinaryHeap.java * 时间:2014年11月3日下午7:15:34 * 作者:修维康 */ package chapter6; import java.util.*; /** * 类名:BinaryHeap 说明:建立一个最小堆 */ class MinHeap<AnyType extends Comparable<? super AnyType>> { private int currentSize; private static final i

《徐徐道来话Java》:PriorityQueue和最小堆

在讲解PriorityQueue之前,需要先熟悉一个有序数据结构:最小堆. 最小堆是一种经过排序的完全二叉树,其中任一非终端节点数值均不大于其左孩子和右孩子节点的值. 可以得出结论,如果一棵二叉树满足最小堆的要求,那么,堆顶(根节点)也就是整个序列的最小元素. 最小堆的例子如下图所示: 可以注意到,20的两个子节点31.21,和它们的叔节点30并没有严格的大小要求.以广度优先的方式从根节点开始遍历,可以构成序列: [10,20,30,31,21,32,70] 反过来,可以推演出,序列构成二叉树的

hdu 4006 The kth great number (优先队列+STB+最小堆)

The kth great number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 6637    Accepted Submission(s): 2671 Problem Description Xiao Ming and Xiao Bao are playing a simple Numbers game. In a roun

C++队列和优先权队列的使用---应用:带时限作业排序

C++队列和优先权队列的使用-应用:带时限作业排序 C++队列的使用 首先包含头文件 include 队列可以用线性表(list)或双向队列(deque)来实现(注意vector container 不能用来实现queue,因为vector 没有成员函数pop_front!): queue<list<int>> q1; queue<deque<int>> q2; 其成员函数有"判空(empty)" ."尺寸(Size)"

优先队列及最小堆最大堆

为什么优先队列里默认是堆(heap)实现,默认是优先级高的出队,定义结构体重载函数为什么要按照从小到大排序?原来是自己对优先队列还不太了解: 1 堆 1.1 简介 n个关键字序列Kl,K2,-,Kn称为(Heap),当且仅当该序列满足如下性质(简称为堆性质): (1)ki<=k(2i)且ki<=k(2i+1)(1≤i≤ n),当然,这是小根堆,大根堆则换成>=号.//k(i)相当于二叉树的非叶结点,K(2i)则是左孩子,k(2i+1)是右孩子 若将此序列所存储的向量R[1..n]看做是一