演算法——TOP K問題最小堆實現__演算法

來源:互聯網
上載者:User
1. 問題背景

在實際應用中,我們經常會遇到在一大推資料中找出最大的幾個數的問題,也就是我們提到的TOP K問題。K表示需要找出資料的數量 2. 解決方案

TOP K問題也有多種解決方案,比如排序,最後截取靠前或者靠後的K個資料。當資料量小的時候,排序解決起來當然可以,演算法簡單,排序演算法也有很多現成的。當資料量很大時,維護一個很長的數組,不管是空間儲存上還是排序耗費的時間上都可能難以接受。這時我們可以採用最小堆的方式來實現,只需要維護一個K長度的數組就行 3. 具體實現

資料結構最小堆MinHeap, 其中最重要的是堆的調整adjustHeap

package org.cyxl.common;/** * Created by jeff on 16/5/11. */public class MinHeap {    // 堆的儲存結構 - 數組    private int[] data;    /**     * 初始化堆中的資料,以int的最小值作為初始值     *     * @param k     */    public MinHeap(int k)    {        this.data = new int[k];        for(int i=0;i<k;i++){            data[i]=Integer.MIN_VALUE;        }    }    private void adjustHeap(int i)    {        //擷取左右結點的數組下標        int l = left(i);        int r = right(i);        // 這是一個臨時變數,表示 跟結點、左結點、右結點中最小的值的結點的下標        int min = i;        // 存在左結點,且左結點的值小於根結點的值        if (l < data.length && data[l]<data[i]){            min = l;        }        // 存在右結點,且右結點的值小於以上比較的較小值        if (r < data.length && data[r]<data[min]){            min = r;        }        // 左右結點的值都大於根節點,直接return,不做任何操作        if (i == min)            return;        // 交換根節點和左右結點中最小的那個值,把根節點的值替換下去        swap(i, min);        // 由於替換後左右子樹會被影響,所以要對受影響的子樹再進行adjustHeap        adjustHeap(min);    }    /**     * 擷取右結點的數組下標     * @param i     * @return     */    private int right(int i)    {        return (i + 1) << 1;    }    /**     * 擷取左結點的數組下標     * @param i     * @return     */    private int left(int i)    {        return ((i + 1) << 1) - 1;    }    /**     * 交換元素位置     *     * @param i     * @param j     */    private void swap(int i, int j)    {        int tmp = data[i];        data[i] = data[j];        data[j] = tmp;    }    /**     * 將數值加入到堆中     *     * @param element     */    public void add(int element)    {        if(element>data[0]) {            data[0] = element;            adjustHeap(0);        }    }    public int[] getData(){        return data;    }    @Override    public String toString(){        StringBuilder builder = new StringBuilder();        builder.append("{");        for (int i=0;i<data.length;i++){            builder.append(data[i]);            if(i!=data.length-1){                builder.append(",");            }        }        builder.append("}");        return builder.toString();    }}
4. 測試
public static void main(String[] args){        int[] a = {12,1,5425,12,43,734,343,999,8,99,55,2,222,444,11};        //求最大的10個        int k=10;        MinHeap heap = new MinHeap(k);        for(int i:a){            heap.add(i);        }        System.out.print(heap);    }

輸出結果是

{12,43,55,99,222,343,999,734,5425,444}
5. 擴充

5.1 當然實際應用中,我們找的可能不是單純的數字。更可能是和這些數字相關的某些對象。比如找出年齡最大的10個使用者,這時我們的User對象可以實現Comparable介面來實現比較。

5.2 這裡我們是最小堆來實現TOP K問題,當然也可以用最大堆來找出最小的K個值

5.3 對於最小(大)堆的定義以及特點可以網上查看一下

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.