『算法学习笔记』9th day. 循环结构 & 计时器函数的使用

本文介绍了C语言编程中解决特定数学问题的方法,包括寻找四位完全平方数的特定模式、解决3n+1问题以及计算阶乘之和的末六位数。通过对算法优化和程序调试的讨论,帮助读者提高编程效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

例2-1 aabb
输出所有形如aabb的四位完全平方数
  1 #include<stdio.h>
  2 #include<math.h>
  3 int main()
  4 {
  5 #if 0
  6         //思路一 从aabb的可能性角度进行枚举
  7         int a,b,temp;
  8         for(a=1;a<=9;a++)
  9         {
 10                 for(b=0;b<=9;b++)
 11                 {
 12                         temp=a*1000+a*100+b*10+b;
 13                         //temp=a*1100+b*11;更好
 14                         //先求出平方跟,再看它是否是整数:用一个数和它的整数部分比较就可以
 15                         float c=sqrt(temp);
 16                         if(c==floor(c+0.5))
 17                         printf("%d\n",temp);
 18                         
 19                 }
 20         }
 21 #endif
 22 #if 1
 23         //思路二 枚举平方根a,从而避免开方操作 
 24         int a,b;
 25         for(a=1;;a++)
 26         {
 27                 b=a*a;//or use the pow function: pow(x,2)
 28                 if(b<1000) continue;
 29                 else if(b>9999) break;
 30                 else
 31                 {
 32                         int low, high;
 33                         low=b%100;
 34                         high=b/100;
 35                         if(((low%10)==(low/10))&&((high%10)==(high/10)))
 36                                 printf("%d\n",b);
 37                 }
 38         }
 39 
 40 
 41 
 42 #endif
 43         return 0;
 44 }


注意:
1.floor(x)返回x的整数部分, 
2.由于浮点数的计算(和函数)有可能存在一定的误差,所以改成四舍五入减小误差,用floor(x+0.5)和x比较!
3.由于 采用了条件continue 和break 所以 for的参数范围给是“残缺”的。





例题2-2.3n+1问题
对于任意大于1的自然数n,若n为奇数,则将n变为3n+1,否则变为n的一半。经过若干次变换,一定会使n变为1.输入n 输出变换次数。 n<10^9
  1 #include<stdio.h>
  2 int main()
  3 {
  4 #if 1
  5         int n,count;
  6         scanf("%d",&n);
  7         if(n>1)
  8         {
  9                 for(count=0;;count++){
 10                         if(n==1) break;
 11                         else
 12                         {
 13                                 if(n%2==1) n=3*n+1;
 14                                 else n=n/2;
 15                         }
 16                 }
 17         }
 18         printf("%d\n",count);
 19 #endif
 20 #if 0
 21         int n,count=0;
 22         scanf("%d",&n);
 23         while(n>1)
 24         {
 25                 if(n%2==1)
 26                 {
 27                         n=n*3+1;
 28                         printf("count=%d,n=%d",count,n);
 29                 }
 30                 else
 31                 {
 32                         n/=2;
 33                         printf("count=%d,n=%d",count,n);
 34                 }       
 35                 count++;
 36         }
 37         printf("%d\n",count);
 38 #endif
 39         return 0;
 40 }


注意:
这并不是真正那个的正确结果。比如输入987654321 采用第二段程序的时候结果是1 采用我的第一段程序的时候无法退出程序。
无法找出错误-> 调试! ->输出中间结果。
第二段代码的28行和33行 就是实例!
edward@edward:~/Desktop/Algorithm$ ./exa2-2
987654321
count=0,n=-13320043321
987654321虽然在n的范围内,但是乘法时候发生溢出!如做修改可以采用double型。


例题2-3.阶乘之和
输入n,计算S=1!+2!+3!+...+n!的末六位(不含前导0)。n<=10^6。
  1 #include<stdio.h>
  2 int main()
  3 {
  4         int i,j,n,temp=1;
  5         long sum=0;
  6         const int MOD =1000000;
  7         scanf("%d",&n);
  8         for(i=1;i<=n;i++)
  9         {
 10                 temp=temp*i;
 11                 printf("current i is %d, value of i! is %d\n ",i,temp);
 12                 sum+=temp;
 13         }
 14         printf("%ld\n",sum%MOD);
 15         return 0;
 16 }


测试程序
在输入100 的时候,发现输出是负数! 通过打印中间结果发现又是乘法溢出了。
定理:计算只包含加法,减法和乘法的整数表达式除以正整数n的余数,可以在每步计算后对n取余,结果不变。

改进之:


  1 #include<stdio.h>
  2 int main()
  3 {
  4         int i,j,n,temp=1;
  5         long sum=0;
  6         const int MOD =1000000;
  7         scanf("%d",&n);
  8         for(i=1;i<=n;i++)
  9         {
 10                 temp=temp*i % MOD;
 11                 printf("current i is %d, value of i! is %d\n ",i,temp);
 12                 sum+=temp;
 13         }
 14         printf("%ld\n",sum % MOD);
 15         return 0;

 16 }


为了观察程序运行的效率,引入一个“计时器”!


  1 #include<stdio.h>
  2 #include<time.h>
  3 int main()
  4 {
  5         int i,j,n,temp=1;
  6         long sum=0;
  7         const int MOD =1000000;
  8         scanf("%d",&n);
  9         for(i=1;i<=n;i++)
 10         {
 11                 temp=temp*i % MOD;
 12         //      printf("current i is %d, value of i! is %d\n ",i,temp);
 13                 sum+=temp;
 14         }
 15         printf("%ld\n",sum % MOD);
 16         printf("Time used =%.2lf\n",(double)clock()/CLOCKS_PER_SEC);
 17         return 0;
 18 }


注意:
1.关于计时器函数 clock()的使用
该函数返回程序目前为止运行的时间,这样在程序结束之前调用它,便可获知整个程序的运行时间。
但是CLOCKS_PER_SEC常数与操作系统相关的值,不能直接使用clock()的返回值,需要除以CLOCKS_PER_SEC
2.为了不把键盘输入的时间计算在程序运行的时间内,需要使用管道符号输入
echo 20|./exa2-3
3.输入从40开始答案始终不变。通过中间结果可以发现这是因为25!末尾有6个0,所以从这项开始就不会影响后面的答案!
edward@edward:~/Desktop/Algorithm$ echo 20 |./exa2-3 
820313
Time used =0.00
edward@edward:~/Desktop/Algorithm$ echo 40 |./exa2-3 
940313
Time used =0.00
edward@edward:~/Desktop/Algorithm$ echo 160 |./exa2-3 
940313
Time used =0.00
edward@edward:~/Desktop/Algorithm$ echo 10000 |./exa2-3 
940313
Time used =0.00
edward@edward:~/Desktop/Algorithm$ echo 12800 |./exa2-3 
940313
Time used =0.00
edward@edward:~/Desktop/Algorithm$ echo 51200 |./exa2-3 
940313
Time used =0.00
edward@edward:~/Desktop/Algorithm$ echo 5120000 |./exa2-3 
940313
Time used =0.04
对此,只需在for循环之前 加一句 if(n>25) n=25 即可解决效率和溢出问题!
事实上很多程序的运行时间与规模魔与n存在着近似的简单关系。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值