問題:輸入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); } }