最小堆解决topK问题

来源:互联网 发布:旅游网络销售范围 编辑:程序博客网 时间:2024/06/05 03:35
package dataStructer;public class MinHeap{// 堆的存储结构 - 数组private int[] data;// 将一个数组传入构造方法,并转换成一个小根堆public MinHeap(int[] data){this.data = data;buildHeap();}// 将数组转换成最小堆private void buildHeap(){// 完全二叉树只有数组下标小于或等于 (data.length) / 2 - 1 的元素有孩子结点,遍历这些结点。// *比如上面的图中,数组有10个元素, (data.length) / 2 - 1的值为4,a[4]有孩子结点,但a[5]没有*        for (int i = (data.length) / 2 - 1; i >= 0; i--)         {        // 对有孩子结点的元素heapify            heapify(i);        }    }private void heapify(int i){// 获取左右结点的数组下标        int l = left(i);          int r = right(i);                // 这是一个临时变量,表示 跟结点、左结点、右结点中最小的值的结点的下标        int smallest = i;                // 存在左结点,且左结点的值小于根结点的值        if (l < data.length && data[l] < data[i])          smallest = l;                  // 存在右结点,且右结点的值小于以上比较的较小值        if (r < data.length && data[r] < data[smallest])          smallest = r;                  // 左右结点的值都大于根节点,直接return,不做任何操作        if (i == smallest)              return;                  // 交换根节点和左右结点中最小的那个值,把根节点的值替换下去        swap(i, smallest);                // 由于替换后左右子树会被影响,所以要对受影响的子树再进行heapify        heapify(smallest);//左子结点被交换 那么做左子树需要重新排列    }// 获取右结点的数组下标private int right(int i){          return (i + 1) << 1;      }   // 获取左结点的数组下标<<位置偏移 相当于倍数放大    private int left(int i)     {          return ((i + 1) << 1) - 1;      }        // 交换元素位置    private void swap(int i, int j)     {          int tmp = data[i];          data[i] = data[j];          data[j] = tmp;      }        // 获取对中的最小的元素,根元素    public int getRoot()    {        return data[0];    }    // 替换根元素,并重新heapifypublic void setRoot(int root){data[0] = root;heapify(0);}}

测试代码:

package dataStructer;public class TopK{// 从data数组中获取最大的k个数private static int[] topK(int[] data,int k){// 先取K个元素放入一个数组topk中int[] topk = new int[k]; for(int i = 0;i< k;i++){topk[i] = data[i];}// 转换成最小堆MinHeap heap = new MinHeap(topk);// 从k开始,遍历datafor(int i= k;i<data.length;i++){int root = heap.getRoot();// 当数据大于堆中最小的数(根节点)时,替换堆中的根节点,再转换成堆if(data[i] > root){heap.setRoot(data[i]);}}return topk;}public static void main(String[] args){// 源数据int[] data = {56,275,12,6,45,478,41,1236,456,12,546,45};         // 获取Top5int[] top5 = topK(data, 5);for(int i=0;i<5;i++){System.out.println(top5[i]);}}}


0 0
原创粉丝点击