1009040130贺程实验1.docx

上传人:b****6 文档编号:8494751 上传时间:2023-01-31 格式:DOCX 页数:22 大小:418.51KB
下载 相关 举报
1009040130贺程实验1.docx_第1页
第1页 / 共22页
1009040130贺程实验1.docx_第2页
第2页 / 共22页
1009040130贺程实验1.docx_第3页
第3页 / 共22页
1009040130贺程实验1.docx_第4页
第4页 / 共22页
1009040130贺程实验1.docx_第5页
第5页 / 共22页
点击查看更多>>
下载资源
资源描述

1009040130贺程实验1.docx

《1009040130贺程实验1.docx》由会员分享,可在线阅读,更多相关《1009040130贺程实验1.docx(22页珍藏版)》请在冰豆网上搜索。

1009040130贺程实验1.docx

1009040130贺程实验1

《算法分析与设计》实验报告

实验一算法效率与时空复杂度检验

姓名贺程学号1*********班级电子商务1002班

时间2013/3/8地点文波机房

同组人无

指导教师朱少林

实验目的

掌握一门程序设计语言

掌握算法及程序设计的一般策略与方法

掌握算法实验的一般步骤

掌握算法分析与设计、算法比较的一般方法

掌握算法实验中的时空复杂度的分析方法

掌握算法实验方案的设计方法

实验内容

选择一个合适的程序设计语言(如C、C++、PASCAL等)

根据问题设计算法。

问题如下

(百钱买百鸡问题)假设公鸡5元钱一只,母鸡3元钱一只,小鸡一元钱3只。

要用100块钱刚好买100只鸡,问有多少种买法,每种买法中公鸡、母鸡、小鸡的数量各为多少?

设计一个实验方案,验证求解此问题的算法的正确性,比较并分析各算法的优劣。

设计实验方案。

方案中应包括

多种问题求解算法

算法执行时间获取方法

抗时间“噪声”方法

时间结果分析对比方法

根据算法和实验方案设计实验程序

例一用你所熟知的程序设计语言编程,求解下百钱买百鸡问题。

【题目描述】设公鸡5元一只,母鸡3元一只,小鸡一元3只,用一百元钱刚好买一百只鸡,问有多少种买法,每种买法公鸡、母鸡、小鸡各多少?

PROGRAM百钱买百鸡()

IntegerM=100

Integerx,y,z,n,k

Integert1,t2

t1ßgettime()

Forkß1toMdo//控制重复次数//

nß0

Forxß0to100do

Foryß0to100do

Forzß0to100do

If5*x+3*y+z/3=100andx+y+z=100

Then

nßn+1

print(n,x,y,z)

endif

repeat

repeat

repeat

repeat

t2ßgettime()

print((t2-t1)/M)//取计算平均值,消除噪声//

END.

例二【题目描述】有M只猴子围成一圈,每只从1到M顺序的编号,打算从中选出一个大王;经过协商,决定出选大王的规则:

从第一个开始循环报数,数到N的猴子出圈,最后剩下来的就是大王。

要求:

从键盘输入M、N,编程计算哪一个编号的猴子成为大王。

PROGRAM猴子选大王()

IntegerM,N

Integert1,t2

t1ßgettime()

ForMß100to10000by100do

//控制猴子总数,重复运行算法,求得不同猴子总数下算法的执行时间。

//

计算出圈的猴子

Numberß最后求得的大王猴子编号;

repeat

t2ßgettime()

print(M,t2-t1,Number)

END.

实验步骤

设计求解此问题的多种算法,并将它们转换成相应程序。

分析各算法(程序)的特点,比较它们的优劣。

安装程序设计语言系统。

输入各个程序,验证它们的正确性。

设计并运行能统计各程序执行时间并能抗“噪声”的程序,统计各算法的时间开销,利用Word或Excel等工具,将实验所得数据制成时空曲线图。

并与之前所做的理论分析比较,看是否一致。

猴子总数

100

200

300

400

500

600

700

800

900

1000

1100

1200

算法

时间

0.2

0.22

0.3

0.37

0.46

0.63

