实验一:求整数和、切披萨和Hanoi(汉诺)塔等问题的求解
一、实验描述
用C语言编程实现求整数和,切披萨以及Hanoi塔等问题的求解,在程序中加入clock ()来计算求解时间,使用不同的输入值得到对应的时间值。分析算法的时间复杂度并与测量结果进行比较,如果存在差异,解释原因。
问题1——求整数和:输入一个正整数n,求1~n的所有正整数之和,即1+2+···+n。
问题2——切披萨:一块披萨(无厚度)切n刀,最多可以切成几块?输入正整数n,返回最多切成的块数。
问题3——Hanoi塔:
汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。
移动的规则如下:
1. 每次只能从一个柱子的最上面移动一个碟子到另外一个柱子上。
2. 不能将大碟子放到小碟子的上面。
按照前面这个规则,我们该怎么去移动这些碟子呢?
二、实验设计
- 求整数和问题:利用递归来计算n项和的值,输入9组大小分别为100,200,300,400,500,600,700,800,900的n;
- 切披萨问题:利用迭代的方式来计算切n刀后的pizza块数,输入9组大小分别为100,200,300,400,500,600,700,800,900的n;
- Hanoi塔问题:利用递归来求解Hanoi问题,输入大小为10至20的n;
- 定义两个时间类型变量start和end,分别用于记录一个函数执行前后的时间,将两个时间相减,便可以得到该函数的运行时间;
- 对于求整数和与切pizza问题,记录程序执行100000次所需的时间;对于Hanoi塔问题,记录程序执行1000次所需的时间,记录得到时间的2的对数值;分别用合适的Excel图表对它们进行描述。
三、实验实现过程
1.整数求和问题:
(1)定义int型变量n,把n作为求和函数的参数;
(2)定义time_t类型的变量start并调用clock()函数来记录函数开始执行时间;
(3)定义方法int sum(int n) //利用递归方法求解;
(4)定义time_t类型的变量end并调用clock()函数来记录函数结束时间。
(5)将求值函数体循环100000次,在函数执行前,加上代码: start=clock(); 函数执行后,加上代码:end=clock();
(6)打印(int)(end-start);
(7)重复5 次实验,得到平均数据;
(8)记录相应9组实验结果并绘制相应Excel图表。
2.切披萨问题:
(1)定义int型变量n,把n作为计算块数函数的参数;
(2)定义time_t类型的变量start并调用clock()函数来记录函数开始执行时间;
(3)定义方法sum(int n) //利用循环来求和;
(4)定义time_t类型的变量end并调用clock()函数来记录函数结束执行时间;
(5)将求值函数体循环100000次,在函数执行前,加上代码: start=clock(); 函数执行后,加上代码:end=clock();
(6)打印(int)(start-end);
(7)重复5 次实验,得到平均数据;
(8)记录相应9组实验结果并绘制相应Excel图表。
3.Hanoi Tower问题:
(1)定义int型变量n作为Hanoi塔的层数,n取10-20;
(2)定义time_t类型的变量start并调用clock()函数来记录开始时间;
(3)定义方法void hanoiTower (int n, char a, charb, char c),利用递归来求解问题,并将方法循环执行1000次;
(4)定义clock_t类型的变量end并调用clock()函数来记录函数结束执行时间;
(5)打印(int)(end-start);
(6)重复5 次实验,得到平均数据;
(7)记录相应9组数据并求2的对数,绘制出相应Excel图表。
四、实验结果
- 求整数和问题图表
求整数和(循环100000次) | |
n | time(ms) |
100 | 31 |
200 | 62 |
300 | 93 |
400 | 125 |
500 | 156 |
600 | 187 |
700 | 218 |
800 | 265 |
900 | 296 |
- 切披萨问题图表
切披萨(循环100000次) | |
n | time(ms) |
100 | 32 |
200 | 64 |
300 | 95 |
400 | 125 |
500 | 157 |
600 | 195 |
700 | 242 |
800 | 275 |
900 | 309 |
- Hanoi塔问题图表
Hanoi Tower问题(循环1000次) | ||
n | time(ms) | log2(time) |
10 | 3 | 1.584963 |
11 | 6 | 2.584963 |
12 | 12 | 3.584963 |
13 | 26 | 4.70044 |
14 | 49 | 5.61471 |
15 | 98 | 6.61471 |
16 | 212 | 7.72792 |
17 | 406 | 8.665336 |
18 | 838 | 9.710806 |
19 | 1569 | 10.61563 |
20 | 3063 | 11.58073 |
五、实验结论
1.算法时间复杂度分析
对于用递归方法求n项整数和与用迭代方法求切披萨所得的块数,它们的时间复杂度T(N)都等于O(N);Hanoi塔问题使用递归方法,有T(N)=2T(N-1)+1, T(1)=1消去系数和常量得T(N)=O(2^N);
2.与测量结果进行比对
求整数和问题与切披萨问题最后得到的结果曲线均为一条直线,n与时间t成线性关系,与算法时间复杂度分析所得的T(N)=O(N)吻合;Hanoi塔问题最后得到的结果曲线大致呈现出线性增长,与前面的分析吻合,曲线存在波动可能与CPU的内存分配与运行速度有关(n增大,2^n迅速增大,递归占用内存也迅速增加)。
六、代码
1.求整数和代码:
#include <stdio.h>
#include <time.h>
int main()
{
int sum(int n);
time_t start,end;
int result;
start=clock();
for(int i=0;i<100000;i++)
result=sum(900);
end=clock();
printf("the result of sum of %d is %d",100,result);
printf("\nthe time is:%d",(end-start));
return 0;
}
int sum(int n)
{
if(0==n)
return 0;
return sum(n-1)+n;
}
2.切披萨问题代码:
#include <stdio.h>
#include <time.h>
int main()
{
int pizza(int n);
time_t start,end;
int result;
start=clock();
for(int i=0;i<100000;i++)
result=pizza(900);
end=clock();
printf("the result is:%d",result);
printf("\nthe time is:%d",end-start);
}
int pizza(int n)
{
if(n==0)
return 1;
return pizza(n-1)+n;
}
3.Hanoi问题代码:
#include <stdio.h>
#include <time.h>
static void hanoiTower (int n, char a, char b, char c);
/* recursively move the tower */
void hanoiTower (int n, char a, char b, char c)
{
/* if there is one layer, move directly from source to target */
if (1 == n)
{
printf ("%c -> %c\n", a, c);
return;
}
/* move the top n-1 layers from source to temp */
hanoiTower (n-1, a, c, b);
/* move the bottom */
printf ("%c -> %c\n", a, c);
/* move the n-1 layers to target */
hanoiTower (n-1, b, a, c);
return;
}
main()
{
time_t start, end;
start = clock ();
for(int i=0;i<1000;i++)
{
hanoiTower (20, 'A', 'B', 'C');
}
end = clock ();
printf ("execution time: %d\n", end-start);
}