《算法分析与设计》(王晓东版)期末复习总结

**

1.1 算法与程序

**
*算法的特性:
1、输入。0个或多个输入
2、输出。至少一个输入
3、确定性。每条指令不能模糊
4、有限行。执行次数、运行时间有限
*程序的特性:
除去4,其他和算法一样。
例如,操作系统,它是一个无限循环的程序,虽然不能叫做算法,但是可以是程序。操作系统中的每一个子操作,却可以叫做算法。

1.2 算法复杂性分析

  • 算法的复杂性 取决于 所需资源的多少。资源包括时间和空间,所以,算法的复杂性可以分为:
    1、时间复杂性(主要考虑)
    2、空间复杂性

  • 用N表示:问题的规模
    用I表示 :输入
    用A表示:算法本身
    用C表示复杂性,则C = F(N, I, A)
    对同一个算法A可隐去,所以C = F(N, I)
    由于输入I的不同,会导致算法的复杂度不同。可以分为最坏Tmax(N),平均Tavg(N),最好Tmin(N),一般使用最坏情况Tmax(N)作为度量

  • 真实的算法中,许多复杂的算法无法对每一个运算都进行计算,所以,采用渐进复杂度代替。
    1、O代表上界。例如N² = O(N³)
    2、Ω代表下界。例如N² = Ω(N)
    3、θ代表上界和下界相等。N² = θ(N²)

2.1 递归的概念

  • 算法一: n!
  int func(int n){
  	if(n==0) return 1;
	return n*func(n-1);
}
  • 算法二: 斐波那契数列1,1,2,3,5,821……
  int func(int n){
	if(n<=1) return 1;
	return func(n-1)+func(n-2);
  }
  • 算法三: 双递归函数:当一个函数及他的一个变量由函数自身定义时,称为双递归函数
  • 算法四: 整数划分。
  int func(int n, int m){
// n表示要分解的数字,最大的加数不能超过m
	if(m < 1|| n < 1) return 0;
	if(m==1|| n==1) return 1;
	if(n<m) return q(n, n);// 最大加数不能大于n
	if(n==m) return func(n,m-1)+1; // 最大加数等于它本身
	return func(n-1,m)+func(n,m-1);
}
  • 算法五:汉若塔。
  void func(int n, int a, int b, int c){
 	 if(n>0){
  		func(n-1, a, c, b);//将a上的1~n-1号盘子移动到c,借助b
  		move(a, b);     //将a上剩下的最大的n号盘子移动到b
  		func(n-1, c, b, a);//将c上的1~n-1号盘子移动到b,借助a
	}
}

重点:全排列。
1、思路:设R = {r1, r2, r3, …… rn},则全排列
Perm(R)=(r1)Perm(R - r1)+(r2)Perm(R - r2)+……+(rn)Perm(R - rn)
即,每一个集合R的全排列等于集合R减掉rk后等到的这个集合R’的全排列加上rk
2、算法:
// 排列从head到end的元素

Perm(int list[], int head, int end){ 
  if(head==end){
	for(int i=0;i<end;i++)
	  cout<<list[i];
	cout<<endl;
	}
	// head这个位置可以放的元素有(end-head+1)种可能
	for(int i=head;i<=end;i++){
  		swap(list[head], list[i]);
  		Perm(list, head+1, end);
  		swap(list[head], list[i]);
	}
}

2.4 大整数乘法

重点:
《算法分析与设计》(王晓东版)期末复习总结_第1张图片
算法复杂度:
在这里插入图片描述
改进:
在这里插入图片描述

算法复杂度:
在这里插入图片描述

2.5 Strassen矩阵乘法

设矩阵A、B是n阶矩阵,AB中,每个元素需要n次乘法和n-1次加法,所以n²个元素时间复杂度为O(n³)
strassen矩阵乘法是将A,B分别分为四个更小的矩阵A11 A12 和 B11 B12,
A21 A22 B21 B22
可以得出:A
B = A11B11+A21B12 A11B12+A12B22
A21B11+A22B21 A21B12+A22B22
时间复杂度仍然是O(n³)

2.8 快排

void qsort(int a[], int h, int t){
	if(h<t){
		int r = departion(a, h, t);
		qsort(a, h, r-1);
		qsort(a, r+1, t);
	}
}
int departion(int a[], int h, int t){
	int r = h;
	while(true){
		while(h<t&&a[++h]<=a[r]) ;
		while(a[t]>a[r]) t--;
		if(h<t) swap(a[t],a[h]);
		else  break;
	}
	swap(a[r],a[t]);
	return r;
}

