Data Structures and Algorithms: Algorithm Analysis

1. mathematical basis

Θ, pronunciation: theta, Sita; are both a lower bound upper bound (tight), equal to the mean.

O, pronunciation: big-oh, Omi can wing (uppercase); represents the upper bound (tightness unknown), meaning less.

ο, pronunciation: small-oh, Omi can wing (lowercase); represents the upper bound (not tight), less than the mean.

Ω, pronunciation: big omega, omega (uppercase); represents a lower bound (tightness unknown), greater than or equal meaning.

ω, pronunciation: small omega, omega (lower case); represents a lower bound (not tight), larger than the mean.

definition:

b0b95142d27d0cf3ed72d2ff043b481f632.jpg

Here is a comparison of the relative growth rate function.

7a989725baa0b582b509f97a7d1589dbb5c.jpg

2. Model

In order to analyze algorithms in a formal framework, we need a computational model. We assume that all instructions in a computer program is to be executed sequentially, and each execution have just spent a unit of time (addition, multiplication, assignments, etc.).

3. issue to be analyzed

The most important resource is the algorithm to analyze the running time, the running time is an effective way to measure the pros and cons of an algorithm.

4. Run Time Calculation

We illustrate analysis algorithm running time is represented by a simple example

4.1. Examples

380e1e57f5566f065d4b28f8db5c7b832da.jpg

c0a3c2852ac1804468e70d9e86307c11981.jpg

among them

Line 17: 1 time units (assignment)

Line 18: 2n + 1 units of time (an assignment, n secondary tables, n time increment)

Line 19: 4n time units (2n multiplications, n additions, n times assignment)

20 line: 1 time units

Total time unit 6n + 3, we say that the algorithm is O (N).

4.2. Law

for loop

A for loop running time up to the time the for loop is run inside the statement multiplied by the number of iterations.

Nested for loop

The total time for loop nested inside a set of statements to run a statement that the running time is multiplied by the restructuring of all the for loop size results.

		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
				k++;

Sequential statements

The statement runs each time sum.

a787fda4a2d243bbf19146d93c19eb73ee0.jpg

		for (int i = 0; i < n; i++)
			k++;

		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
				k++;

if / else statements

5807d636eb618fef6f480aa3255f24e46d8.jpg

The basic strategy analysis algorithm running time is to start work from the inside to the outside or the deepest part. If there is a method call, you must first analyze these calls. If you have a recursive call, so there are several options.

The first: the recursive veil covering only for loop, which are usually run time O (N):


	public static int factorial(int n) {
		if (n <= 1) {
			return 1;
		} else {
			return n * factorial(n - 1);
		}
	}

It is essentially a loop

		int n = 1;
		
		for (int i = 1; i <= 5; i++) {
			n *= i;
		}

Second: When the recursion is normally used, which is converted into a cycle is very difficult.

	public static int fib(int n) {
1		if (n <= 1)
2			return 1;
3		else
4			return fib(n - 1) + fib(n - 1);
	}

分析起来是十分简单的,令T(N)为调用fib(n)的运行时间。如果N=0或N=1则运行时间T(N)为常数T(0)=T(1)=1。当N>2时,运行时间为第1行运行时间加上第4行运行时间。有T(N)为fib(n)运行时间则T(N-1)为fib(n-1)运行时间。得出N>2时运行时间公式:T(N) = T(N-1)+T(N-1)+2

由前面我们证明过的斐波那契数列可得

ea24371f8f71c068ace08daa9eb98b4f3b0.jpg

从而得知这个程序的运行时间以指数速度增长。

这个程序之所以运行慢,是由于做了大量重复工作,如在程序第4行计算f(n-1)和f(n-2)的值,其实在f(n-1)函数内部又会重新计算f(n-2)和f(n-3)的值,这样就导致f(n-2)进行了重复计算。所以可以使用一个数组来保存中间计算的值。省去这部分计算。以后会对该递归进行优化。

5.最大子序列问题

问题:给定一个数列,其中可能有正数也可能有负数,我们的任务是找出其中连续的一个子数列(不允许空序列),使它们的和尽可能大。

我们通过4种算法求解来比较不同算法的优劣。

第一种:穷举所有子序列的可能,时间复杂度为

115485c60abddb0eccf7f3359edf3b6904d.jpg

	public static int maxSubSum1(int[] a) {
		int maxSum = 0;
		for (int i = 0; i < a.length; i++) {
			for (int j = i; j < a.length; j++) {
				int thisSum = 0;
				for (int k = i; k < j; k++) {
					thisSum += a[k];
				}
				if (thisSum > maxSum) {
					maxSum = thisSum;
				}
			}
		}
		return maxSum;
	}

第二种:经过改良版时间复杂度

56483e150f705e50e6102ce60b305c4e852.jpg

	public static int maxSubSum2(int[] a) {
		int maxSum = 0;
		for (int i = 0; i < a.length; i++) {
			int thisSum = 0;
			for (int j = i; j < a.length; j++) {
				thisSum += a[j];
				if (thisSum > maxSum) {
					maxSum = thisSum;
				}
			}
		}
		return maxSum;
	}

