【算法设计zxd】第一章 算法基础 4.设计工具【三角矩阵,】

目录

1. 循环设计

(1) 设计思维

自底向上的设计(Down – Top Design)

自顶向下的设计(Top-Down Design)

(2)挖掘内在规律构建计算模型

【例1-3】设计算法,输出一个n×n的三角矩阵,如图所示规律。

  问题分析:

计算模型:​

 算法设计与描述:

 算法分析:

算法实现:

(3)改进计算模型提高运算效率

【例1-4】​

 问题分析      

计算模型

算法设计与描述      

算法实现:

2. 递归设计

递归设计的步骤:

【1-5】运用递归方式设计求解斐波那契数列(Fibonacci sequence)的第n项的值

计算模型

算法分析

 3.循环与递归的比较

【例1-5】任意给定十进制数:(1)从低位到高位逐位输出各位数字; (2) 从高位到低位逐位输出各位数字。

问题分析

算法实现

 

【例1-6】求从n个自然数(1,2,3,…, n)中取出r个数的所有组合。

 计算模型:1)循环算法:

2)递归

 算法实现

【1-7】找出n个自然数(1,2,3,…, n)中取出r个数的所有组合。

算法分析

算法设计与描述

 比较总结:


1. 循环设计

(1) 设计思维

自底向上的设计(Down – Top Design)

先找出某个问题的子问题或若干特殊问题,

定性、定量的方式去描述和解决这些子问题,

然后,逐步合并子问题的解,最后得到大问题的解。

核心本质:合并

自顶向下的设计(Top-Down Design)

将复杂的大问题分解为相对简单的小问题,

找出每个问题的关键、重点所在,

然后用精确的思维定性、定量地去描述问题和解决问题。

核心本质:分解

例如:归并算法:自顶向下拆,自底向上合并

(2)挖掘内在规律构建计算模型

挖掘问题的内在规律,进行抽象并构建计算模型

交通指挥灯:数据构造

三角矩阵:运算规律

运算规律:一般找下标对应规律 最快

【例1-3】设计算法,输出一个n×n的三角矩阵,如图所示规律。

行列参与运算(下标)

  问题分析:

问题:要找到按斜行访问与按矩阵访问之间的映射关系?

计算模型:

 算法设计与描述:

输入:矩阵行列值n

输出:按斜行元素值为连续整数的三角矩阵

 算法分析:

算法主体语句执行次数为:

 其中,L代表斜行,j代表列。

【其实是每一个元素都进行操作,且只进行一次。所以执行次数=元素个数】

【第一斜行n 第二斜行……】

算法实现:

#include<stdio.h>int main()
{// 输入  int n,k=1;int a[100][100];printf("请输入n值:");scanf("%d",&n);for(int L=0;L<n;L++)//L是斜行 {for(int j=0;j<n-L ;j++){a[L+j][j] = k++ ;}}//输出for(int i=0;i<n;i++){for(int j=0;j<=i;j++){printf("%5d",a[i][j]);}printf("\n");} return 0;
}

思考题:n=5*5?

代码:

