微软算法100题05 查找最小的k 个元素

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 }

 

posted @ 2015-10-21 18:45  蟹粉小笼包  阅读(238)  评论(0编辑  收藏  举报