寻找最小的k个数

1. 能想到的最直接的办法,就是对数组进行排序,最好的排序算法的时间复杂性为O(n*logn),这一个方法请参照各种排序算法。

2. 另外申请一个k空间数组,依次更改里面的最大值,每做一次最多要扫描一下这个K大小的空间(如果比上一次的最大值大的话,就不用扫描了,所以这里说是“最多”),整体时间复杂度为O((n-k)*k),实现代码如下:

 

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int initData(int test[],int len);
int printArray(int test[],int len);
int maxOfArray(int test[],int k);
int selectElement(int test[],int len,int k);

int main()
{
    const int arraySize=100;
    const int k=20;
    int test[arraySize];
    initData(test,arraySize);
    printArray(test,arraySize);
    selectElement(test,arraySize,k);
    printArray(test,k);
    return 0;
}
int selectElement(int test[],int len,int k)
{
    int maxIndex=maxOfArray(test,k);
    for(int i=k;i<len;i++)
    {
        int tmp=test[maxIndex];
        if(tmp>test[i])
        {
            test[maxIndex]=test[i];
            maxIndex=maxOfArray(test,k);
        }
    }
    return 0;
}
int maxOfArray(int test[],int k)
{
    int index=0;
    int tmp=test[0];
    for(int i=1;i<k;i++)
    {
        if(test[i]>tmp)
        {
            index=i;
            tmp=test[i];
        }
    }
    return index;
}
int initData(int test[],int len)
{
    srand(time(NULL));
    for(int i=0;i<len;i++)
    {
        test[i]=rand()%20;
    }
    return 0;

}
int printArray(int test[],int len)
{
    for(int i=0;i<len;i++)
    {
        cout<<test[i]<<"\t";
    }
    cout<<endl;
    return 0;
}

3.第三种方式是建立一个k大小的极大堆,每一次将数据与堆头的元素比较,如果比它小,则替换之,然后更新堆的结构,除去构建堆的时间,时间复杂度为:O((n-k)*logk),代码如下:

 

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;


int initData(int test[],int len);
int printArray(int test[],int len);
int maxHeap(int test[],int i,int k);//i为下标
int buildHeap(int test[],int arraySize,int k);
int selectElement(int test[],int arraySize,int k);
int main()
{
    const int arraySize=20;
    const int k=5;
    int test[arraySize];
    initData(test,arraySize);
    printArray(test,arraySize);
    buildHeap(test,arraySize,k);
    printArray(test,arraySize);
    selectElement(test,arraySize,k);
    printArray(test,arraySize);
    return 0;
}
int selectElement(int test[],int arraySize,int k)
{
    for(int i=k;i<arraySize;i++)
    {
        if(test[i]<test[0])
        {
            test[0]=test[i];
            maxHeap(test,0,k);
        }
    }
    return 0;
}
int buildHeap(int test[],int arraySize,int k)
{
    for(int i=arraySize/2-1;i>=0;i--)
    {
        maxHeap(test,i,k);
    }
    return 0;
}
int maxHeap(int test[],int i,int k)//i为下标
{
    int least=i;
    int left=(i+1)*2-1;
    int right=(i+1)*2;
    if(left<k&&test[left]>test[least])
        least=left;
    if(right<k&&test[right]>test[least])
        least=right;
    if(least!=i)
    {
        test[i]=test[i]+test[least];
        test[least]=test[i]-test[least];
        test[i]=test[i]-test[least];
        maxHeap(test,least,k);
    }
    return 0;
}
int initData(int test[],int len)
{
    srand(time(NULL));
    for(int i=0;i<len;i++)
    {
        test[i]=rand()%20;
    }
    return 0;

}
int printArray(int test[],int len)
{
    for(int i=0;i<len;i++)
    {
        cout<<test[i]<<"\t";
    }
    cout<<endl;
    return 0;
}

 对堆不了解的这里插入一个3D动画http://www.benfrederickson.com/2013/10/10/heap-visualization.html

4. 第四种方法是借鉴快速排序的partition过程,partition做完后,假设返回的下标是k,那么我们确定k之前的元素都比k下标的元素要小,依次不断递归下去,时间复杂度是O(n),实现代码如下:

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int partition(int test[],int p,int r);
int selectElements(int test[],int p,int r,int k);//前k个最小元素;
int initData(int test[],int len);
int printArray(int test[],int len);


int main()
{
    const int arraySize=10;
    const int k=5;
    int test[arraySize];
    initData(test,arraySize);

    printArray(test,arraySize);
    selectElements(test,0,arraySize-1,k);
    printArray(test,arraySize);
    return 0;
}
int selectElements(int test[],int p,int r,int k)//前k个最小元素
{
    if(p<=r)
    {
        int partIndex=partition(test,p,r);
        int len=partIndex-p+1;
        if(len==k)
            return 0;
        else if(len<k)
        {
            selectElements(test,partIndex+1,r,k-len);
        }
        else
        {
            selectElements(test,p,partIndex-1,k);
        }
    }
    return 0;
}
int partition(int test[],int p,int r)
{
        int flagValue=test[r];
        int k=p-1;
        for(int i=p;i<r;i++)
        {
            if(test[i]<flagValue)
            {
                k++;
                /*
                test[i]=test[k]+test[i];test[k]与test[i]是同一块区域的话,这样会把数据清0
                test[k]=test[i]-test[k];
                test[i]=test[i]-test[k];
                */
                int tmp=test[k];
                test[k]=test[i];
                test[i]=tmp;
            }
        }
        k++;
        test[r]=test[k];
        test[k]=flagValue;
        return k;

}
int initData(int test[],int len)
{
    srand(time(NULL));
    for(int i=0;i<len;i++)
    {
        test[i]=rand()%20;
    }
    return 0;

}
int printArray(int test[],int len)
{
    for(int i=0;i<len;i++)
    {
        cout<<test[i]<<"\t";
    }
    cout<<endl;
    return 0;
}

 

 

 

 

 

posted @ 2014-03-14 13:35  很厉害的名字  阅读(241)  评论(0编辑  收藏  举报