使用优先级队列求一个大数组中的前k个最大的数(或前k个最小的数)

时间:2022-04-23 18:53:04
/**
* 对于一个数据量很大的数组,找出数组中前k个最大的数和前k个最小的数
*/

package 华为机试题;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;

/**
* @author Hutongling
*
* @time:2017年4月10日 下午9:12:25
*/

public class 优先级队列 {

//找到数组中的前k个最小值
static Queue<Integer> findFirstEndN(int[] data, int k){
if(data==null || data.length==0)
return null;

Queue<Integer> priorityQueue=new PriorityQueue<>(k);
for(int i=0;i<data.length;i++)
priorityQueue.add(data[i]);
return priorityQueue;

}

//找到数组中的前k个最大值
static Queue<Integer> findTopN(int[] data, int k){
if(data==null || data.length==0)
return null;

Queue<Integer> priorityQueue=new PriorityQueue<>(k);
priorityQueue.add(data[0]);
for(int i=1;i<data.length;i++){
if(priorityQueue.size()<k)
priorityQueue.add(data[i]);
else if(data[i]>=priorityQueue.peek()){
priorityQueue.poll();
priorityQueue.add(data[i]);
}
}
return priorityQueue;
}

//找到数组中的前k个最小值
static Queue<Integer> findFirstEndN1(String filePath, int k) throws NumberFormatException, IOException{
if(filePath==null)
return null;

Queue<Integer> priorityQueue=new PriorityQueue<>(k);
File fileName= new File(filePath);
BufferedReader bufread= new BufferedReader(new FileReader(fileName));
String read;
while((read=bufread.readLine())!=null){
String[] data=read.split(" ");
for(int i=0;i<data.length;i++)
priorityQueue.add(Integer.valueOf(data[i]));
read=null;
data=null;
}

return priorityQueue;

}

// 找到数组中的前k个最大值
static Queue<Integer> findTopN1(String filePath, int k) throws NumberFormatException, IOException {
if (filePath == null)
return null;

Queue<Integer> priorityQueue = new PriorityQueue<>(k);// 建立一个优先级队列
File fileName = new File(filePath);
BufferedReader bufread = new BufferedReader(new FileReader(fileName));// 读入文件
String read;
while ((read = bufread.readLine()) != null) {
String[] data = read.split(" ");
priorityQueue.add(Integer.valueOf(data[0]));
for (int i = 1; i < data.length; i++) {
if (priorityQueue.size() < k)
priorityQueue.add(Integer.valueOf(data[i]));
else if (Integer.valueOf(data[i]) >= priorityQueue.peek()) {
priorityQueue.poll();
priorityQueue.add(Integer.valueOf(data[i]));
}
}
read = null;
data = null;
}
return priorityQueue;
}

public static void main(String[] args) throws IOException {
int[] data=new int[10000000];
Random random=new Random();
for(int i=0;i<data.length;i++)
data[i]=random.nextInt(10000000);

int k=15;
Queue<Integer> priorityQueue=findFirstEndN(data,k);
Queue<Integer> priorityQueueTop=findTopN(data,k);

System.out.println("前k个最小的数为:");

for(int i=0;i<k;i++)
System.out.print(priorityQueue.poll() + " ");

System.out.println("\n前k个最大的数为:");
for(int i=0;i<k;i++)
System.out.print(priorityQueueTop.poll() + " ");

String path="D:/data1.txt";
File text=new File(path);
FileWriter textFile=new FileWriter(text);
int n=10000000;
for(int i=0;i<n;i++)
if((i+1)%1000!=0)
textFile.write(random.nextInt(10000000) + " ");
else
textFile.write(random.nextInt(10000000) + "\n");

Queue<Integer> priorityQueue1=findFirstEndN1(path,k);
Queue<Integer> priorityQueueTop1=findTopN1(path,k);

System.out.println("前k个最小的数为:");

for(int i=0;i<k;i++)
System.out.print(priorityQueue1.poll() + " ");

System.out.println("\n前k个最大的数为:");
for(int i=0;i<k;i++)
System.out.print(priorityQueueTop1.poll() + " ");
}

}

代码结果:(每次运行的结果不一样,因为使用的是随机函数随机生成的一千万数据)
前k个最小的数为:
0 0 1 1 1 2 3 5 5 5 8 9 10 12 14
前k个最大的数为:
9999984 9999985 9999986 9999989 9999990 9999991 9999992 9999992 9999993 9999993 9999996 9999996 9999997 9999998 9999999 前k个最小的数为:
0 0 1 1 3 5 6 6 6 7 7 12 13 14 14
前k个最大的数为:
8467240 9976497 9977578 9983445 9985562 9986467 9988006 9988126 9988131 9988140 9988146 9988196 9988221 9988255 9988335