首页 > 其他 > 详细

几个时间复杂度O(logN)的算法

时间:2014-02-26 21:21:57      阅读:672      评论:0      收藏:0      [点我收藏+]

1 二分查找算法

bubuko.com,布布扣
int BinarySearch(const ElementType A[], ElementType X, int N)
{
    int mid, right, left;
    right = 0;
    left = N - 1;

    while(right <= left){           // 不断更新左右边界的索引(实质是每次循环将待查元素减半,实现了O(logN)时间复杂度),直到左索引大于右索引
        mid = (right + left)/2;
        if(A[mid] > X)
            left = mid - 1;
        else if(A[mid] < X)
            right = mid + 1;
        else
            return mid;
    }
    return -1;
}
bubuko.com,布布扣

二分查找算法适合:只需查找,不需要插入(O(N)复杂度?)和删除的情况。如查询元素周期表这种较稳定的数据。

2 欧几里德算法(求最大公因数)

bubuko.com,布布扣
 1 unsigned int Gcd(unsigned int M, unsigned int N)
 2 {
 3     unsigned int Rem;
 4      
 5     while(N > 0){
 6         Rem = M % N;
 7         M = N;
 8         N = Rem;
 9     }           
10     
11     return M;
12 }
bubuko.com,布布扣

若M > N,则第一次循环交换M和N。

若想分析其时间复杂度,则要求循环次数,即生成余数的次数。

可以证明: 当M > N, 则M % N < M / 2

证明:当N <= M/2 时,M % N < M / 2

         当N > M/2时,M - N < M / 2,那么也有M % N < M/2. 

   结论成立。

由此可得:有M、N(M>N)两个正整数,第一次循环后其余数小于M/2,第二次循环后其余数小于N/2,所以可以说,每两次循环后,余数最多为原值的一半。

所以最大的求余次数为2logN = O(logN).

2logN并不精确,即使在最坏的情况(如M、N是相邻的fibonacci数)下,仍然可被优化为1.44logN(每次M和余数的商为1.618,则求余的次数为N关于1.618的对数,即1.44logN)。欧几里德算法的平均性能需要大量篇幅的精确计算,迭代次数的平均值约为(12ln2 lnN) / π^2+1.47。

3 求幂

最简单的递推公式:Xn = Xn-1 * X;

         X0 = 1;

需要Θ(n)步和Θ(n)空间

还可以: Xn = X n/2 * X n/2 = (X * X)n/2    X is even

     X= X(n-1)/2 * X(n-1)/2  * X = (X * X)(n-1)/2 * X     X is odd

bubuko.com,布布扣
long int Pow(long int X,unsigned int N)
{
    if(N == 0)
        return 1;if(N % 2 == 1)
        return Pow(X * X, N/2);
    else
        return Pow(X * X, (N-1)/2) * X;
}
bubuko.com,布布扣

需要Θ(logN)步和Θ(logN)空间。

还可以:Xn = X n/2 * X n/2     X is even

    Xn = Xn-1 * X          X is odd

 
bubuko.com,布布扣
1 long int Pow(long int X, unsigned int N)
2 {
3     if(N == 0)
4         return 1;
5     if(N % 2 == 0)
6         return Pow(X*X, N/2);
7     else
8         return Pow(X, N-1) * X;
9 }   
bubuko.com,布布扣

 

需要Θ(logN)步和Θ(logN)空间。

在不影响正确性的前提下对代码进行微调是很有趣的。

如对第六行的修改:

1) return Pow(Pow(X,2), N/2);

看上去正确,但当N=2时,return Pow(Pow(X,2),1)调用Pow(X,2),Pow(X,2)继续调用Pow(X,2),每次递归没有向基准情况推进,无限循环直到崩溃。

2) return Pow(Pow(X, N/2), 2);

看上去正确,但当N = 2时, 调用Pow(X,2),再调用Pow(X,2)...,同(1).

3) return Pow(X, N/2) * Pow(X, N/2);

正确,但影响效率。

每次调用都有两次递归。则总步数为20 + 21 + 22 + ... 2logN  = 2logN+1 -1

则需O(2logN)步和O(2logN)空间。(待验证)

几个时间复杂度O(logN)的算法,布布扣,bubuko.com

几个时间复杂度O(logN)的算法

原文:http://www.cnblogs.com/ithink/p/3567129.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!