數組中的k個最小值

問題:輸入n個整數,找出其中最小的k個數。數組

方案一:將輸入的n個整數進行排序,輸出前k個數即爲所求的k個最小數。時間複雜度爲O(nlogn).ui

方案二:建立一個大小爲k的容器,來存儲最小的k個數。遍歷剩下的n-k個數字,若是大於k個數中的最大值,則替換;不然繼續遍歷數組的剩  下的數字。spa

  在裝k個最小數字的容器(使用大根堆)中,所要作的操做有如下三個:code

  (1)在k個整數中找到最大的值;(時間複雜度爲O(1),根節點即爲最大值點)blog

  (2)在這個容器中刪除最大的數字;排序

  (3)將可能要插入的值插入到容器中。(插入和刪除的時間複雜度爲O(logk))class

總共有n個節點,則總的時間複雜度爲O(nlogk)。容器

 

package com.wyl; /** * 找到數組中的k個最小值 * @author wyl */
public class KMin { /** * 找到數組array中最下的k個數 * 思路:將數組的前K個數看成最小的k個數,存入到數組2中, * 遍歷array中剩餘的n-k個數,若是比數組2中的最大數字小,替換數組2中的數字; * 比其大繼續遍歷,最後數組2中存放的即爲最小的k個數 * @param array * @param k * @return
     */
    public void findKMin(int[] array, int k){ if(array.length < k){ return; } int[] newArray = new int[k]; for(int i=0;i<k;i++){ //前k個數字存入數組中
            newArray[i] = array[i]; } //將數組調整成大根堆,k/2爲堆的最後一個非葉節點
        for(int i = k/2 - 1;i>=0;i--){ //最後一個非葉節點的下標爲n/2-1
 rebuildHeap(newArray, i, k); } //n-k個數和前面和k中最大數比較
        for (int i =k; i < array.length; i++) { //若是堆頂大於n-k中數,則交換位置
            if(newArray[0]>array[i]){ newArray[0]=array[i]; //調整堆,堆頂被替換了,加入被替換的值很是小,會一直下沉到葉子節點.
                for(int j = k/2 - 1;j>=0;j--){ //最後一個非葉節點的下標爲n/2-1
 rebuildHeap(newArray, j, k); } } } // 輸出最小的K個數
        for (int i = 0; i < k; i++) { System.out.print(newArray[i] + " "); } } /** * 調整堆 * @param a * @param i * @param n */
    public void rebuildHeap(int[] a, int i, int n){ if(n <= 0){ return; } int temp = a[i];  //待調整節點
        boolean finish = false; //調整完成標誌
        int li = 2 * i + 1; //左節點下標
        while(li <= n - 1 && !finish){ if(li < n - 1 && a[li] < a[li+1]){ //節點存在右子樹,且右子樹值大於左子樹
                li = li+1; } if(temp < a[li]){ //待調整節點值小於子樹值,繼續調整子樹
                a[i] = a[li]; a[li] = temp; }else{ finish = true; } } } public static void main(String[] args) { KMin kMin = new KMin(); int[] array = {4,5,1,6,3,8,7,9}; kMin.findKMin(array, 4); } }
相關文章
相關標籤/搜索