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

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

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 npast 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 functions f( n) and g( n) by computing lim f( 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,  ... , A

       第三层:计算各子序列

       代码如下:

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值