【数据结构与算法】第二章:算法分析
第二章:算法分析
2.1数学知识预备
四个定义:
- 大 记法:如果存在正常数 和 使得当 时 ,则记为 .
- 如果存在正常数 和 使得当 时 ,则记为 .
- ,当且仅当 且 .
- 如果 且 ,则记作 .
在大 记法中, 是 的一个下界, 是 的一个上界.
性质:
- 如果 且 那么a) b)
- 如果 是一个 次多项式,那么有 .
- 对于任意常数k, .
常见增长率
函数 | 名称 |
---|---|
常数 | |
常数 | |
对数 | |
对数平方根 | |
线性 | |
对数平方根 |
2.2模型
- 假定模型机做任何一件简单的工作都恰好花费一个时间单元.
- 为合理起见,我们假定我们的模型都有固定范围的整数,并且不存在矩阵求逆或排序等运算.
- 假定模型机有无限的内存.
2.3要分析的问题
- 运行时间
- 平均时间:
- 最坏时间:
注,一般而言
2.4运行时间计算
2.4.1 一般法则
- FOR循环:运行时间至多是该循环内语句的运行时间乘上迭代次数.
- 嵌套的FOR循环:在嵌套的循环内部的一条语句的总的运行时间是该语句乘以该组所有的for循环的大小的乘积.
- 顺序语句:将各个语句的运算时间求和.
- if-else语句:不超过判断加分支中运算时间长者的总的运行时间.
2.4.2 例题
- 最大子序列和问题
给定正整数 求 的最大值(若所给的整数均为负数,则最大子序列的和为0).
输入样例: -2, 11, -4, 13, -5, -2
输出结构: 20 (从 到 )
/* 算法1:穷举法 */
int MaxSubsequenceSum_1( const int A[], int N){
int ThisSum, MaxSum, i, j, k;
MaxSum = 0;
for( i=0; i<N; i++){
for( j=i; j<N; j++){
ThisSum = 0;
for( k=i; k<=j; k++)
ThisSum += A[k];
if( ThisSum > MaxSum)
MaxSum = ThisSum;
}
}
return MaxSum;
}
/* 算法2:算法1的改进版 */
int MaxSubsequenceSum_2( const int A[], int N){
int ThisSum, MaxSum, i, j;
MaxSum = 0;
for( i=0; i<N; i++){
ThisSum = 0;
for( j=i; j<N; j++){
ThisSum += A[j];
if( ThisSum > MaxSum)
MaxSum = ThisSum;
}
}
return MaxSum;
}
/* 算法3:分治策咯 */
int MaxSubsequenceSum_3( const int A[], int Left, int Right){
int MaxLeftSum, MaxRightSum;
int MaxLeftBorderSum, MaxRightBorderSum;
int LeftBorderSum, RightBorderSum;
int Center, i;
if( Left == Right){ //Base Case
if( A[Left] > 0)
return A[Left];
else
return 0;
}
Center = ( Left + Right) /2;
MaxLeftSum = MaxSubsequenceSum_3( A, Left, Center);
MaxRightSum = MaxSubsequenceSum_3( A, Center + 1, Right);
//Both Side MaxSum
MaxLeftBorderSum = 0; LeftBorderSum = 0;
for( i = Center; i >= Left; i--){
LeftBorderSum += A[i];
if( LeftBorderSum > MaxLeftBorderSum)
MaxLeftBorderSum = LeftBorderSum;
}
MaxRightBorderSum = 0; RightBorderSum = 0;
for( i = Center + 1; i <= Right; i++){
RightBorderSum += A[i];
if( RightBorderSum > MaxRightBorderSum)
MaxRightBorderSum = RightBorderSum;
}
int SideMaxSum = MaxLeftSum > MaxRightSum ? MaxLeftSum : MaxRightSum;
int BorderMaxSum = MaxRightBorderSum + MaxLeftBorderSum;
return SideMaxSum > BorderMaxSum ? SideMaxSum : BorderMaxSum;
}
/* 算法4 */
int MaxSubsequenceSum_4( const int A[], int N){
int ThisSum, MaxSum, i;
ThisSum = MaxSum = 0;
for( i=0; i<N; i++){
ThisSum += A[i];
if( ThisSum > MaxSum)
MaxSum = ThisSum;
else if( ThisSum < 0)
ThisSum = 0;
}
return MaxSum;
}
2.4.3 运行时间中的对数
- 对数出现的一般法则:
如果一个算法用常数时间 将问题的大小削减为其一部分(通常是 ,那么该算法的时间复杂度就是 .另一方面,如果使用常数时间只是把问题减少一个常数 ,那么这个算法就是 的.
对分查找
给定一个整数 和整数 ,后者已经预先排序并在内存中,求使得 的下标 ,如果X不在数据中,则返回 .最简单的便是线性查找,时间复杂度为 ,
- 对分查找
int BinarySearch( int A[], int X, int N){
int Low, Mid, High;
Low = 0;
High = N - 1;
while( Low <= High){
Mid = (Low + High) / 2;
if( A[Mid] == X)
return Mid;
else if( A[Mid] < X)
Low = Mid + 1;
else if( A[Mid] > X)
High = Mid - 1;
}
return NotFound;
}
- 欧几里得算法
欧几里得算法是计算最大公因数的算法.两个数的最大公因数Gcd是同时整除二者的最大整数.例如Gcd(50,15)=5.
对于正整数M,N.假设M>N则必然有 M mod N < M/2.
//假设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;
}
- 幂运算
假设机器的内存足够大.计算 的一般方法是使用N-1次乘法.
long int Pow( long int X, unsigned int N){
if( N == 0)
return 1;
if( N == 1)
return X;
if( N % 2 == 0) //X是偶数
return Pow( X*X, N/2);
else
return Pow( X*X, N/2) * X;
}