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