SWUST 算法分析与设计 实验报告1

Locker doors实验报告 

一、      实验内容及目的

实验内容

有一组数从1~n。从1开始,访问第i个数和它的倍数。以此类推。当i = n 结束时,求有多少个数的访问次数为奇数。

实验目的:

验证不同的算法,在不同的数据规模的情况下,运行时间的变化情况,绘制成曲线图,比较算法的优劣性。体会蛮力算法和非蛮力算法的区别,以及蛮力算法的优缺点。

分析的指标:

在较大数据规模的情况下的蛮力算法和非蛮力算法代码运行时间以及代码占用的空间。

二、实验方案

1实验硬件平台


实验环境:Windows10 + Dev-C++ + 硬盘大小100GB + 8核处理器 + 16GB内存

非蛮力算法伪代码:

非蛮力算法的思路就是找出其中包含的规律。

      1 = 1 * 1

      2 = 1 * 2

      3 = 1 * 3

4 = 1 * 4 或 2 * 2

5 = 1 * 5

6 = 1 * 6 或 2 * 3

7 = 1 * 7

8 = 1 * 8 或 2 * 4

9 = 1 * 9 或 3 * 3

……

我们发现,只有能够被开方的数他们被访问到的次数为奇数次。通过这个规律,可以判断在1~n的范围内有多少可以被开方的数,进而就能得出结果。

非蛮力算法伪代码:

        Fun1(int n)

       //功能:求在范围内访问次数为奇数的数的个数。 

       //输入:一个正整数n

     //输出:1~n中访问次数为奇数的数的个数。

                ans ← 0

                for i ← 1 to n do

                   if i^2 > n break

                   else ans++

                return ans

测试数据规模:一个整数,范围1~1x10^8

 蛮力算法:

      蛮力算法的思路就是根据题目进行模拟,申请布尔类型的数组,用正负表示柜子的开关。最后遍历计算布尔数组中有多少为正的数组单元的就是问题的答案。

蛮力算法伪代码:

Fun2(int n)

       //功能:求在范围内访问次数为奇数的数的个数。 

       //输入:一个正整数n

     //输出:1~n中访问次数为奇数的数的个数。

                ans ← 0

                for i ←1 to n do

                        for j ←1 to n do

                          if i * j > n

                                break

                          else

                                flag[i*j] = !flag[i*j]      //对flag数组取反表示或开或关

                for i ←1 to n do

                        if flag[i]

ans++;

return ans

测试数据规模:一个整数,范围1~1x10^8

运行时间采集方式:

2计时方法


使用系统自带函数clock(),这个函数返回从“开启这个程序进程”到“程序中调用clock()函数”时之间的CPU时钟计时单元数。在程序开始时先记录一个时钟数,在程序结束时再记录一个时钟数。将两个时钟数相减并除以一秒钟内CPU运行的时钟周期数(宏定义为CLOCKS_PER_SEC)就能得到程序运行时间。

 

三、结果及分析

蛮力算法:

ans ← 0

                for i ←1 to n do ……………………………………………………  n

                        for j ←1 to n do   …………………………………………………  n/i

                          if i * j > n

                                break

                          else

                                flag[i*j] = !flag[i*j]     

                for i ←1 to n do    ……………………………………………………  n

                        if flag[i]

ans++;

return ans

T(n) = n * n/i + n = (n^2)/i + n

其时间复杂度为O(n^2)

此算法占用的空间为一个flag数组,随着数据的增加,其空间容量也增加。

 

非蛮力算法:

        Fun1(int n)

       //功能:求在范围内访问次数为奇数的数的个数。 

       //输入:一个正整数n

     //输出:1~n中访问次数为奇数的数的个数。

                ans ← 0

                for i ← 1 to n do

                   if i^2 > n break   ……………………………………………………  √n

                   else ans++

                return ans

此算法的时间复杂度为O(√n)

空间占用少

表 1


 

结论:我们可以发现,非蛮力算法的时间几乎不变,而蛮力算法在数据规模小的时候时间与非蛮力算法差不多,但是在数据规模变大以后蛮力算法的运行时间就会变得很大。总之,非蛮力算法要优于蛮力算法。

 

四、总结

由于开始输入规模较小,导致在n<1000的范围内两个算法所用时间相差不大。曾一度以为是记录时间的程序出了问题,输出一直是0ms。后来发现是输入规模还不够大,在调大规模后有了明显结果。

由于int数据类型的限制,在int能表示的范围里未能看见非蛮力算法有明显的改变。但是在理论推导中,是认为这个算法的时间是应该有变化的。

本人写这篇报告时,发现了一个更好的非蛮力的算法:

        非蛮力算法伪代码:

        Fun3(int n)

       //功能:求在范围内访问次数为奇数的数的个数。 

       //输入:一个正整数n

     //输出:1~n中访问次数为奇数的数的个数。

                n = sqrt(n);

                return n;

这个算法的时间复杂度为O(1)而且稳定,是最好的算法。

 

五、参考文献及附录

clayyjh. C语言 记录程序的执行时间[EB/OL] [2021-03-12].https://www.cnblogs.com/clayyjh/p/14526665.html

 小乔流水人家. C语言 查看运行程序所需要的时间和占用的内存[EB/OL] [2017-02-22].https://www.cnblogs.com/BeautyFuture/articles/6428551.html

 附录:

蛮力算法:

#include<bits/stdc++.h>

using namespace std;

bool flag[100000000+7] = {0};

int main() {

        int n ;

        int ans = 0;

        cin >> n ;

        clock_t start_time=clock();

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

                for(int j = 1 ; i*j <= n ; j++) {

                        flag[i*j] = !flag[i*j];

                }

        }

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

                if(flag[i]) ans++;

        }

        cout << ans << endl;

        clock_t end_time=clock();

        cout<< "Running time is: "<<static_cast<double>(end_time-start_time)/CLOCKS_PER_SEC<<"s"<<endl;

}

 

非蛮力算法:

#include<bits/stdc++.h>

using namespace std;

int main() {

        int n;

        cin >> n ;

        clock_t start_time=clock();

        int ans = 0;

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

                if(i * i > n) break;

                ans++;

        }

        cout << ans << endl;

        clock_t end_time=clock();

        cout<< "Running time is: "<<static_cast<double>(end_time-start_time)/CLOCKS_PER_SEC<<"ms"<<endl;

}

posted @ 2023-09-11 18:32  夏莱发电厂的Sensei  阅读(230)  评论(1)    收藏  举报