找出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都很大時,這種算法比前兩種算法要快很多。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM