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);
		}
	}

}








posted on 2017-04-27 09:35  ljbguanli  阅读(380)  评论(0编辑  收藏  举报