2.9 线性时间选择

//选出第K小的数,最坏复杂度O(n²),但平均时间复杂度还行

int solve(int a[], int h, int t, int k){
	if(h==t) return a[h];

	int i = partion(a, h, t); //该方法把数组a划分为两个段,a[h,i-1]a[i+1,t]
	int j = i - h + 1;
	if(j>=k) return solve(a, h, i, k);
	else return solve(a, i+1, t, k -j);
}
// 优化算法,思路:线性时间内找到一个划分基准。最坏时间复杂度O(N)
//伪代码
int solve(int a[], int h, int t, int k){
	if(t - h < 75){
	用随便一个简单的排序算法对a[h]-a[t]从小到大排序;
	return a[h+k-1];
	}

	for(int i=0; i<=(t-h-4)/5; i++){
		将a[p+i*5]-a[p+i*5+4]的第3小元素与a[i]交换位置;
	}//此时前(t-h-4)/5项全都是各个组的中位数
	int x = solve(a, h, h+(t-h-4)/5, (t-h-4)/10); //找出中位数的中位数,作为基准元素
	int i = partion(a, h, t, x); //以x为基准,划分a[h]-a[t],小的放左段,大的放右段
	int j = i - h + 1;
	if(k <= j) return solve(a, h, i, k);
	else return solve(a, i+1, t, k - j);
}

3.1 矩阵连乘

void MatrixChain(int *p,int n,int **m,int **s)
{
        for (int i = 1; i <= n; i++) m[i][i] = 0;
        for (int r = 2; r <= n; r++)
              for (int i = 1; i <= n - r+1; i++) {
                      int j=i+r-1;
// Ai到j所需的最少数乘次数假设为A[i](A[i+1]…A[j])的数乘次数
                      m[i][j] = m[i+1][j]+ p[i-1]*p[i]*p[j];
                      s[i][j] = i;//括号的位置
                      for (int k = i+1; k < j; k++) {
							//逐一计算,找到最佳断法
                           int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];
                           if (t < m[i][j]) { m[i][j] = t; s[i][j] = k;}
                      }
              }
}

3.2 最长公共子序列

《算法分析与设计》(王晓东版)期末复习总结_第2张图片

void solve(int m, int n, int *x, int *y, int **c, int **b){
// m,n为两个字符串x,y的长度
// c[i][j]保存x[0,i]和y[0,j]最长子串的长度,b[i][j]记录来向,方便回溯输出子串
	for(int i=0;i<=m;i++) c[i][0]=0;
	for(int i=0;i<=n;i++) c[0][n]=0;
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			if(x[i]==y[j]){
				c[i][j]=[i-1][j-1]+1;
				b[i][j]=1;
			}
			else{
				if(c[i-1][j]>=c[i][j-1]){
				c[i][j]=c[i-1][j];
				b[i][j]=2;
				}
				else {
					c[i][j]=c[i][j-1];
					b[i][j]=3;
				}
			}
		}
	}
}

// 递归回溯子串

void print(int i, int j, int *x, int **b){
	if(i<=0||j<=0) return;
		if(b[i][j]==1){
		print(i-1,j-1,x,b);
		cout<<x[i];
	}
	else if(b[i][j]==2){
		print(i-1,j,x,b);
	}
	else{
		print(i,j-1,x,b);
	}
}

3.3 最长子段和

// a[]是字符串,b[j]记录以a[j]为最后一个字符的最大子段和

void solve(int n, int *a, int *b){
	b[1]=max(0,a[1]);
	for(int j=2;j<=n;j++){
		b[j] = max(b[j-1]+a[j], a[j]);
	}
}

最大子段和就是b[]中的最大值
《算法分析与设计》(王晓东版)期末复习总结_第3张图片

3.4 0-1背包问题

重点

回溯搜索的“子集树”和“排列树”的搜索框架(书P124-125)

重点

棋盘n皇后问题和图的m着色问题(书P135和P142)

重点


如果帮到你的话,点个关注不迷路~
至少至少点个赞吧 ~ 客官~ (ಥ_ಥ)

你可能感兴趣的:(专业课那些事儿,算法,数据结构,java)