运行时间具有对数性质的几种算法
对分查找算法
给定一个整数 X 和整数 A 0 A_{0} A0, A 1 A_{1} A1, A 2 A_{2} A2……, A N − 1 A_{N-1} AN−1,后者已经预先排序并在内存中,求使得 A i A_{i} Ai=X 的下标 i ;如果 X 不在数据中,则返回-1.
int BinarySearch( const ElementType A[], ElementType x, int N)
{
int low, mid, high;
low = 0; high = N-1;
while( low <= high )
{
mid=( low + high )/2;
if( A[mid] < x)
low = mid + 1;
else
{
if( A[mid] > x)
high = mid -1;
else
return mid;
}
}
return -1;
}
显然,每次迭代再循环内的所有工作花费为O(1), 因此分析需要确定循环的次数。循环从 high - low = N-1 开始;到 high - low >= -1 结束。每次循环后 high - low的值减少一半,于是循环次数最多为[ log(N-1) ] + 2。
例如,若 high - low = 128, 则在各次迭代后 high - low 的最大值为64,32,16,8,4,2,1,0,-1。
因此,运行时间是O( logN )。
欧几里得算法
给定两个整数 M , N ,求 M , N 的最大公因数。
unsigned int Gcd( unsigned int M, unsigned int N )
{
unsigned int Rem;
while( N > 0 )
{
Rem = M % N;
M = N;
N = Rem;
}
return M;
}
因为余数不会超过原始值的一半,所以运行时间也是O( logN )。
冥运算
计算
x
n
x^n
xn。(假设机器能够存储足够大的数)
注:如果n是偶数,则
x
n
x^n
xn =
x
n
2
x^\frac{n}{2}
x2n *
x
n
2
x^\frac{n}{2}
x2n,如果n是奇数,那么
x
n
x^n
xn =
x
n
−
1
2
x^\frac{n-1}{2}
x2n−1 *
x
n
−
1
2
x^\frac{n-1}{2}
x2n−1 * x。
long int Pow( long int x, unsigned int n)
{
if( n == 0 )
return 1;
if( n == 1 )
return x;
if( IsEven ( n ) ) /* 判断是否是偶数 */
return Pow( x * x, n / 2 ); /* 用x*x做参数,能提高效率 */
else
return Pow( x * x, n / 2) * x;
}
例如,为了计算
x
62
x^{62}
x62,算法将如下进行,它只用到9次乘法:
x
3
x^3
x3 = (
x
2
x^2
x2 ) * x,
x
7
x^7
x7 =
(
x
3
)
2
{ (x^3) }^2
(x3)2 * x,
x
15
x^{15}
x15 =
(
x
7
)
2
{ (x^7) }^2
(x7)2 * x
x
31
x^{31}
x31 =
(
x
15
)
2
{( x^{15} )}^2
(x15)2 * x,
x
62
x^{62}
x62 =
(
x
32
)
2
{( x^{32} )}^2
(x32)2
显然,所需要的乘法次数最多是2logn; 因为把问题分半最多需要两次乘法(如果n是奇数)。