找出N个数中最小的k个数问题(复杂度O(N*logk))

原文链接:http://www.cnblogs.com/studynote/p/3404873.html

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

思路一

先直接排序,再取排序后数据的前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都很大时,这种算法比前两种算法要快很多。



作者: Jingle Guo
出处: http://www.cnblogs.com/studynote/
若标题中有“转载”字样,则本文版权归原作者所有。若无转载字样,本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用矩阵快速幂算法,其时间复杂度为O(n^3*logk)。 具体实现步骤如下: 1.定义一个矩阵结构体,包含矩阵的行数、列数和数据数组。 2.实现矩阵乘法运算函数matrix_multiply(),接受两个矩阵作为参数,返回它们的乘积矩阵。 3.实现矩阵快速幂算法power_matrix(),接受一个矩阵和一个整数k作为参数,返回矩阵的k次幂。 4.在power_matrix()函数,先判断k的大小,当k为1时直接返回原矩阵;当k为偶数时,将原矩阵的半次幂矩阵相乘即可得到k次幂矩阵;当k为奇数时,先计算原矩阵的半次幂矩阵,再将其与原矩阵相乘,即可得到k次幂矩阵。 代码如下: ```c #include<stdio.h> #include<stdlib.h> /* 定义矩阵结构体 */ typedef struct { int row; // 矩阵的行数 int col; // 矩阵的列数 int **data; // 矩阵的数据数组 } Matrix; /* 矩阵乘法 */ Matrix matrix_multiply(Matrix m1, Matrix m2) { Matrix res; res.row = m1.row; res.col = m2.col; res.data = (int**)malloc(res.row * sizeof(int*)); for(int i=0; i<res.row; i++) { res.data[i] = (int*)malloc(res.col * sizeof(int)); for(int j=0; j<res.col; j++) { res.data[i][j] = 0; for(int k=0; k<m1.col; k++) { res.data[i][j] += m1.data[i][k] * m2.data[k][j]; } } } return res; } /* 矩阵快速幂 */ Matrix power_matrix(Matrix m, int k) { if(k == 1) { return m; } Matrix half_res = power_matrix(m, k/2); if(k % 2 == 0) { return matrix_multiply(half_res, half_res); } else { return matrix_multiply(matrix_multiply(half_res, half_res), m); } } int main() { int n = 3; // 矩阵的行数和列数 int k = 3; // 矩阵的次幂 Matrix m; m.row = n; m.col = n; m.data = (int**)malloc(n * sizeof(int*)); for(int i=0; i<n; i++) { m.data[i] = (int*)malloc(n * sizeof(int)); } // 初始化矩阵 m.data[0][0] = 1; m.data[0][1] = 2; m.data[0][2] = 3; m.data[1][0] = 4; m.data[1][1] = 5; m.data[1][2] = 6; m.data[2][0] = 7; m.data[2][1] = 8; m.data[2][2] = 9; Matrix res = power_matrix(m, k); // 打印矩阵的k次幂 for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { printf("%d ", res.data[i][j]); } printf("\n"); } // 释放内存 for(int i=0; i<n; i++) { free(m.data[i]); free(res.data[i]); } free(m.data); free(res.data); return 0; } ``` 注意:以上代码,矩阵数据类型为整数,如果是实数,则需要将矩阵乘法运算的加法和乘法改为实数的加法和乘法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值