topK 问题
- topK
- 二、实验内容
- 三、数据结构设计
- 四、算法设计
- 五、运行结果
- 六、程序源码
topK
(1)实验题目
topK 问题
(2)问题描述
从大批量数据序列中寻找最大的前 k 个数据,比如从 10 万个数据中,寻找最大的前 1000 个数。请给出最大前 k 个数据的和。
二、实验内容
(1)设计求解 topK 问题的存储结构;
(2)用伪代码描述算法,并分析时空性能;
(3)编程实现。
三、数据结构设计
典型的topK问题,由于题目要求的是最大的前K个数,所以使用小根堆,堆的大小为k,首先创建堆,此时堆的大小为k ,当再次插入元素时,和栈顶元素比较,如果比堆顶元素大,把堆顶元素删除,将该元素入堆;如果比堆顶元素小,不做任何处理.把所有的数据集合遍历完,此时,小根堆中的元素就是最大的前k 个数.,然后再对这k个数求和.
堆的成员变量:
public int[] elem ;//底层结构
public int usedSize;//标记元素个数
public interface IList {
void offer(int val);//插入
int poll();//删除堆顶元素
int peek();//查看堆顶元素
}
四、算法设计
(1)堆的插入:offer(int val) :
首先将元素插入数组的尾部,usedSize++,然后向上调整.
向上调整:shiftUp()
时间复杂度:O(log2 N)
空间复杂度:O(1)
初始条件child = usedSize ; 结束条件:child = 0
每次循环让parent = (child-1)/2, 可以理解成child 的父节点
循环体:
if(elem[child] < elem[parent] ),交换child 下标和parent下标的值,然后child = parent ,parent =( child -1) /2
否则直接退出循环.
(2)堆的删除:poll(int parent ,int len)
首先将elem[0] 和elem[usedSize]交换,usedSize–,然后向下调整
向下调整:shiftDown()
时间复杂度:O(log2 N)
空间复杂度:O(1)
五、运行结果
六、程序源码
```java
//接口
public interface IList {
void offer(int val);//插入
int poll();//删除堆顶元素
int peek();//查看堆顶元素
}
public class TestHeap implements IList {
public int[] elem ;
public int usedSize;
public TestHeap(int k){
this.elem = new int[k];//初始容量
}
//堆的插入
public void offer(int val){
elem[usedSize] = val;
usedSize++;
//向上调整
shiftUp(usedSize-1);
}
public void shiftUp(int child){
int parent =(child -1) / 2;
while(child > 0){
if(elem[child] < elem[parent]){
swap(child ,parent);
child = parent;
parent = (child -1 ) / 2;
}else{
break;
}
}
}
//堆的删除
public int poll(){
int tmp = elem[0];
swap(0 ,usedSize-1);
usedSize--;
//向下调整
shiftDown(0,usedSize);
return tmp;
}
public int peek(){
return elem[0];
}
private void shiftDown(int parent ,int len){
int child = parent *2+1;
while(child < len){
if(child +1 < elem.length && elem[child] > elem[child+1]){
child ++;
}
if(elem[parent] > elem[child]){
swap(parent,child);
parent =child ;
child = 2* parent+1;
}else {
break;
}
}
}
private void swap(int i,int j){
int tmp = elem[i];
elem[i] = elem[j];
elem[j] = tmp;
}
}
//测试类
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入元素个数:");
int count = scanner.nextInt();
System.out.println("请输入要查找的序号: ");
int k = scanner.nextInt();
TestHeap testHeap =new TestHeap(k);
System.out.println("请输入元素结合:");
int[] array = new int[count];
for (int i = 0; i < count; i++) {
array[i] = scanner.nextInt();
}
//构建元素个数为k 的小根堆
for (int i = 0; i < k; i++) {
testHeap.offer(array[i]);
}
//确保小根堆中的元素是数据集合中的最大的
for (int i = k; i < array.length; i++) {
int tmp = array[i];
if(tmp > testHeap.peek()){
testHeap.poll();
testHeap.offer(tmp);
}
}
int sum = 0;
for (int i = 0; i < k; i++) {
sum += testHeap.poll();
}
System.out.println(sum);
}
}