您的位置:首页 > 理论基础 > 数据结构算法

数据结构与算法分析笔记:CHAPTER 2: ALGORITHM ANALYSIS

2013-11-25 02:39 323 查看
本章首先介绍了估计一个程序所需时间的数学定义,然后用这些数学定义分析了求最大子序列和问题的几种算法。

2.1. Mathematical Background

Throughout the book we will use the following four definitions:

DEFINITION: T(n) = O(f(n)) if there are constants c and n0 such that T(n)<=cf(n) when n>= n0.

DEFINITION: T(n) = Ω(g(n)) if there are constants c and n0 such that T(n)>=cg(n) when n>=n0.

DEFINITION: T(n) =θ(h(n)) if and only if T(n)= O(h(n)) and T(n)=Ω(h(n)).

DEFINITION: T(n) = o(p(n)) if T(n)= O(p(n)) and T(n) !=(p(n)).

Thus, we compare their relative rates of growth.

The first definition says that eventually there is some point n0 past
which cf(n)is always at least as large as T(n),so that if constant factors are ignored,f(n) is at least as big asT(n).
If we use the traditional inequality operators to compare growth rates,then the first definition says that the growth rate ofT(n) is less than or equal to () that of f(n).

The second definition, T(n)=(g(n))(pronounced "omega"), says that the growth rate of T(n)is greater than or equal to () that ofg(n).

The third definition, T(n) = (h(n))(pronounced "theta"), says that the growth rate of T(n)equals ( = ) the growth rate ofh(n).

The last definition, T(n) = o(p(n))(pronounced"little-oh"), says that the growth rate of T(n) is less than (<) the growth rate ofp(n). This is
different from Big-Oh,because Big-Oh allows the possibility that the growth rates are the same.

The important things to know are:

RULE 1:

If T1(n) = O(f(n))and T2(n) =O(g(n)),then

(a)T1(n) + T2(n) = max(O(f(n)),O(g(n))),

(b)T1(n) * T2(n) = O(f(n)*g(n)),

RULE 2:

If T(x)is a polynomial of degree n, then T(x) =


RULE 3:


=O(n) for any constant k.This tells
us that logarithms grow very slowly.

Several points are in order. First, it is very bad style to include constants or low-orderterms inside a Big-Oh.Do not sayT(n) =O(2n2)orT(n) =O(n2+
n). In both cases, the correct form isT(n)=O(n2).

Secondly, we can always determine the relative growth rates of two functionsf(n) andg(n) by computing limf(n)/g(n), using L'Hôpital's rule if necessary.

2.4.3 最大子序列和问题的解

Don't compute anything more than once.

给定整数A1,A2,… , AN, 求[jk=iAk(为方便起见,如果所有整数均为负数,则最大子序列和为0)。

方法一、穷举法
计算所有子序列的和,比较得到最大子序列的和。如何穷举所有子序列?用三层for循环嵌套。

第一层:穷举各种子序列的范围:A1到AN、A2到AN…

第二层:在Ax到AN的范围中,穷举该范围内的子序列:Ax, Ax+1; Ax, Ax+1, Ax+2 ; … ... ; Ax, Ax+1, ... , AN

第三层:计算各子序列

代码如下:

int MaxSubsequenceSum(const int A[], int N)
{
int ThisSum, MaxSum=0, i, j, k;

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)。该段代码明显不符合“Don't compute anything more than once.”,如A1+A2被计算了N次。

方法二、在计算各子序列时,不采用for循环
代码如下:

int MaxSubsequenceSum_2(const int A[], int N)
{
int ThisSum, MaxSum=0, i, j;

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)。该段代码仍不符合“Don't compute anything more than once.”。

方法三、递归
The algorithm uses a "divide-and-conquer" strategy. The idea is to split the problem into two roughly equal subproblems, each of which is half the size of the original. The subproblems are then solvedrecursively.
This is the "divide" part. The"conquer" stage consists of patching together the two solutions of the subproblems, and possibly doing a small amount of additional work, to arrive at a solution for the whole problem.

In our case, the maximum subsequence sum can be in one of three places.Either it occurs entirely in the left half of the input, or entirely in the right half, or it crosses the middle and is in both halves. The first two cases can be solved recursively.
The last case can be obtained by finding the largest sum in the first half that includes the last element in the first half and the largest sum in the second half that includes the first element in the second half. These two sums can then be added together.

divide-and-conquer策略将problem分割成两个可以用同样策略解决的子问题,蕴含了递归的思想。

如何实现递归,第一章有介绍the four basic rules of recursion,就本例而言:

1) Basic cases

将一组数据不断的从中间分割,最后肯定会出现:只剩一个数值的情况,此时相当于改组数据的最左侧值=最右侧值;

2) Making progress

由1的分析知,将一组数据不断的从中间分割,最后会到达Base case;

3) Design rule; 4) Compound interest rule

Rule 3是假设满足;rule 4是设计高效率的递归时应遵循的。

在本例中还应考虑的是,因为the maximum subsequence sum can be in one of three places. Either it occurs entirely in the left half of the input, or entirely in the right half, or it crosses the middle and is in both halves. 而在子数组中得到的都是entirely in the left half of
the input t, or entirely in the right half, 也就是还需要计算crosses the middle and is in both halves。

代码如下:

int MaxSubsequenceSum_3(const int A[], int Left, int Right)
{
int Center = 0, MaxLeftSum=0, MaxRightSum=0;
int MaxLeftBorderSum=0, MaxRightBorderSum=0;
int LeftBorderSum=0, RightBorderSum=0, MaxCross;
int i=0;
int Max;

//Base case
if (Left == Right)
{
if (A[Left]>0)
return A[Left];
else
return 0;
}

//Making progress
Center = (Left + Right)/2;
MaxLeftSum = MaxSubsequenceSum_3(A, Left, Center);
MaxRightSum = MaxSubsequenceSum_3(A, Center+1, Right);

//Calculating the max that crosses the middle and is in both halves
for (i=Center; i>=Left; i--)
{
cout << "A[i] = " << A[i] << endl;
LeftBorderSum += A[i];
if (LeftBorderSum > MaxLeftBorderSum)
MaxLeftBorderSum = LeftBorderSum;
}
for (i=Center+1; i<=Right; i++)
{
cout << "A[i] = " << A[i] << endl;
RightBorderSum += A[i];
if (RightBorderSum > MaxRightBorderSum)
MaxRightBorderSum = RightBorderSum;
}
MaxCross = MaxLeftBorderSum + MaxRightBorderSum;

//return the Max of the three
Max = MaxLeftSum > MaxRightSum ? MaxLeftSum : MaxRightSum;
Max = Max > MaxCross ? Max : MaxCross;

cout << Max << endl;
return Max;
}


分析:分治算法以O(N log N)时间运行,该算法仍不符合“Don't compute anything more than once.”,但已经必前两种算法好很多。

除分治算法外,可将对数最常出现的规律概括为以下法则:

An algorithm is O(log n) if it takes constant
(O(1)) time to cut the problem size by a fraction (which is usually).On the other hand, if constant time is required to merely reduce the problem by a constant amount(such as to make the problem smaller by 1), then the algorithm
is O(n).

示例:计算XN
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: