数据结构面试题1.2.9-查找最小的K个元素-使用最大堆

来源:互联网 发布:华孚色纺怎么样 知乎 编辑:程序博客网 时间:2024/05/21 23:00

Java最大堆相关知识:http://blog.csdn.net/sayangnala/article/details/48682381


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-costint[] heap = a;// create MaxHeap of K elements form the last RootIndex to 0.// 先建立K的最大堆,K个值,那么起始点为K/2-1int 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(", ");}}}

0 0
原创粉丝点击