数据结构面试题1.2.9-查找最小的K个元素-使用最大堆
2015-09-23 15:41
429 查看
Java最大堆相关知识:/article/9191429.html
package questions; import java.util.Arrays; import java.util.Random; /** * @title 查找最小的K个元素-使用最大堆 * @question 输入n个整数,输出其中最小的K个元素,例如,输入1,2,3,4,5,6,7,8那么最小的4个元素就是1,2,3,4 * @analysis * 堆其实是一颗完全二叉树,堆对于两类问题有着很好的解决方案:a.排序问题:由于堆是一颗完全二叉树,所以采用堆,堆n元数组进行排序,时间复杂度不会超过O * (nlgn),而且只需要几个额外的空间。b.优先级队列。通过插入新元素和调整堆结构来维护堆的性质,每个操作所需要的时间都是O(lgn)<br> * 堆常见实现是采用一个大小为n的数组存储元素,并且0号单元舍弃不用。对堆中的元素按照层次从上到下,从左导游的顺序依次编号。 * 那么对于编号为i的元素:<br> * a:如果左孩子存在,那么左孩子的编号为2i<br> * b:如果右孩子存在,那么右孩子的编号为2*i+1<br> * c:如果有父结点,那么父结点的编号为i/2<br> * d:结点为叶结点的条件是左孩子且右孩子都为空,为空结点的条件是i<1或者i>n<br> * 堆的设计对于处理Top K问题十分方便。首先设置一个大小为K的堆(如果求最大top K,那么用最小堆,如果求最小top * K,那么用最大堆),然后扫描数组。并将数组的每个元素与堆的根比较,符合条件的就插入堆中,同时调整堆使之符合堆的特性,扫描完成后, * 堆中保留的元素就是最终的结果 * 。说到调整堆,不得不提的是调整的算法,分为两类:向下调整(shiftdown)和向上调整(shiftup)。<br> * 有了堆的基本操作,top K问题就有了一个基础(当然也完全可以完全不用堆解决top K问题)。以最小top * K问题为例(此时需要建立大小为K的最大堆),top * K的求解过程是:扫描原数组,将数组的前K个元素扔到堆中,调整使之保持堆的特性。对于k之后的元素 * ,如果比堆顶的元素小,那么替换堆顶元素并调整堆,扫描数组完成后,堆中保存的元素就是最终的结果。 * * * * @link 堆的理解http://www.java3z.com/cwbwebhome/article/article1/1362.html?id=4745 * @author Sam * */ public class Ex1o2o9 { public static void main(String[] args) { int[] a = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; int k = 7; MinKElement mke = new MinKElement(); mke.disArrange(a); System.out.println("after disarranging,the array a[]:"); System.out.println(Arrays.toString(a)); mke.findKMin(a, k); } } /** * 最小的K个元素,使用最大堆,当然使用快速排序也是OK的 */ class MinKElement { /** * rearrange the array, just for test.随机调换数组 * * @param a */ public void disArrange(int[] a) { for (int i = 0, len = a.length; i < len; i++) { Random random = new Random(); int j = random.nextInt(len); swap(a, i, j); } } /** * 数组a中下标为i,j数据交换 * * @param a * @param i * @param j */ private static void swap(int[] a, int i, int j) { int temp = a[i]; a[i] = a[j]; a[j] = temp; } public void findKMin(int[] a, int k) { // you can do this:int[] heap = new int[k].but that may be space-cost int[] heap = a; // create MaxHeap of K elements form the last RootIndex to 0. // 先建立K的最大堆,K个值,那么起始点为K/2-1 int rootIndex = k / 2 - 1; while (rootIndex >= 0) { reheap(heap, rootIndex, k - 1); rootIndex--; } // 建立好K的最大堆之后,循环,将length-k之外的值不断的和最大值进行对比,小于最大值,就纳入堆中,调整堆的最大堆 for (int i = k, len = heap.length; i < len; i++) { if (heap[i] < heap[0]) { heap[0] = heap[i]; reheap(heap, 0, k - 1); } } System.out.println(toString(heap, k)); } // reheap:from root to lastIndex. public void reheap(int[] heap, int rootIndex, int lastIndex) { int orphan = heap[rootIndex]; boolean done = false; int leftIndex = rootIndex * 2 + 1; while (!done && leftIndex <= lastIndex) { int largerIndex = leftIndex; if (leftIndex + 1 <= lastIndex) { int rightIndex = leftIndex + 1; if (heap[rightIndex] > heap[leftIndex]) { largerIndex = rightIndex; } } // Attention! should not use-->heap[root]<heap[largerIndex]<-- // I spend time to find the problem.... if (orphan < heap[largerIndex]) { heap[rootIndex] = heap[largerIndex]; rootIndex = largerIndex; leftIndex = rootIndex * 2 + 1; } else { done = true; } } heap[rootIndex] = orphan; } public static String toString(int[] a, int length) { if (a == null) return "null"; int iMax = length - 1; if (iMax == -1) return "[]"; StringBuilder b = new StringBuilder(); b.append('['); for (int i = 0;; i++) { b.append(a[i]); if (i == iMax) return b.append(']').toString(); b.append(", "); } } }
相关文章推荐
- 数据结构:最小生成树--Prim算法
- 找出一个字符数组(元素不重复)所有可能字符的组合
- 数据结构之AVL树
- 数据结构与算法分析2.19题
- RMQ with Shifts
- 第一章:javascript: 数据结构与算法
- Struts2的数据结构
- 数据结构与算法分析2.16
- 数据结构与算法分析第二章12题
- 数据结构(线段树)训练
- most of 1-1000
- MongoDB学习笔记~数据结构与实体对象不一致时,它会怎么样?
- 基本数据结构:栈(stack)
- 基本数据结构:链表(list)
- 第四周项目三数据结构实践(一)——单链表:逆置
- 项目4 -- 链表算法库 程序的多文件组织形式
- 项目3 -- 单链表的应用(3)
- 项目3 -- 单链表的应用(2)
- 第四周项目二数据结构之自建算法库——单链表
- 各类数据结构的特点