topK问题分析与实现

版权声明:本文为博主原创文章,转载请注明原文链接 https://blog.csdn.net/qq_36922927/article/details/82527611

一,什么是topK问题?

一组数据中,需要找出前k大(小)的数据

二,思路分析:以前k小为例

思路1:先排序再输出

如果是完全有序,那么输出所求数据很简答了(需要排序,将数据完全排序

思路2:基于快排,分片,不完全排序

使用快排思想,不断分片,左侧是比基准小的元素,右侧是比基准大的元素,

         令 index=基准元素下标

a, index<k  说明第k小元素在index右侧,在index右侧寻找新的基数,直到基数的下标index==k

b,index==k   说明第k小元素就是基准元素

c,index>k  说明第k小元素在index左侧,在index左侧寻找新的基数,直到基数的下标index==k

三,实现 java代码实现:

 public static  int  topK(int [] array,int k) throws Exception {
        if(null==array||array.length==0){
           throw new Exception("数组不能为空!");
        }
        if(k>array.length||k<=0){
            throw new Exception("k 范围不合法");
        }
        //开始处理快排:如何找基准数?基准数的大小越靠中间越好
        int middleIndex=getMiddle(array,0,array.length-1);
        while(middleIndex!=k){
//去右侧找新的基数位置
            if(middleIndex<k){
                middleIndex=getMiddle(array,middleIndex+1,array.length-1);
            }else{
//去左侧找新的基数位置
                middleIndex=getMiddle(array,0,middleIndex-1 );
            }
        }
     return array[middleIndex];
  }

getMiddle方法实现:

 //找到array中下标在from,to范围的基数的下标(同时是在通过快排思想将元素分割,移动)
  public static int getMiddle(int []array,int from,int to){
      int middle=array[from];//暂存基准值
      while(from<to){
          //从右往左扫描
          while(from<to &&  array[to]>=middle){
              to--;
          }
          array[from]=array[to];//暂存这个比较神奇的to所指元素
          // (array[to] 该元素可能是
          // 1,from==to条件下产生,from==to,那这个赋值没啥影响
          // 2,也可能是array[to]<middle条件下产生,此赋值将比middle小的元素移动到middle所在位置
          //从左往右扫描
          while(from<to && array[from]<middle){
              from++;
          }
          array[to]=array[from];//
      }
//   from==to,退出while循环,此时已经保证比基准值middle小
的元素在from左侧 ,不小于基准值middle的元素在from右侧

        array[from]=middle;//将基准值(放回数组)放到from这个位置

        return from;
  }

附上产生随机数组代码

/**
*@author wangwei
*@created 11:17 2018/9/8
 *@classname RandomUtil
*@classdescription  随机数生成工具类
*
*/
public class RandomUtil {
    /**
     * 
     * @param size   随机数组容量
     * @param max    随机数最大值
     * @return    随机数组
     */
    public static int []  buildArray(int size, int max){


        int []array=new int[size];
        for(int i=0;i<size;i++){
            array[i]= (int) (Math.random()*max)%max;

        }
        return array;
    }

    public static void main(String[] args) {
      System.out.println( RandomUtil.buildArray(20,100).toString());
    }
}

测试代码:

 public static void main(String[] args) throws Exception {
        final int k=4;
       int  [] array= RandomUtil.buildArray(10,20);
       showArray("before topK",array);
      System.out.println("第"+(k+1)+"小值:"+topK(array,k));
        showArray("after topK",array);
    }
  public static  void showArray(String info,int  []array){
        System.out.println(info);
   for(int  item:array){
       System.out.println(item);
   }
  }

测试结果:

这是一次测试结果:注意的是,基准之前的元素并不保证是否有序,只是保证其比基准元素小,基准之后的元素同理

before topK
14
4
3
3
6
6
3
13
11
6
第5小值:6
after topK
3
4
3
3
6
6
6
13
11
14

猜你喜欢

转载自blog.csdn.net/qq_36922927/article/details/82527611
今日推荐