zoukankan      html  css  js  c++  java
  • Java实现寻找最小的k个数

    1 问题描述
    有n个整数,请找出其中最小的k个数,要求时间复杂度尽可能低。

    2 解决方案
    2.1 全部排序法

    先对这n个整数进行快速排序,在依次输出前k个数。

    package com.liuzhen.array_2;
    
    public class SearchMinK {
        //方法1:全部排序
        public void quickSort(int[] A,int start,int end){
            if(end > start){
                int k = LomutoPartition(A,start,end);
                quickSort(A,start,k-1);
                quickSort(A,k+1,end);
            }
        }
        //返回数值result,满足:     左边部分< A[result] <=右边部分
        public int LomutoPartition(int[] A,int start,int end){
            if(start >= end)
                return start;
            int begin = A[start];
            int result = start;
            for(int i = start + 1;i <= end;i++){
                if(A[i] < begin){
                    result++;
                    swap(A,i,result);
                }
            }
            swap(A,start,result);
            return result;
        }
        //交换数组m位置和n位置上的值
        public void swap(int[] arrayA,int m,int n){
            int temp = arrayA[m];
            arrayA[m] = arrayA[n];
            arrayA[n] = temp;
        }
        //输出数组前k个元素
        public void printArrayK(int[] array,int k){
            for(int i = 0;i < k;i++){
                System.out.print(array[i]+" ");
            }
        }
    public static void main(String[] args){
            SearchMinK test = new SearchMinK();
            int[] A = {9,8,7,5,4,3,2,1,6,3,4,5,12,32,3,2,1,4,6,34};
            test.quickSort(A, 0, A.length-1);
            System.out.println("对数组进行排序后结果:");
            for(int i = 0;i < A.length;i++)
                System.out.print(A[i]+" ");
            System.out.println("
    "+"输出数组最小的5个数:");
            test.printArrayK(A, 5);
    
        }
    }
    

    运行结果:

    对数组进行排序后结果:
    1 1 2 2 3 3 3 4 4 4 5 5 6 6 7 8 9 12 32 34 
    输出数组最小的5个数:
    1 1 2 2 3 
    

    2.2 部分排序法
    具体操作步骤如下:

    (1)遍历n个数,把最先遍历到的k个数存入到大小为k的数组中,假设他们就是最小的k个数;

    (2)利用选择排序或交换排序找到这k个元素中的最大值kmax;

    (3)继续遍历剩余的n-k个数。假设每次遍历到的新元素的值为x,把x与kmax进行比较:如果x<kmax,则用x替换kmax,并回到第2步重新找出k个元素的数组中新的最大元素kmax;如果x>=kmax,则继续遍历,不更新数组。

    具体代码如下:

    package com.liuzhen.array_2;
    
    public class SearchMinK {
    //方法2:部分排序
        public void getArrayMinK(int[] A,int k){
            if(k > A.length)
                return;
            while(true){
                int max = getMaxArrayK(A,k);  //当前数组前k个元素中的最大值
                int count = 0;
                for(int i = k;i < A.length;i++){
                    if(A[max] > A[i])
                        swap(A,max,i);
                    else
                        count++;
                }
                if(count == A.length-k)
                    break;
            }
            System.out.println("
    "+"使用方法2进行部分排序后的结果:");
            for(int i = 0;i < A.length;i++)
                System.out.print(A[i]+" ");
            System.out.println("
    部分排序选出数组中最小的"+k+"个数:");
            for(int i = 0;i < k;i++)
                System.out.print(A[i]+" ");
        }
        
        //获取数组前k个元素的最大值的数组下标
        public int getMaxArrayK(int[] A,int k){
            int result = 0;
            if(k > A.length)
                return 0;
            for(int i = 0;i < k;i++){
                if(A[i] > A[result])
                    result = i;
            }
            return result;
        }
    //交换数组m位置和n位置上的值
        public void swap(int[] arrayA,int m,int n){
            int temp = arrayA[m];
            arrayA[m] = arrayA[n];
            arrayA[n] = temp;
        }
    public static void main(String[] args){
            SearchMinK test = new SearchMinK();
    
            int[] B = {9,8,7,5,4,3,2,1,6,3,4,5,12,32,3,2,1,4,6,34};
            test.getArrayMinK(B, 5);
    
        }
    

    运行结果:

    使用方法2进行部分排序后的结果:
    1 1 2 2 3 9 8 7 6 5 4 5 12 32 4 3 3 4 6 34 
    部分排序选出数组中最小的5个数:
    1 1 2 2 3 
    

    2.3 用堆代替数组法
    此处思想和2.2中一致,唯一区别就是在寻找kmax时,是使用堆排序的思想。

    具体代码如下:

    package com.liuzhen.array_2;
    
    public class SearchMinK {
    //方法3:用堆来代替数组
        /*
         * 函数功能:对数组A前k个元素进行堆排序
         */
        public void heapBottomUp(int[] A,int k){
            for(int i = (k-1)/2;i >= 0;i--){
                int temp = i;
                int tempV = A[temp];
                boolean heap = false;
                while(!heap && 2*temp < k-1){
                    int j = 2*temp + 1;
                    if(j < k-1){
                        if(A[j] < A[j+1])
                            j = j + 1;
                    }
                    if(tempV >= A[j])
                        heap = true;
                    else{
                        A[temp] = A[j];
                        temp = j;
                    }
                }
                A[temp] = tempV;
            }
        }
        
        public void getArrayMinK2(int[] A,int k){
            heapBottomUp(A,k);
            while(true){
                int count = 0;
                for(int i = k;i < A.length;i++){
                   if(A[i] < A[0]){
                       swap(A,i,0);
                      heapBottomUp(A,k);
                   }
                   else
                       count++;
                }
                if(count == A.length-k)
                    break;
            }
            System.out.println("
    "+"使用方法3进行部分堆排序后的结果:");
            for(int i = 0;i < A.length;i++)
                System.out.print(A[i]+" ");
            System.out.println("
    部分排序选出数组中最小的"+k+"个数:");
            for(int i = 0;i < k;i++)
                System.out.print(A[i]+" ");
        }
    //交换数组m位置和n位置上的值
        public void swap(int[] arrayA,int m,int n){
            int temp = arrayA[m];
            arrayA[m] = arrayA[n];
            arrayA[n] = temp;
        }
    public static void main(String[] args){
            SearchMinK test = new SearchMinK();
    
            int[] D = {9,8,7,5,4,3,2,1,6,3,4,5,12,32,3,2,1,4,6,34};
            test.getArrayMinK2(D, 5);
    
        }
    }
    

    运行结果:

    使用方法3进行部分堆排序后的结果:
    3 2 2 1 1 9 8 7 6 5 4 5 12 32 4 3 3 4 6 34 
    部分排序选出数组中最小的5个数:
    3 2 2 1 1 
    

    2.4线性选择算法
    看具体代码即可理解其中蕴含的思想。

    package com.liuzhen.array_2;
    
    public class SearchMinK {
    //返回数值result,满足:     左边部分< A[result] <=右边部分
        public int LomutoPartition(int[] A,int start,int end){
            if(start >= end)
                return start;
            int begin = A[start];
            int result = start;
            for(int i = start + 1;i <= end;i++){
                if(A[i] < begin){
                    result++;
                    swap(A,i,result);
                }
            }
            swap(A,start,result);
            return result;
        }
    
        //方法4:线性选择法
        public void getArrayMinK3(int[] A,int k){
            int start = 0;
            int end = A.length - 1;
            int tempK = LomutoPartition(A,start,end);
            while(tempK != k){
                if(tempK > k){
                    end = tempK - 1;
                    tempK = LomutoPartition(A,start,end);
                }
                if(tempK < k){
                    start = tempK + 1;
                    tempK = LomutoPartition(A,start,end);
                }
            }
            System.out.println("
    "+"使用方法4进行快速选择排序后的结果:");
            for(int i = 0;i < A.length;i++)
                System.out.print(A[i]+" ");
            System.out.println("
    部分排序选出数组中最小的"+k+"个数:");
            for(int i = 0;i < k;i++)
                System.out.print(A[i]+" ");
        }
    public static void main(String[] args){
            SearchMinK test = new SearchMinK();
    
            int[] E = {9,8,7,5,4,3,2,1,6,3,4,5,12,32,3,2,1,4,6,34};
            test.getArrayMinK3(E, 5);
        }
    }
    

    运行结果:

    使用方法4进行快速选择排序后的结果:
    1 2 2 1 3 3 3 4 5 5 4 4 6 8 6 7 9 32 12 34 
    部分排序选出数组中最小的5个数:
    1 2 2 1 3 
    

    此处附上四种方法的完整代码

    package com.liuzhen.array_2;
    
    public class SearchMinK {
        //方法1:全部排序
        public void quickSort(int[] A,int start,int end){
            if(end > start){
                int k = LomutoPartition(A,start,end);
                quickSort(A,start,k-1);
                quickSort(A,k+1,end);
            }
        }
        //返回数值result,满足:     左边部分< A[result] <=右边部分
        public int LomutoPartition(int[] A,int start,int end){
            if(start >= end)
                return start;
            int begin = A[start];
            int result = start;
            for(int i = start + 1;i <= end;i++){
                if(A[i] < begin){
                    result++;
                    swap(A,i,result);
                }
            }
            swap(A,start,result);
            return result;
        }
        //交换数组m位置和n位置上的值
        public void swap(int[] arrayA,int m,int n){
            int temp = arrayA[m];
            arrayA[m] = arrayA[n];
            arrayA[n] = temp;
        }
        //输出数组前k个元素
        public void printArrayK(int[] array,int k){
            for(int i = 0;i < k;i++){
                System.out.print(array[i]+" ");
            }
        }
        
        //方法2:部分排序
        public void getArrayMinK(int[] A,int k){
            if(k > A.length)
                return;
            while(true){
                int max = getMaxArrayK(A,k);  //当前数组前k个元素中的最大值
                int count = 0;
                for(int i = k;i < A.length;i++){
                    if(A[max] > A[i])
                        swap(A,max,i);
                    else
                        count++;
                }
                if(count == A.length-k)
                    break;
            }
            System.out.println("
    "+"使用方法2进行部分排序后的结果:");
            for(int i = 0;i < A.length;i++)
                System.out.print(A[i]+" ");
            System.out.println("
    部分排序选出数组中最小的"+k+"个数:");
            for(int i = 0;i < k;i++)
                System.out.print(A[i]+" ");
        }
        
        //获取数组前k个元素的最大值的数组下标
        public int getMaxArrayK(int[] A,int k){
            int result = 0;
            if(k > A.length)
                return 0;
            for(int i = 0;i < k;i++){
                if(A[i] > A[result])
                    result = i;
            }
            return result;
        }
        
        //方法3:用堆来代替数组
        /*
         * 函数功能:对数组A前k个元素进行堆排序
         */
        public void heapBottomUp(int[] A,int k){
            for(int i = (k-1)/2;i >= 0;i--){
                int temp = i;
                int tempV = A[temp];
                boolean heap = false;
                while(!heap && 2*temp < k-1){
                    int j = 2*temp + 1;
                    if(j < k-1){
                        if(A[j] < A[j+1])
                            j = j + 1;
                    }
                    if(tempV >= A[j])
                        heap = true;
                    else{
                        A[temp] = A[j];
                        temp = j;
                    }
                }
                A[temp] = tempV;
            }
        }
        
        public void getArrayMinK2(int[] A,int k){
            heapBottomUp(A,k);
            while(true){
                int count = 0;
                for(int i = k;i < A.length;i++){
                   if(A[i] < A[0]){
                       swap(A,i,0);
                      heapBottomUp(A,k);
                   }
                   else
                       count++;
                }
                if(count == A.length-k)
                    break;
            }
            System.out.println("
    "+"使用方法3进行部分堆排序后的结果:");
            for(int i = 0;i < A.length;i++)
                System.out.print(A[i]+" ");
            System.out.println("
    部分排序选出数组中最小的"+k+"个数:");
            for(int i = 0;i < k;i++)
                System.out.print(A[i]+" ");
        }
        
        //方法4:线性选择法
        public void getArrayMinK3(int[] A,int k){
            int start = 0;
            int end = A.length - 1;
            int tempK = LomutoPartition(A,start,end);
            while(tempK != k){
                if(tempK > k){
                    end = tempK - 1;
                    tempK = LomutoPartition(A,start,end);
                }
                if(tempK < k){
                    start = tempK + 1;
                    tempK = LomutoPartition(A,start,end);
                }
            }
            System.out.println("
    "+"使用方法4进行快速选择排序后的结果:");
            for(int i = 0;i < A.length;i++)
                System.out.print(A[i]+" ");
            System.out.println("
    部分排序选出数组中最小的"+k+"个数:");
            for(int i = 0;i < k;i++)
                System.out.print(A[i]+" ");
        }
        public static void main(String[] args){
            SearchMinK test = new SearchMinK();
            int[] A = {9,8,7,5,4,3,2,1,6,3,4,5,12,32,3,2,1,4,6,34};
            test.quickSort(A, 0, A.length-1);
            System.out.println("对数组进行排序后结果:");
            for(int i = 0;i < A.length;i++)
                System.out.print(A[i]+" ");
            System.out.println("
    "+"输出数组最小的5个数:");
            test.printArrayK(A, 5);
            int[] B = {9,8,7,5,4,3,2,1,6,3,4,5,12,32,3,2,1,4,6,34};
            test.getArrayMinK(B, 5);
            int[] C = {2,9,7,6,5,8};
            test.heapBottomUp(C, 6);
            System.out.println("
    C数组:");
            for(int i = 0;i < C.length;i++)
                System.out.print(C[i]+" ");
            int[] D = {9,8,7,5,4,3,2,1,6,3,4,5,12,32,3,2,1,4,6,34};
            test.getArrayMinK2(D, 5);
            int[] E = {9,8,7,5,4,3,2,1,6,3,4,5,12,32,3,2,1,4,6,34};
            test.getArrayMinK3(E, 5);
        }
    }
    
    完整代码
    
  • 相关阅读:
    SAP OPEN UI5 Step 8: Translatable Texts
    SAP OPEN UI5 Step7 JSON Model
    SAP OPEN UI5 Step6 Modules
    SAP OPEN UI5 Step5 Controllers
    SAP OPEN UI5 Step4 Xml View
    SAP OPEN UI5 Step3 Controls
    SAP OPEN UI5 Step2 Bootstrap
    SAP OPEN UI5 Step1 环境安装和hello world
    2021php最新composer的使用攻略
    Php使用gzdeflate和ZLIB_ENCODING_DEFLATE结果gzinflate报data error
  • 原文地址:https://www.cnblogs.com/a1439775520/p/13077956.html
Copyright © 2011-2022 走看看