堆问题:求n个整数中最小的K个数
来源:互联网 发布:新疆网络管制原理 编辑:程序博客网 时间:2024/06/03 11:16
关联:http://blog.csdn.net/tonghuawanli/article/details/70140441
建堆过程
堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。
既然是堆排序,自然需要先建立一个堆,而建堆的核心内容是调整堆,使二叉树满足堆的定义(每个节点的值都不大于其父节点的值)。调堆的过程应该从最后一个非叶子节点开始,假设有数组A = {1, 3, 4, 5, 7, 2, 6, 8, 0}。
建堆过程如下:
例题:输入4,5,1,6,2,7,3,8这8个数字,查找最小的4个数字是1,2,3,4
题目分析:
在找出前k个最小(或最大)的元素时,如果元素个数较少,可以采用简单选择排序;如果元素较多,可以采用堆排序;如果元素基本有序,可以采用冒泡排序。本文采用的是堆排序O(nlogk)
方法1:利用java的PriorityQueue
想求最小的k个数,可以用一个大根堆过滤大的数;
如果想求k个最大的数,可以用小根堆过滤小的数;
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) { ArrayList<Integer> list = new ArrayList<>(); if(input.length<1 || k<1 || input.length<k) return list; // 小根堆 //PriorityQueue<Integer> minHeap = new PriorityQueue<>(); // 建个大根堆 PriorityQueue<Integer> maxHeap = new PriorityQueue<>(new Comparator<Integer>() { // 如果上面的写法出错就用下面的这个 // PriorityQueue<Integer> maxHeap = new PriorityQueue<>(1,new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { // TODO Auto-generated method stub return o2-o1; } }); for(int i=0;i<input.length;i++){ maxHeap.offer(input[i]); // 保证堆中元素数目始终是k个 if(i>=k) maxHeap.poll(); } int[] a = new int[k]; // 暂时求的数组是降序的 for(int i=0;i<k;i++) a[i]=maxHeap.poll(); for(int i=k-1;i>=0;i--) list.add(a[i]); return list; }
时间复杂度分析:
PriorityQueue的peek()和element操作是常数时间,add(), offer(), 无参数的remove()以及poll()方法的时间复杂度都是log(N)
因为在程序中限制了堆中元素数目始终<=k个,循环了n次,时间复杂度O(nlogk)
方法2:网友写的创立小根堆与大根堆。
(1)小根堆
代码结合着建堆过程图看
import java.util.ArrayList;public class Main { public static void main(String[] args) { Main main = new Main(); int[] b = {98,15,12,8,8,4,43,11,15,9,64,2,76,35,11,3,1}; int k = 5; System.out.println(main.sort(b, k)); } //在数组b中查找前k个最小的数据 public ArrayList<Integer> sort(int[] b, int k) { ArrayList<Integer> list = new ArrayList<>(); if(b.length<k) return list; int n=b.length; //移除堆顶,将最后一个元素推入堆顶 for(int i=0;i<k;i++){ int k1 = (n-i)/2-1; //k1为待调整的初始堆最后一个非叶子节点 for(int j=k1;j>=0;j--){ //建堆 smallHeap(b, j, n-i-1); } //System.out.print(b[0]+" "); list.add(b[0]); int temp = b[0]; //此处是将堆顶与待排序的最后一个元素交换 b[0] = b[n-i-1]; b[n-i-1] = temp; } return list; } //建小根堆,从最后一个非终端节点至顶点,参数是(b[], 开始比较的节点下标,最后一个待比较的元素的下标) // 注:就是调整第k个结点(结点从0开始编号)为根的那棵树。 public static void smallHeap(int[] b, int k, int end){ int i=k, j=2*i+1;//i为要筛选的节点的下标,从0开始,j为 i的左孩子 while(j<=end){ //当还没有比较到叶子节点 if(j<end && b[j]>b[j+1]){ //j保存i的左右孩子中较大的孩子的下标 j++; } if(b[i]<b[j]){ //如果i比左右孩子都小,则结束本轮比较 break; } else{ // i节点与j节点交换, int temp = b[i]; b[i] = b[j]; b[j] = temp; i = j; j=2*i+1; } } }}// 输出:[1, 2, 3, 4, 8]
(2)大根堆
如果求最大的k个数,就建立大根堆。
import java.util.ArrayList;public class Main3 { public static void main(String[] args) { Main3 main3 = new Main3(); int[] b = {98,15,12,8,8,4,43,11,15,9,64,2,76,35,11,3,1}; int k = 5; System.out.println(main3.sort(b, k)); } //在数组b中查找前k个最大的数据 public ArrayList<Integer> sort(int[] b, int k) { ArrayList<Integer> list = new ArrayList<>(); if(b.length<k) return list; int n=b.length; //移除堆顶,将最后一个元素推入堆顶 for(int i=0;i<k;i++){ int k1 = (n-i)/2-1; //k1为待调整的初始堆最后一个非叶子节点 for(int j=k1;j>=0;j--){ //建堆 bigHeap(b, j, n-i-1); } //System.out.print(b[0]+" "); list.add(b[0]); int temp = b[0]; //此处是将堆顶与待排序的最后一个元素交换 b[0] = b[n-i-1]; b[n-i-1] = temp; } return list; } //建大根堆 // 注:就是调整第k个结点(结点从0开始编号)为根的那棵树。 public static void bigHeap(int[] b, int k, int end){ int i=k, j=2*i+1;//i为要筛选的节点的下标,从0开始,j为 i的左孩子 while(j<=end){ //当还没有比较到叶子节点 if(j<end && b[j]<b[j+1]){ //j保存i的左右孩子中较大的孩子的下标 j++; } if(b[i]>b[j]){ //如果i比左右孩子都大,则结束本轮比较 break; } else{ // i节点与j节点交换, int temp = b[i]; b[i] = b[j]; b[j] = temp; i = j; j=2*i+1; } } }}// 结果:[98, 76, 64, 43, 35]
0 0
- 堆问题:求n个整数中最小的K个数
- 求输入n个整数中最小的k个数
- 输入n个整数,找出最小的k个数
- 输入n个整数,找出其中最小的k个数
- 输入n个整数,找出其中最小的K个数
- 输入n个整数,找出其中最小的K个数
- 求n个数中最小的K个数。
- 找出N个整数中最大的K个数
- 找出N个整数中最大的K个数
- 找出N个整数中最大的K个数
- 找出N个整数中最大的K个数
- 找出N个整数中最大的K个数
- 找出N个整数中最大的K个数python
- 查找n个数中最小的k个元素
- n 个数中最小的 k 个数
- 算法面试题:求最小的k个束/求数组中最小的k个数
- n个数里最小的k个
- n个数里最小的k个
- 第四次作业-判断成绩
- rem移动适配
- Arduino的多任务管理
- 经典排序算法
- monkey脚本编写
- 堆问题:求n个整数中最小的K个数
- samescorenumber
- 关于hexo + github快速构建个人博客
- myeclipse创建svn资源库时连接不成功问题的解决
- Spring 事务失效问题
- 递推递归--G Fighting_小银考呀考不过四级
- 【c++】必须在类的初始化列表中初始化的的几种情况
- Digital Root(数根推导)
- monkey常用API