欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

TOP-K问题

程序员文章站 2024-03-15 21:52:06
...

其实这个>其实我是一个算法渣,也不怎么会算法,只是最近遇到这个问题,就顺手谷歌一下,遇到一个不错的解法,记录一下

修改部分代码就可以获取最大堆 和 最小堆,参考了这篇文章基于堆实现的优先级队列:PriorityQueue 解决 Top K 问题



import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Random;

/**
 * 指定元素数量的最大堆
 * @author Think
 *
 * @param <E>
 */
public class FixSizedPriorityQueue <E extends Comparable<E>> implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private PriorityQueue<E> queue;
	private int maxSize; // 堆的最大容量

	public FixSizedPriorityQueue(int maxSize) {
		if (maxSize <= 0)
			throw new IllegalArgumentException();
		this.maxSize = maxSize;
		this.queue = new PriorityQueue(maxSize, new Comparator<E>() {
			public int compare(E o1, E o2) {
				// 生成最小堆使用o2-o1,生成最大堆使用o1-o2, 并修改 e.compareTo(peek) 比较规则
				return o1.compareTo(o2);
			}
		});
	}

	public void add(E e) {
		
		if (queue.size() < maxSize) { // 未达到最大容量,直接添加
			queue.add(e);
		} else { // 队列已满
			E peek = queue.peek(); //如果o2-o1 大于0 那么队列头元素是最大的,要得到的是最小堆,那么就是留peek和e的较小值
			//同样类似的o1-o2,对头元素是最小的,要生成最大堆,保留peek和e的较大者
			if (peek.compareTo(e) < 0) { // 将新元素与当前堆顶元素比较,保留较大的元素
				queue.poll();
				queue.add(e);
			}
		}
	}
	//队列中是否包含该元素
	public boolean contains(E e){
		return queue.contains(e);
	}
	//队列实际元素个数
	public int getSize() {
		return queue.size();
	}
	
	public List<E> reverse(){
		
		List<E> resultList  = new  ArrayList<E>(maxSize);
		
		while (!this.queue.isEmpty()) {
			resultList.add(queue.poll());
		}
		 Collections.reverse(resultList);
		 return resultList;
	}
	
	
	

	public static void main(String[] args) {
		final FixSizedPriorityQueue<Integer> pq = new FixSizedPriorityQueue(10);
		Random random = new Random();
		int rNum = 0;
		System.out.println("100 个 0~999 之间的随机数:-----------------------------------");
		for (int i = 1; i <= 20; i++) {
			rNum = random.nextInt(1000);
			System.out.println(rNum);
			pq.add(rNum);
		}
		System.out.println("PriorityQueue 本身的遍历是无序的:-----------------------------------");
		Iterable<Integer> iter = new Iterable<Integer>() {
			public Iterator<Integer> iterator() {
				return pq.queue.iterator();
			}
		};
		for (Integer item : iter) {
			System.out.print(item + ", ");
		}
		System.out.println();
		System.out.println("PriorityQueue 排序后的遍历:-----------------------------------");
		
		List<Integer> reverse = pq.reverse();
		System.out.println(reverse);
	}
}