赞
踩
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
printf("csdn");
}
}
n的值 | 10 | 100 | 1000 | 10000 | n |
---|---|---|---|---|---|
执行次数 | 100 | 10000 | 1000000 | 100000000 | n2 |
从这可以看出这个算法时间的复杂度为n2(O(n2))
for (i = 0; i < n; i++)
{
for (j = i; j < n; j++)
{
printf("csdn");
}
}
n的取值 | 10 | 100 | 1000 | 10000 | n |
---|---|---|---|---|---|
执行次数 | 10+9 + … + 1 | 100 + 99 + … + 1 | 1000 + 999 + … + 1 | 10000 + 9999+ … + 1 | 1 2 {1}\over{2} 21n2+ 1 2 \frac{1}{2} 21n |
在计算时间复杂度时,省略较小的项,去掉常数,只保留最高阶。故这个算法的时间复杂度也是n2(O(n2))
for (i = 1; i < n; i *= 2)
{
printf("csdn");
}
n的取值 | 8 | 16 | 512 | 1024 | n |
---|---|---|---|---|---|
执行次数 | 3 | 4 | 9 | 10 | log2n |
在计算语句执行次数时,会发现语句的执行次数与n的值和后面的i *= 2
有关;而且可以发现他们的关系为以2为底的对数关系。可以发现执行次数 = log~2~n
。
去掉常数2 。得到时间复杂度为logn(O(logn))。
举一个简单的例子:
计算从i = 1
开始,每次i
增加1
后的 i3的连续和;
(i = 1) (N)∑ i3
int sum(int N)
{
/*1*/ int i, partialSum = 0;
/*2*/ for (i = 0; i <= N; i++)
/*3*/ partialSum += i * i * i;
/*4*/ return partialSum;
}
第一行和第4行各占一个时间单元,第3行占4个时间单元(一次赋值,一次加法,两次乘法)
N的大小 | 5 | 10 | 20 | n |
---|---|---|---|---|
执行次数 | 4 * 5 + 2 | 4 * 10 + 2 | 4 * 20 + 2 | 4 * n + 2 |
省略掉常数后,得到的时间复杂度为n (O(n))。
for(i = 0; i < N; i++)
printf("csdn");
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
printf("scdn");
在这个语句中先去掉较小的O(N), 在花费O(N2),总的花销也就是O(N2);
if(Condition)
S1;
else
S2;
一个if / else 语句的运行时间,从不超过判断的时间 加上 S1与S2中运行时间较长的总的运行时间。
分析的策略基本都是从内部(或者最深层次)向外扩展开的。如果有函数调用,那么这些函数调用要最先分析。
如果有递归过程,那么存在这么几种选择
long int
factorial(int N)
{
if (N <= 1)
return 1;
else
return N * factorial (N - 1);
}
不难看出这个算法的时间的复杂度为O(N)。
long int
Fib(int N)
{
if (N <= 1)
return 1;
else
return Fib(N - 1) + Fib(N - 2);
}
可以证明(
5
3
{5}\over{3}
35)N >= Fib(N) >= (
3
2
{3}\over{2}
23)N
这个时间复杂度是个指数,是最坏的情况。违反了第四条基本法则。
注释:递归调用的四条基本法则
计算给出的一个数列中划分的各个子数列中最大的那个值。
int MaxSubsequenceSum(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; }
不难看出这个算法的时间复杂度为O(n3)
为我们可以进行一步优化,将最外部的循环删去会发现他并不会影响结果。因此可以得到:
int MaxSubsequenceSum (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; }
新的算法的时间复杂度不难看出为O(n2)。在数列数字个数很多的时候显然这个新的算法更具有优势。
有时候递归和二分的运用能够大幅度的优化时间复杂度,在这里有一个很好的例子:
int Max3(int a, int b, int c) { int max = 0; if (a > b) max = a; else max = b; if (max > c) max = max; else max = c; return max; } int MaxSubSum(const int A[], int left, int Right) { int MaxLeftSum, MaxRightSum; int MaxLeftBorderSum, MaxRightBorderSum; int LeftBorderSum, RightBorderSum; int Center, i; if (Left == Right) if (A[Left] > 0) return A[Left]; else return 0; Center = (Left + Right) / 2; MaxLeftSum = MaxSubSum(A, Left, Center); MaxRightSum = MaxSubSum(A, Center + 1, Right); MaxLeftBorderSum = 0; LeftBorderSum = 0; for (i = center, i >= Left; i--) { LeftBorderSum += A[i]; if (LeftBorder > MaxLeftBorderSum) MaxLeftBorderSum = LeftBorderSum; } MaxRightBorderSum = 0; RightBorderSum = 0; for (i = center + 1; i <= Right; i++) { RightBorderSum += A[i]; if (RightBorderSum > MaxRightBorderSum) MaxRightBorderSum = RightBorderSum; } return Max3(MaxLeftSum, MaxRightSum, MaxLeftSum + MaxRightSum); } int MaxSubsequenceSum(cost int A[], int N) { return MaxSubSum(A, 0, N - 1); }
这段代码的在数量和复杂程度都超过了前两个算法,要设计这个算法是要花费一定的精力的,但是这段代码时间复杂度控制的很好,这个算法的时间复杂度就是O(nlogn)。
计算过程明天再加。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。