#include<iostream>
using namespace std;int main()
{int n=5*5;int k=0;int a[n][n];for (int i=0;i<n;i++){for(int j=0;j<n-i;j++){a[i+j][j]=k++;}}for(int i=0;i<n;i++){for(int j=0;j<=i;j++)//注意这里是<= {cout<<a[i][j]<<" ";}cout<<endl;}return 0;
}

结果:
 

0 0 1
0 1 2
0 2 3
0 3 4
1 0 5
1 1 6
1 2 7
2 0 8
2 1 9
3 0 10
1
5 2
8 6 3
10 9 7 4

(3)改进计算模型提高运算效率

【例1-4】求1/1!-1/3!+1/5!-1/7!+…+(-1)n+1/(2*n-1)!

① 问题分析      (运算过滤)

迭代方法是在累乘的基础上实现累加

②计算模型

 中间项

③算法设计与描述      

依据式(4-1)设计的算法EA

依据式(4-2)设计的算法EA_G

输入 

计算范围n

输出

累加结果S

算法

描述

step 1: 读入n,令S=T=1、i=3、j=1,n=2*n-1

step 2: 判断i<=n,成立T=1转step3, 否则进入step 6

step 3: 判断j<=i,成立转step 4, 否则进入step5

step 4: 执行T=T*j, j=j+1; 转step 3;

step 5: 计算T的符号;

step 6: S=S+1/T; i=i+2; 转step 2;

step 7: 输出S,运算结束。

step 1: 读入n,令S=T=1、i=3,n=2*n-1

step 2: 判断i<=n,成立转step3, 否则进入step 5

step 3: T=(-1)*T*(i-1)*i;

step 4: S=S+1/T; i=i+2; 转step 2;

step 5: 输出S,运算结束。

3 4是内层循环 少去内层循环

④算法分析(缺)

⑤算法实现:

EA

// EA 
#include<stdio.h>
int main()
{float s=1.0f,t;int n,count=2;//项数printf("请输入计算项数:");scanf("%d",&n);for(int i=3;i<=2*n-1;i+=2){t=1.0f;//每次都重新算for(int j=2;j<=i;j++)//分母{t=t*j; }for(int j=1;j<=count+1;j++){t=-t;}s=s+ 1/t;count++;}printf("s=%f\n",s);
}

 EA_G 

// EA _ G 
#include<stdio.h>
int main()
{float s=1.0f,t=1.0f;int n;printf("请输入计算项数:");scanf("%d",&n);for(int i=3;i<=2*n-1;i+=2){t= -t*(i-1)*i;//计算分母 s=s+ 1/t;}printf("s=%f\n",s);
}

⑥测试

⑦结果整理与文件编制

2. 递归设计

定义:一个过程或函数在定义中直接或间接调用自身的一种方法。

设计关键:找出递归关系(方程)递归终止(边界)条件。递归关系就是使问题向边界条件转化的规则。

递归设计的步骤:

(1) 分析问题找到递归关系:找出大规模问题与小规模问题的关系,以便通过递归使问题规模变小。(收敛的)

(2)设置终止条件控制递归:通过停止条件的设置,找出可解的最小规模问题。

(3)设计函数确定数据传递方式。

【1-5】斐波那契的第n项 递归

运用递归方式设计求解斐波那契数列(Fibonacci sequence)的第n项的值

计算模型

递归的终止条件和递归方程,如下:

其中,式(5-2)是递归方程,式(5-1)是终止条件。

算法分析

 依据计算模型,容易得知,求第n项的值需要计算n-2次,所以,主体算法计算次数约为f(n)=n-2

斐波那契:算法实现 C

#include<stdio.h> int fcc(int n)
{int t;if(n==1|n==2)return 1;else return fcc(n-1)+fcc(n-2);
}
int main()
{int n;printf("input n:");scanf("%d",&n);printf("No.%d value of Fibonacci sequence is %d\n ",n,fcc(n));return 0;
}

 3.循环与递归的比较

每个迭代算法原则上总可以转换成与它等价的递归算法;

反之则不然,

就是说不是每个递归算法都可以转换成与它等价的循环结构算法。

 

【例1-5】任意给定十进制数:(1)从低位到高位逐位输出各位数字; (2) 从高位到低位逐位输出各位数字。

问题分析

这是一个较为简单的问题,我们将从实现的角度来比较两者对于问题的适应性。

算法实现

(1)从低位到高位:效率实际一样

(2)从高位到低位:循环首先需要确定位数,递归——联系到树的先根遍历和中 后

改变要求,递归变化可能极小

思考题:尝试总结 递归与循环 的优缺点 

思考题:用递归求出斐波那契数列 去除重复计算

#include<iostream>
using namespace std;
//递归 
int fb(int i)
{if(i==1||i==2)return 1;else return fb(i-1)+fb(i-2);
}
//时间复杂度O(2^n)
//空间复杂度O(1) //数组,去重,用空间换时间 
int a[40];
int fib(int n)
{a[0]=0;a[1]=1;for(int i=2;i<=n;i++){a[i]=a[i-1]+a[i-2];}return a[n];
}
//时间O(n)
//空间O(n) //动态规划
int fibdp(int n)
{int f=0;int fp=1;while(n--){fp=fp+f;//规则 f=fp-f;//恢复fplus }return f; 
}
//时间O(n) 
//空间O(1) 
int main()
{cout<<fb(12)<<endl;return 0;
}

代码:
 

#include<iostream>
using namespace std;void gaocir(int n)
{int b[20];int i=0;while(n){b[i]=n%10;n=n/10;i++;}while(i--){cout<<" "<<b[i]''}
} 
void gaodg(int n)
{if(n<10)cout<<" "<<n;else{gaodg(n/10);cout<<" "<<n%10;}
}
void dicir(int n)
{cout<<"低位开始 循环";while(n){cout<<" "<<n%10;n=n/10;}
}
void didg(int n)
{
//	cout<<"低位开始 递归";if(n<10)cout<<" "<<n;else {	cout<<" "<<n%10;didg(n/10);}
}
int main()
{int n=12345;return 0;
}

【例1-6】求从n个自然数(1,2,3,…, n)中取出r个数的所有组合。

问题分析

 计算模型:
1)循环算法:

设i代表第i个位置,则 r 个位置上的取值范围依次为:

 其中, 1 ≤ r ≤ n , 且 r 在循环算法实现时 代表循环嵌套的层数,必须是定值。

2)递归

 算法实现

算法分析

算法设计与描述

 比较总结:

递归

循环

程序可读性

代码量大小

时间

占用空间

适用范围

广

设计难度

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注