第三种:该方法采用“分治”策略,将系列分为两部分,前半部分与后半部分,分析最大子序列出现的可能性就又三种,第一种出现在前半部分,第二种出现在后半部分,还有一种就是横跨前半部分和后半部分。

1adcdcd306967970efa7c6a30f8d4c6ddf6.jpg

	public static int maxSubSumRec(int[] a, int left, int right) {

		if (left == right) {  //基准情况
			if (a[left] > 0) {
				return a[left];
			} else {
				return 0;
			}
		}
		
		int center = (left + right)/2;
		int maxLeftSum = maxSubSumRec(a, left, center);
		int maxRightSum = maxSubSumRec(a, center, right);
		
		int maxLeftBorderSum=0,leftBorderSum=0;
		for(int i=center;i>=left;i--) {  //从中间向左遍历
			leftBorderSum += a[i];
			if(leftBorderSum>maxLeftBorderSum) {
				maxLeftBorderSum = leftBorderSum;
			}
		}
		
		int maxRightBorderSum=0,rightBorderSum=0;
		for(int i=center;i<right;i++) { //从中间向右遍历
			rightBorderSum += a[i];
			if(rightBorderSum>maxRightBorderSum) {
				maxRightBorderSum = rightBorderSum;
			}
		}
		//求最大值
		return max(maxLeftSum, maxRightSum,maxLeftBorderSum+maxRightBorderSum);
	}
	

设执行该方法的时间为T(N);

方法前面部分执行判断,时间为常量。

中间部分执行两个递归调用,每个递归执行N的一般的计算执行时间为T(N/2)。

再后面两个循环,一共遍历N数量,执行时间为O(N)。

则得到方程组:T(1) = 1 和  T(N) = 2T(N/2) + O(N)

541d45740860cdeb4c27053c79fb753ccc6.jpg

8d2c7615911d64ec70c61fa0a9bc701b711.jpg

这个分析的假设是N为2的幂时成立。

第四种:这个算法是聪明的,正确性不那么容易看出来。

	public static int maxSubSum4(int[] a ) {
		int maxSum = 0, thisSum = 0;
		for(int i=0;i<a.length;i++) {
			thisSum += a[i];
			if(thisSum > maxSum) {
				maxSum = thisSum;
			}else if(thisSum <0){
				thisSum = 0;
			}
		}
		return maxSum;
	}

比较其中的每一个子序列和,当子序列和为负数时初始化为0重新计算。

6.运行时间中对数

Analysis algorithms running time is probably the most confusing aspects of the logarithm problem. We have seen divide and conquer algorithm will run O (N log N) logarithmic time.

There is also the case for the number of possible: when the size of the problem may be reduced to their portion (usually 1/2) by calculating the time constant, then the algorithm is O (log N).

A specific example is a case where three kinds of time complexity is logarithmic.

Binary search

39fc75254cd18600fadf3a9e00d30b7388d.jpg

Algorithm strategy: whether we can play through the verification element X, if it is found; if X is less than the drama series elements as already sorted, we can verify the left side of the series in the same way; if X is greater than the play of the same element way to verify the right of the series.

	public static int binarySearch(int[] a,int x) {
		
		int low =0, high = a.length-1;
		while(low <= high) {
			int mid = (low + high)/2;
			if(a[mid] < x) {
				low = mid+1;
			}else if(a[mid] > x) {
				high = mid -1;
			}else {
				return a[mid];
			}
		
		}
		return -1;
	}

Europe and Germany in a few algorithms

The second example is a few years in Europe and Germany algorithm to calculate the greatest common factor. Greatest common divisor of two integers (GCD) is the maximum integer divisible by both simultaneously.

Theorem: the greatest common divisor of two integers is equal to the smaller of the two numbers divided by the number and the greatest common divisor of the remainder.

	
	public static long gcd(long m,long n) {
		while(n != 0) {
			
			long rem = m % n; //算法中首先m要大於n,然後求余数,将较小的替换为大数,余数替换为小数。知道余数为0为止。
			m = n; 
			n = rem;
		}
		return m;
	} 

Exponentiation

bb51712197e6315af5a3edfdeffeff3c9e4.jpg

d8656a351ad3233bfa57548e0d781a5cc85.jpg

Note: the recursive propulsion principle is gradually reduced n, n = 1 to n = 0 or propulsion.

	//求解x的n次幂
	public static long pow(long x,int n) {
		if(n == 0) {
			return 1;
		}
		if(n == 1) {
			return x;
		}
		if(isEven(n)) {//n为偶数时
			return pow(x*x,n/2);  //该递归推进的原则就是n中间减小,向0或1基准情形靠近
		}else {
			return pow(x*x,n/2)*x;
		}
	}

 

Reproduced in: https: //my.oschina.net/u/3100849/blog/3057469

Guess you like

Origin blog.csdn.net/weixin_33757911/article/details/92375711