算法分析
第一次
程序设计一般步骤
1 确定数据结构
2 确定算法
3 编写程序
4 调试程序
5 编写文档资料
上述5个步骤中最重要的第2步 确定算法
算法:所谓算法是指某个问题或者某个功能的求解方法。
实际中某个问题或者某个功能的求解方法不止一个。
考虑选择哪种算法作为我该问题或者该功能的最终解决方案呢?
1 算法正确
2 时间复杂度和空间复杂度
例1 输入一个正整数给x,判断其是否是素数?
分析 所谓素数就是质数:也就是只能被1和其本身(x)整除的数
其实任何额一个正整数都能被1和其本身整除,而这点其实可以不证明
重点去证明:不能被2到x-1范围内的所有的数整除。
举例:
x=7 2 3 4 5 6
2到6中每个数值都与7之间是不能整除的关系,所以7才是素数
x=8 2 3 4 5 6 7
8对2取余数就是0,整除关系,结果可以直接下结论8不是3到7就没必要再进行判断了,循环可以提前结束。
整个问题中涉及2个问题,是素数1,不是素数0
代码1
#include"stdio.h"
#include"windows.h"
int main()
{
int x,i,flag;//flag=1 是素数 flag=0 表示不是素数
printf(“请你任意输入一个正整数:”);
scanf("%d",&x);
flag=1;//相当于一开始假设x是素数
for(i=2;i<=x-1;i++)
{
if(x%i==0)
{
flag=0;
break;
}
}
if(flag==1)
printf(“yes”);
else
printf(“no”);
system(“pause”);
}
上述程序的时间复杂度是多少? o(n)
时间复杂度的表示形式是 o(?)
1 白话解释:看程序运行所耗费的时间
2 专业理解:形式o(?)
?体现出来的就是一个问题求解过程中操作的执行次数。
执行次数要把问题放大到n个数值的角度来看待。
特别注意: 专业理解时间复杂度的问题,把一个问题求解方法的过程,放大到n个数值类似的角度来看待问题。
举例说明:s=1+2+3+4+…+100
方法1 用等差数列求和公式来表示
s=(1+100)*100/2;
时间复杂度 o(1)
注意这里1 表示操作的执行次数
方法2 用循环
s=0;
for(i=1;i<=100;i++)
s=s+i;
时间复杂度 o(n)
注意这里n 表示操作的执行次数
如果在之前所学过的输出所有三位数值中的水仙花数。
for(a=1;a<=9;a++)
for(b=0;c<=9;b++)
for(c=0;c<=9;c++)
{
t=a100+b10+c;
if(t==aaa+bbb+ccc)
printf("%d\n",t);
}
白话解释 91010
时间复杂度 o(nnn) 等价 o(n^3)
改进素数程序
举例
x=7 2 3 4 5 6 2到6中每个数值都与7之间是不能整除的关系,所以7才是素数
x=8 2 3 4 5 6 7 8对2取余数就是0,整除关系,结果可以直接下结论8不是
3到7就没必要再进行判断了。
循环可以提前结束。
注意 上述方法中
其实对于7而言 4 5 6没必要判断,因为它们都超过了7的一半,所以不可能是整除关系
其实对于8而言 5 6 7没必要判断,因为它们都超过了8的一半,所以不可能是整除关系
最后修改的是循环 for(i=2;i<=x/2;i++)
代码2
#include"stdio.h"
#include"windows.h"
int main()
{
int x,i,flag;//flag=1 是素数 flag=0 表示不是素数
printf(“请你任意输入一个正整数:”);
scanf("%d",&x);
flag=1;//相当于一开始假设x是素数
for(i=2;i<=x/2;i++)
{
if(x%i==0)
{
flag=0;
break;
}
}
if(flag==1)
printf(“yes”);
else
printf(“no”);
system(“pause”);
}
白话理解:运算次数少了
专业理解:时间复杂度是多少呢? o(n)
继续修改
4不是素数 因为2
6不是素数 因为2
8不是素数 因为2
9不是素数 因为3
10不是素数 因为2
12不是素数 因为2
14不是素数 因为2
15不是素数 因为3
16不是素数 因为2
。。。。。。。。。。。
25不是素数 因为5
26不是素数 因为2
所以每个数值x是否是素数,判断范围还可以缩小,2到x的平方根 sqrt(x)
代码2
#include"stdio.h"
#include"windows.h"
#include"math.h"
int main()
{
int x,i,flag;//flag=1 是素数 flag=0 表示不是素数
printf(“请你任意输入一个正整数:”);
scanf("%d",&x);
flag=1;//相当于一开始假设x是素数
for(i=2;i<=sqrt(x);i++)
{
if(x%i==0)
{
flag=0;
break;
}
}
if(flag==1)
printf(“yes”);
else
printf(“no”);
system(“pause”);
return 0;
}
白话理解:运算次数少了
专业理解:时间复杂度是多少呢? o(logn)
最后提醒一下
一般我们强调某个方法的时间复杂度,应该是包含该问题求解方法的所有步骤所耗费的时间
实际处理的是一个问题求解方法中,所有步骤中取耗费时间(次数)最多的作为最后的时间复杂度的描述
一般情况下,时间复杂度的表示形式如下常见的5种
1 o(1)
2 o(n)
3 o(logn)
4 o(n*logn)
5 o(n^3) 或者 o(n^?)
例2 1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素值重复,
其他均只出现一次。设计一个算法,将它找出来,你能否设计一个算法实现?
最后要找出哪个数是重复的?如果可以的话再找出具体是哪2个位置的数?
方法1 简单粗暴,我想用枚举法,暴力破解法。好处,理解简单啊
a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] a[10] a[11]
2 9 8 6 5 4 1 3 7 10 8
最终考虑到是任意输入的情况
(1)将a[1]与 a[2]到a[11]依次比较,如果相等则输出a[1],1,另外一个相同值的位置
for(i=2;i<=11;i++)
{
if(a[1]==a[i])
printf("%d %d %d\n",a[1],1,i);
}
(2)将a[2]与 a[3]到a[11]依次比较,如果相等则输出a[2],2,另外一个相同值的位置
for(i=3;i<=11;i++)
{
if(a[2]==a[i])
printf("%d %d %d\n",a[2],2,i);
}
…
(10)将a[10]与 a[11]到a[11]依次比较,如果相等则输出a[10],10,另外一个相同值的位置
for(i=11;i<=11;i++)
{
if(a[10]==a[i])
printf("%d %d %d\n",a[10],10,i);
}
上述过程再凑循环
for(j=1;j<=10;j++)
{
for(i=j+1;i<=11;i++)
{
if(a[j]==a[i])
printf("%d %d %d\n",a[j],j,i);
}
}
最后代码
#include"stdio.h"
#include"windows.h"
int main()
{
int a[12],i,j;
printf(“请你输入11个数值,且在1-10之间,且只能有一个数值重复\n”);
for(i=1;i<=11;i++)
scanf("%d",&a[i]);
for(j=1;j<=10;j++)
{
for(i=j+1;i<=11;i++)
{
if(a[j]==a[i])
printf("%d %d %d\n",a[j],j,i);
}
}
system(“pause”);
}
这里是算次数
10+9+…+1
n-1+n-2+…+1
(n-1+1)(n-1)/2
n(n-1)/2
n^2-n/2
标准 o(1+n+(n^2-n)/2)
这里1 是定义代码的
这里n 是输入代码的
这里(n^2-n)/2 是求解代码的
最后取最大值 o(n^2)
最后的修改思路
a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] a[10] a[11]
2 9 8 6 5 4 1 3 7 10 8
准备2个数组,一个数组长度11,另外一个数组长度10
数组a的每个数组元素的值,作为数组b数组元素的标号
数组b中所有数组元素初始值为0
b[1] b[2] b[3] b[4] b[5] b[6] b[7] b[8] b[9] b[10]
1 1 1 1 1 1 1 2 1 1
说明2出现了1次 说明8出现了2次
#include"stdio.h"
#include"windows.h"
int main()
{
int a[12],b[12]={0},i,j,t;
printf(“请你输入11个数值,且在1-10之间,且只能有一个数值重复\n”);
for(i=1;i<=11;i++)
scanf("%d",&a[i]);
for(i=1;i<=11;i++)
{
b[a[i]]++;
if(b[a[i]]==2)
{
t=a[i];
break;
}
}
//如果输出既要位置也要输出的值,我得再来 一轮循环
for(i=1;i<=11;i++)
{
if(t==a[i])
printf(“相同值%d 相同位置%d\n”,t,i);
}
system(“pause”);
}
其实这个方法是用来 空间换时间。
最后问题该方法的时间复杂度是多少呢? o(n)
过程
1 定义部分 1
2 输入部分 n
3 求解部分 n
4 输出部分 n
最后取最大值 n
提出方法3 思路 请思考用异或(位运算)
异或 一样为0,不一样为1
如果是9
9^0 结果是 9
9^9 结果是 0