5.查找最小的k 个元素
题目:输入n 个整数,输出其中最小的k 个。
例如输入1,2,3,4,5,6,7 和8 这8 个数字,则最小的4 个数字为1,2,3 和4。
思路: 对于元素集合非常大的情况,比如上亿条数据,可以通过在内存中构造一个有限大小的大堆(heap)来处理
大堆的特性是根节点总是为堆内元素的最大元素
1.对前K个元素构造大堆,里面包含K+1个元素,下标为1的元素为head根节点,该根结点是堆中的最大元素
2.依次读取剩余元素 如果读到的元素比根节点大,则忽略,因为我们的目的是查找最小的K个元素,堆中的元素总是比根节点小,所以如果比根节点还大,那肯定比堆中其他元素还大
如果读到的元素小于根节点,则将根节点替换为该元素,为了保持堆的特性,需要依次将其与其左右节点比较,如果左或右节点大于改节点,则下移该元素与子元素交换(sink)
3. 在堆中,i元素的左节点坐标为2*i, 右节点为2*i+1
1 package com.rui.microsoft; 2 3 import java.util.Arrays; 4 5 /** 6 * 5.查找最小的k 个元素 7 题目:输入n 个整数,输出其中最小的k 个。 8 例如输入1,2,3,4,5,6,7 和8 这8 个数字,则最小的4 个数字为1,2,3 和4。 9 * 10 */ 11 public class Test05_FindKMinItems { 12 13 public static void main(String[] args) { 14 //int[] array = {1,2,3,5,5,6,7,8,4}; 15 int[] array = {1,8,9,3,2,7,6,4,5}; 16 int size = 4; 17 int[] array01 = Arrays.copyOf(array, size); 18 int[] array02 = Arrays.copyOfRange(array, array01.length, array.length); 19 20 MaxHeap heap = new MaxHeap(size); 21 22 for(int i = 0; i < array01.length; i++){ 23 heap.insert(array01[i]); 24 } 25 26 for(int i = 0; i < array02.length; i++){ 27 heap.updateHead(array02[i]); 28 } 29 30 for(int i = 0; i < heap.size+1; i++){ 31 System.out.println(heap.get()[i]); 32 } 33 } 34 35 static class MaxHeap{ 36 private int[] array; 37 private int size; 38 39 //current position in array which is open for insertion 40 private int pos = 1; 41 42 //our MaxHeap has a fixed size 43 public MaxHeap(int size){ 44 this.size = size; 45 array = new int[size+1]; 46 } 47 48 public void insert(int data){ 49 //insert to the end of the array 50 if(pos > size){ 51 return; 52 } 53 int i = pos; 54 this.array[pos++] = data; 55 56 //start to swim up 57 while(i>1){ 58 if(array[i] < array[i/2])break; 59 else{ 60 swap(i, i/2); 61 i /= 2; 62 } 63 } 64 } 65 66 //Update the head node (maximum node) of the heap with a different value 67 public void updateHead(int data){ 68 //head is always the first node in the array 69 int head = array[1]; 70 if(data >= head){ 71 //the new data for head node is larger than the old one, just skip it 72 //because it maintains the max heap definition: the root node is always the largest one 73 //array[1] = data; 74 return; 75 }else{ 76 array[1] = data; 77 int i = 1; 78 int j = i; 79 while(i < (pos-1)/2 && i > 0){ 80 //start to sink the head node 81 j = i; 82 if(array[i] > array[2*i] && array[i] > array[2*i + 1]) break; 83 else{ 84 i *= 2; 85 if(array[i] < array[i+1])i++; 86 swap(i,j); 87 } 88 } 89 } 90 } 91 92 private void swap(int i, int j){ 93 int tmp = array[i]; 94 array[i] = array[j]; 95 array[j] = tmp; 96 } 97 98 public int[] get(){ 99 return this.array; 100 } 101 } 102 }