0.76

1

1.26

1.67

2.2

2.7

4.附加实验与思考

(1)设有由n个不相同的整数组成的数列,记为:

a

(1)、a

(2)、……、a(n)且a(i)<>a(j) (i<>j)

例如3,18,7,14,10,12,23,41,16,24。

若存在i1

如上例中3,18,23,24就是一个长度为4的不下降序列,同时也有3,7,10,12,16,24长度为6的不下降序列。

设计一个算法,当原数列给出之后,求出最长的不下降序列。

(2)用几种不同的方法写出求斐波拉奇序列第n项f(n)的算法,将算法转换成程序并选用不同的n值上机验算,给出各算法的时间复杂度曲线图。

(3)自选一个问题,设计多种算法和程序并重复上述实验。

实验步骤

1.百钱买白鸡

a.将该问题的算法算法,转换成相应程序。

程序1:

#include

#include

#defineN1000

voidmain(){

inti,j,k,t,t1,t2,n;

printf("公鸡\t母鸡\t小鸡\n");

t1=clock();

for(n=0;n

for(i=0;i<100;i++)

for(j=0;j<100;j++)

for(k=0;k<=100;k+=3)

if((5*i+3*j+k/3)==100&&(i+j+k)==100&&n==0)

printf("%d\t%d\t%d\n",i,j,k);

t2=clock();

printf("程序运行时间:

%fs\n",((double)t2-t1)/N);//计算运行1000次的平均时间

}

程序运行得到解:

公鸡母鸡小鸡

02575

41878

81181

12484

运行时间是:

1.955s

b.由于只有100元钱,而公鸡是5元钱一只,母鸡是3元钱一只,所以最多只能买到20只公鸡,33只母鸡,所以可以减少不必要的循环,提高程序执行的效率,即将三层for循环语句修改为:

for(n=0;n

for(i=0;i<100;i++)

for(j=0;j<100;j++)

for(k=0;k<=100;k+=3)

再次运行程序,得到此时的运行时间是:

0.129s

可见算法优化后,程序执行效率大大提高。

2.猴子选大王

以下给出四种算法,均以文件abc.txt中的内容为测试数据,即100、200…1200,淘汰的是17号。

a.环移动

每次都把数组中下标为0的元素移到数组末尾,然后把剩余的j个元素逐个移动到前一个位置,这样循环移动n-1次后,这样所有被淘汰的猴子都被移到了数组后面,所以最终剩下的数组中的首元素a[0]即为猴王。

#include

#include

#include

#defineN100

FILE*stream;

voidmain(){

intn,m,*a,i,j,temp,t,k,t1,t2,count=0;

stream=fopen("abc.txt","r");//读操作

while(fscanf(stream,"%d",&n)&&fscanf(stream,"%d",&m)){

count++;

t1=clock();

for(intc=0;c

a=(int*)malloc(n*sizeof(int));

for(i=0;i

a[i]=i+1;

}

for(j=n-1;j>0;j--){

for(k=1;k<=m;k++){

temp=a[0];

for(t=0;t

a[t]=a[t+1];

}

a[j]=temp;

}

}

}

printf("%d\n",a[0]);

t2=clock();

printf("程序运行时间:

%fms\n",((double)t2-t1)/N);//计算运行1000次的平均

free(a);

if(count==12){

fclose(stream);

break;

}

}

}

猴子总数

100

200

300

400

500

600

700

800

900

1000

1100

1200

算法

时间

0.42

1.57

3.45

6.15

9.37

13.79

18.60

24.29

30.48

37.64

45.74

54.24

由以上的运行时间表和曲线图容易看出,该算法时间复杂度相当大,因为已经被淘汰的猴子依然参与了移动。

可以大致的算出其时间复杂度近似为O(n*n*m)。

 

b.简单数组

用t保存报数的位置,该算法与算法a相似,但是减少了移动的次数,如果把淘汰的猴子移动到末尾后,以后移动的时候则不再考虑已经被淘汰的猴子,则最终留下的数组首元素就是猴王。

#include

#include

#include

#defineN100

FILE*stream;

voidmain(){

intn,m,*a,i,j,t,t1,t2,count=0;

stream=fopen("abc.txt","r");//读操作

while(fscanf(stream,"%d",&n)&&fscanf(stream,"%d",&m)){

count++;

t1=clock();

for(intk=0;k

a=(int*)malloc(n*sizeof(int));

for(i=0;i

a[i]=i+1;

}

t=0;

for(i=n;i>0;i--){

t=(t+m-1)%i;

for(j=t;j

a[j]=a[j+1];

}

}

}

printf("%d\n",a[0]);

t2=clock();

printf("程序运行时间:

%fms\n",((double)t2-t1)/N);//计算运行1000次的平均

free(a);

if(count==12){

fclose(stream);

break;

}

}

}

猴子总数

100

200

300

400

500

600

700

800

900

1000

1100

1200

算法

时间

0.02

0.06

0.12

0.19

0.30

0.43

0.58

0.74

0.95

1.16

1.42

1.67

该算法是时间复杂度近似为为O(n*m),相对于算法a,提高了效率。

c.循环链表

构造一个循环链表,L为表头节点,最后一个节点指向首结点。

每淘汰一只猴子就从循环链表中将该只猴子节点删除。

最终if(p->next==p)说明链表中只剩下一个节点,该节点猴子就是猴王。

#include

#include

#include

#defineN100

FILE*stream;

typedefstructNode{

intdata;

Node*next;

}MonkeyNode;

voidmain(){

intn,m,i,j,t1,t2,count=0;;

MonkeyNode*L,*q,*p;//p为插入节点L为头指针q指向末尾节点

L=(MonkeyNode*)malloc(sizeof(MonkeyNode));

L->next=NULL;

stream=fopen("abc.txt","r");//读操作

while(fscanf(stream,"%d",&n)&&fscanf(stream,"%d",&m)){

count++;

t1=clock();

for(intk=0;k

q=(MonkeyNode*)malloc(sizeof(MonkeyNode));

q=L;//q指向表头

for(i=1;i<=n;i++){

p=(MonkeyNode*)malloc(sizeof(MonkeyNode));

p->data=i;

q->next=p;//将新节点插入链表末尾

q=q->next;//将节点q指向末尾

}

q->next=L->next;//构造循环链表

p=L->next;

j=2;//设置j的初值为2,便于根据节点p删除p的后继节点

MonkeyNode*pd;//pd节点用于存放要删除的节点

while

(1){

if(p->next==p)//如果只剩下一个节点

break;

if(j==m){

pd=p->next;

p->next=pd->next;

deletepd;

j=1;

continue;

}else{

p=p->next;

}

j++;

}

}

printf("%d\n",p->data);

t2=clock();

printf("程序运行时间:

%fms\n",((double)t2-t1)/N);//计算运行100次的平均

if(count==12){

fclose(stream);

break;

}

}

}

猴子总数

100

200

300

400

500

600

700

800

900

1000

1100

1200

算法

时间

0.08

0.15

0.23

0.31

0.40

0.47

0.56

0.64

0.71

0.79

0.89

0.98

不难看出,该算法的时间复杂度要明显优于算法a和算法b。

其时间复杂度近似为O(n)。

d.递推

该算法不需要设置数组,只需要几个变量做记录就可以。

但是该算法需要递推出淘汰猴子过程中的关系。

第1步:

Sn:

Sn=0//当只有1只猴子时,编号为0的猴子将被淘汰

第2步:

Sn->Sn-1:

Sn-1=(Sn+m)%2;

第3步:

Sn-1->Sn-2:

Sn-2=(Sn-1+m)%3;

第i步:

Sn-i+2->Sn-i+1:

Sn-i+1=(Sn-i+2+m)%i;

第n步:

S2->S1:

S1=(S2+m)%n;

于是有了递推式:

S=0(i=1时)

S=(s+m)%i(i>1时)

#include

#include

#defineN1000

FILE*stream;

voidmain(){

intn,m,i,s,t1,t2,count=0;

stream=fopen("abc.txt","r");//读操作

while(fscanf(stream,"%d",&n)&&fscanf(stream,"%d",&m)){

count++;

t1=clock();

for(intj=0;j

s=0;

for(i=2;i<=n;i++){

s=(s+m)%i;

}

}

printf("%d\n",s+1);

t2=clock();

printf("程序运行时间:

%fms\n",((double)t2-t1)/N);//计算运行1000次的平均

if(count==12){

fclose(stream);

break;

}

}

}

猴子总数

100

200

300

400

500

600

700

800

900

1000

1100

1200

算法

时间

0.001

0.002

0.003

0.004

0.006

0.007

0.008

0.009

0.010

0.011

0.012

0.014

可见,该算法的时间度为O(n),而且其比较次数为0,只是不断的进行取模运算,而且其空间复杂度也是最小的。

有纵坐标就可以看出,该算法的效率是最优的。

3.附加实验与思考:

求斐波那契序列

文件x.txt中的内容为:

36912151821242730

用两种不同的算法求斐波那契序列,算法a运用递归求解,算法二运用动态规划。

两种算法执行的时间均为求解1000次取得的平均值,测试数据通过读文件x.txt得到,及计算3、6、9…30的斐波那契序列。

a.递归求解

#include

#include

#defineN1000

FILE*stream;

longF(intn);

voidmain()

{

intt1,t2,count=0,n;

longresult;

stream=fopen("x.txt","r");//读操作

while(count<10){

fscanf(stream,"%d",&n);

t1=clock();

for(inti=0;i

result=F(n);

if(i==0)

printf("%ld\n",result);

}

t2=clock();

printf("程序执行时间为:

%f\n",((double)t2-t1)/N);

count++;

}

fclose(stream);

}

longF(intn){

if(n==0)

return0;

elseif(n==1)

return1;

else

returnF(n-1)+F(n-2);

}

运行程序得到时间统计表和曲线图如下:

n

3

6

9

12

15

18

21

24

27

30

算法

时间

0.000

0.002

0.005

0.018

0.049

0.206

0.873

4.296

16.227

68.402

由曲线图可以看出,递归算法,随着数字变大,算法运行时间急剧上升,时间复杂度相当高,由于在递归过程中设置很多断点,并且需要重复计算,下面运用动态规划对算法进行优化。

b.动态规划求解

#include

#include

#include

#defineN1000

FILE*stream;

longF(intn);

voidmain()

{

intt1,t2,count=0,n;

longresult;

stream=fopen("x.txt","r");//读操作

while(count<10){

fscanf(stream,"%d",&n);

t1=clock();

for(inti=0;i

result=F(n);

if(i==0)

printf("%ld\n",result);

}

t2=clock();

printf("程序执行时间为:

%f\n",((double)t2-t1)/N);

count++;

}

fclose(stream);

}

longF(intn)//婓波那契----动态规划//

{

if(n<=0)

return0;

if(n==1)

return1;

long*a=(long*)malloc((n+1)*sizeof(long));

a[0]=0;

a[1]=1;

for(inti=2;i<=n;i++)

a[i]=a[i-1]+a[i-2];

returna[n];

}

n

3

6

9

12

15

18

21

24

27

30

算法

时间

0.001

0.001

0.001

0.001

0.001

0.001

0.001

0.001

0.001

0.002

由曲线图可见随着数字增大,纵坐标值得变化非常小,该算法的时间复杂度为O(n)

分析和总结、

在以前学习过程中,我只是要求把算法转化为程序,运行没有bug就可以了,没有关注算法执行的效率和时间复杂度。

在本实验中,我把猴子选大王问题通过4中算法实现,在平时做得时候,只是看一下这4种方法得到的结果是否正确。

通过自己实验进行比较和统计运行时间,绘制随着问题规模的扩大程序执行的时间的变化,有了非常深刻的体会,不同的算法得到的程序运行结果的差别是如此之大,这提醒了我,在以后的学习过程中不仅要追求程序运行结果的正确性,也要注重算法执行的效率,在保证算法结果正确的前提下,对算法不断优化,力争做到更好,这无疑是大有裨益的。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1