topk

1、topk问题

  • 采用小根堆或者大根堆

   求最大K个采用小根堆,而求最小K个采用大根堆。

  求最大K个的步奏:

  1.     根据数据前K个建立K个节点的小根堆。
  2.     在后面的N-K的数据的扫描中,
  • 如果数据大于小根堆的根节点,则根节点的值覆为该数据,并调节节点至小根堆。
  • 如果数据小于或等于小根堆的根节点,小根堆无变化。

 求最小K个跟这求最大K个类似。时间复杂度O(nlogK)(n:数据的长度),特别适用于大数据的求Top K。

package test1;

/**
 * 求前面的最大K个 解决方案:小根堆 (数据量比较大(特别是大到内存不可以容纳)时,偏向于采用堆)
 * 
 * 
 */
public class topk {

    public static void main(String[] args) {
        int a[] = { 4, 3, 5, 1, 2, 8, 9, 10 };
        int result[] = new topk().getTopKByHeap(a, 3);
        for (int temp : result) {
            System.out.println(temp);
        }
    }

    /**
     * 创建k个节点的小根堆
     * 
     * @param a
     * @param k
     * @return
     */

    int[] createHeap(int a[], int k) {
        int[] result = new int[k];
        for (int i = 0; i < k; i++) {
            result[i] = a[i];
        }
        for (int i = 1; i < k; i++) {
            int child = i;
            int parent = (i - 1) / 2;
            int temp = a[i];
            while (parent >= 0 && child != 0 && result[parent] > temp) {
                result[child] = result[parent];
                child = parent;
                parent = (parent - 1) / 2;
            }
            result[child] = temp;
        }
        return result;

    }

    void insert(int a[], int value) {
        a[0] = value;
        int parent = 0;

        while (parent < a.length) {
            int lchild = 2 * parent + 1;
            int rchild = 2 * parent + 2;
            int minIndex = parent;
            if (lchild < a.length && a[parent] > a[lchild]) {
                minIndex = lchild;
            }
            if (rchild < a.length && a[minIndex] > a[rchild]) {
                minIndex = rchild;
            }
            if (minIndex == parent) {
                break;
            } else {
                int temp = a[parent];
                a[parent] = a[minIndex];
                a[minIndex] = temp;
                parent = minIndex;
            }
        }

    }

    int[] getTopKByHeap(int input[], int k) {
        int heap[] = this.createHeap(input, k);
        for (int i = k; i < input.length; i++) {
            if (input[i] > heap[0]) {
                this.insert(heap, input[i]);
            }

        }
        return heap;

    }

}

 2、topk  大根堆 求最小的K个数

package test1;

import java.util.*;


/**
 * 无序数组中最小的k个数
 * 
 * @author 过路的守望
 *
 */
public class Main_2 {
    public static void main(String[] args) {
        Scanner s =new Scanner(System.in);
        int n=s.nextInt();
        int k=s.nextInt();
        int[] A=new int[n];
        for(int i=0;i<n;i++) {
            A[i]=s.nextInt();
        }
        int[] res=findKthNumbers(A,n,k);
        for(int i=0;i<k;i++) {
            System.out.println(res[i]);
        }
//        System.out.println(Arrays.toString(res));
     
    }

    public static int[] findKthNumbers(int[] A, int n, int k) {
        n = A.length;
        /*
         * p为数组中第k大的数
         */
        int p = getKthNumberByHeapSort(A, k);
        int[] result = new int[k];
        int pos = 0;
//        System.out.println(p);
        for (int i = 0; i < n; i++) {
            if (A[i] <= p) {
                result[pos++] = A[i];
            }
        }
        return result;
    }

    /**
     * 取数组前k个元素作为初始堆元素
     * 
     * @param A
     * @param k
     * @return
     */
    public static int getKthNumberByHeapSort(int[] A, int k) {
        int[] heap = new int[k];
        heap = Arrays.copyOf(A, k);
        /*
         * 建堆
         */
        buildHeap(heap, k);
        /*
         * 将数组后n-k个元素与堆顶元素比较,若比其小,则赋值给堆顶元素后执行下滤操作. 时间复杂度
         */
        for (int i = k; i < A.length; i++) {
            if (A[i] < heap[0]) {
                heap[0] = A[i];
                perColate(heap, 0, k);
            }
        }

        return heap[0];

    }

    /**
     * 建堆过程
     * 
     * @param data
     * @param len
     */
    public static void buildHeap(int[] data, int len) {
        for (int i = (len - 1) / 2; i >= 0; i--) {
            perColate(data, i, len);
        }

    }

    /**
     * 下滤操作 最大堆
     * 
     * @param data
     * @param i
     * @param length
     */
    public static void perColate(int[] data, int i, int length) {
        int len = length;
        int leftChild = getLeftChild(i);
        int temp = data[i];
        while (leftChild < len) {
            if (leftChild < (len - 1) && data[leftChild] < data[leftChild + 1]) {
                leftChild++;
            }
            if (temp < data[leftChild]) {
                data[i] = data[leftChild];
                i = leftChild;
                leftChild = getLeftChild(i);
            } else {
                break;
            }

        }
        data[i] = temp;

    }

    /**
     * 得到左儿子下标
     * 
     * @param parent
     * @return
     */
    public static int getLeftChild(int parent) {
        return 2 * parent + 1;
    }

}

 

posted @ 2020-07-30 16:18  我们村里的小花儿  阅读(346)  评论(0编辑  收藏  举报