zoukankan      html  css  js  c++  java
  • 找出N个数中最小的k个数问题(复杂度O(N*logk))

    这是一个经典的算法题,下面给出的算法都在给定的数组基础上进行,好处时不用分配新的空间,坏处是会破坏原有的数组,可以自己分配新的空间以避免对原有数组的破坏。

    思路一

    先直接排序,再取排序后数据的前k个数。

    排序算法用最快的堆排序,复杂度也会达到O(N*logN).

    void filterDown(int* disorder, int pos, int size){
        int temppos=pos,temp=0;
        while(temppos<size/2){
            if(2*temppos+2<size){
                if(disorder[2*temppos+1]>disorder[2*temppos+2]){
                    if(disorder[temppos]<disorder[2*temppos+1]){
                        temp=disorder[temppos];
                        disorder[temppos]=disorder[2*temppos+1];
                        disorder[2*temppos+1]=temp;
                        temppos=2*temppos+1;
                    }
                    else{
                        break;
                    }
                }
                else{
                    if(disorder[temppos]<disorder[2*temppos+2]){
                        temp=disorder[temppos];
                        disorder[temppos]=disorder[2*temppos+2];
                        disorder[2*temppos+2]=temp;
                        temppos=2*temppos+2;
                    }
                    else{
                        break;
                    }
                }
            }
            else if(disorder[temppos]<disorder[2*temppos+1]){
                temp=disorder[temppos];
                disorder[temppos]=disorder[2*temppos+1];
                disorder[2*temppos+1]=temp;
                temppos=2*temppos+1;
            }
            else{
                break;
            }
    
        }
    }
    void heapSort(int* disorder, int size){
        int bottomRowSize=2;
        while(bottomRowSize<size){
            bottomRowSize*=2;
        }
        int temp=0,i=0;
        for(int j=size/2-1;j>=0;j--){
            filterDown(disorder, j, size);
        }
        for(int j=size-1;j>0;j--){
            temp=disorder[0];
            disorder[0]=disorder[j];
            disorder[j]=temp;
            filterDown(disorder,0,j);
        }
    }
    int _tmain(int argc, _TCHAR* argv[])
    {
        const int size=200;
        const int maxnum = 10000;
        const int k=10;
        int* disorder=new int[size];
        srand((unsigned) time(NULL)); 
        for(int i=0;i<size;i++){
            disorder[i]=rand()%maxnum;    
        }
        heapSort(disorder,size);
        for(int i=0;i<k;i++){
            cout<<disorder[i]<<endl;
        }
        return 0;
    }

    当k接近于N时,可以用这种算法。

    思路二

    先排序前k个数,对于后面N-k个数,依次进行插入。

    时间复杂度为O(k*n)

    void insertSort(int* disorder, int size){
        int temp=0,i=0;
        for(int j=1;j<size;j++){
            temp=disorder[j];
            for(i=j;i>0;i--){
                if(temp<disorder[i-1]){
                    disorder[i] = disorder[i-1];
                }
                else{
                    break;
                }
            }
            disorder[i]=temp;
        }
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        const int size=200;
        const int maxnum = 10000;
        const int k=10;
        int* disorder=new int[size];
        srand((unsigned) time(NULL)); 
        int i=0,temp;
        for(;i<size;i++){
            disorder[i]=rand()%maxnum;    
        }
        insertSort(disorder,k);
        for(int j=k;j<size;j++){
            temp=disorder[j];
            for(i=k-1;i>=0;i--){
                if(temp<disorder[i]){
                    disorder[i+1] = disorder[i];
                }
                else{
                    break;
                }
            }
            disorder[i+1]=temp;
        }
    
        for(int i=0;i<k;i++){
            cout<<disorder[i]<<endl;
        }
        return 0;
    }

    当k很小时,可以用这种算法

    思路三

    对前k个数,建立最大堆,对于后面N-k个数,依次和最大堆的最大数比较,如果小于最大数,则替换最大数,并重新建立最大堆。

    时间复杂度为O(N*logk)

    void filterDown(int* disorder, int pos, int size){
        int temppos=pos,temp=0;
        while(temppos<size/2){
            if(2*temppos+2<size){
                if(disorder[2*temppos+1]>disorder[2*temppos+2]){
                    if(disorder[temppos]<disorder[2*temppos+1]){
                        temp=disorder[temppos];
                        disorder[temppos]=disorder[2*temppos+1];
                        disorder[2*temppos+1]=temp;
                        temppos=2*temppos+1;
                    }
                    else{
                        break;
                    }
                }
                else{
                    if(disorder[temppos]<disorder[2*temppos+2]){
                        temp=disorder[temppos];
                        disorder[temppos]=disorder[2*temppos+2];
                        disorder[2*temppos+2]=temp;
                        temppos=2*temppos+2;
                    }
                    else{
                        break;
                    }
                }
            }
            else if(disorder[temppos]<disorder[2*temppos+1]){
                temp=disorder[temppos];
                disorder[temppos]=disorder[2*temppos+1];
                disorder[2*temppos+1]=temp;
                temppos=2*temppos+1;
            }
            else{
                break;
            }
    
        }
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        const int size=200;
        const int maxnum = 10000;
        const int k=10;
        int* disorder=new int[size];
        srand((unsigned) time(NULL)); 
        int i=0,temp;
        for(;i<size;i++){
            disorder[i]=rand()%maxnum;    
        }
        for(int j=k/2-1;j>=0;j--){
            filterDown(disorder, j, k);
        }
        for(int j=k;j<size;j++){
            if(disorder[j]<disorder[0]){
                disorder[0]=disorder[j];
                filterDown(disorder,0,k);
            }
        }
        for(int j=k-1;j>0;j--){
            temp=disorder[0];
            disorder[0]=disorder[j];
            disorder[j]=temp;
            filterDown(disorder,0,j);
        }
        for(int i=0;i<k;i++){
            cout<<disorder[i]<<endl;
        }
        return 0;
    }

     当k和N都很大时,这种算法比前两种算法要快很多。

  • 相关阅读:
    Android高斯模糊技术,实现毛玻璃效果(转)
    设计模式笔记之六:生产消费者模式
    设计模式笔记之五:观察者模式
    设计模式笔记之四:MVP+Retrofit+RxJava组合使用
    设计模式笔记之三:Android DataBinding库(MVVM设计模式)
    Eclipse Code Recommenders 自动补全(联想)神器
    java根据freeMark模板生成内容
    通过java反射机制,获取对象的属性和值(包括所有继承的父类)
    win7下自动更新svn目录
    jdk11 eclipse下开启ZGC
  • 原文地址:https://www.cnblogs.com/studynote/p/3404873.html
Copyright © 2011-2022 走看看