当前位置:编程学习 > C/C++ >>

C语言循环的小艺术

1. 质数判断

对于这个,很多人可能会直接这样写:

 

 

view plaincopy to clipboardprint?int isPrime(int n) //函数返回1表示是质数,返回0表示不是质数  

int i; 
for (i = 2; i < n; i++) 
if (n % i == 0) 
break; 
return i >= n; 

int isPrime(int n) //函数返回1表示是质数,返回0表示不是质数
{
int i;
for (i = 2; i < n; i++)
if (n % i == 0)
break;
return i >= n;
}

 

又或者,有的人知道平方根的优化:


view plaincopy to clipboardprint?int isPrime(int n) 

int i, s = (int)(sqrt((double)n) + 0.01); 
for (i = 2; i <= s; i++) 
if (n % i == 0) 
break; 
return i > s; 

int isPrime(int n)
{
int i, s = (int)(sqrt((double)n) + 0.01);
for (i = 2; i <= s; i++)
if (n % i == 0)
break;
return i > s;
}
再或者,消除偶数:
view plaincopy to clipboardprint?int isPrime(int n) 

int i, s = (int)(sqrt((double)n) + 0.01); 
if (n <= 3) return 1; 
if (n % 2 == 0) return 0; 
for (i = 3; i <= s; i += 2) 
if (n % i == 0) 
break; 
return i > s; 

int isPrime(int n)
{
int i, s = (int)(sqrt((double)n) + 0.01);
if (n <= 3) return 1;
if (n % 2 == 0) return 0;
for (i = 3; i <= s; i += 2)
if (n % i == 0)
break;
return i > s;
}
当然,这样还不是很够的话,我们可以考虑这个事实:
所有大于4的质数,被6除的余数只能是1或者5
比如接下来的5,7,11,13,17,19都满足

所以,我们可以特殊化先判断2和3
但后面的问题就出现了,因为并非简单的递增,从5开始是+2,+4,+2,+4,....这样递增的
这样的话,循环应该怎么写呢?

首先,我们定义一个步长变量step,循环大概是这样 for (i = 5; i <= s; i += step)
那么,就是每次循环,让step从2变4,或者从4变2
于是,可以这么写:
view plaincopy to clipboardprint?#include <stdio.h>  
#include <math.h>  
 
int isPrime(int n) 

int i, s = (int)(sqrt((double)n) + 0.01), step = 4; 
if (n <= 3) return 1; 
if (n % 2 == 0) return 0; 
if (n % 3 == 0) return 0; 
for (i = 5; i <= s; i += step) 

if (n % i == 0) 
break; 
step ^= 6; 

return i > s; 

 
int main() 

int n; 
for (n = 2; n < 100; ++n) //找出 2 - 100 的质数并输出  

if (isPrime(n)) printf("%d,", n); 

getchar(); 
return 0; 

#include <stdio.h>
#include <math.h>

int isPrime(int n)
{
int i, s = (int)(sqrt((double)n) + 0.01), step = 4;
if (n <= 3) return 1;
if (n % 2 == 0) return 0;
if (n % 3 == 0) return 0;
for (i = 5; i <= s; i += step)
{
if (n % i == 0)
break;
step ^= 6;
}
return i > s;
}

int main()
{
int n;
for (n = 2; n < 100; ++n) //找出 2 - 100 的质数并输出
{
if (isPrime(n)) printf("%d,", n);
}
getchar();
return 0;
}
如上代码,一个 step ^= 6; 完成step在2和4之间转换(这个 ^ 符号是C里的异或运算)
理由是,2化二进制是010,4是100,6是110,于是2异或4得到6:
2 ^ 4 => 6
6 ^ 2 => 4
6 ^ 4 => 2

于是利用异或,就可以构造这种步长在两个值之间来回变化的循环
思考题:前面说的是双值循环,那么如何构造三值或者四值循环?

 

2.菱形打印

很多人,打印菱形在控制台的思路是,把菱形上下拆分,分两段很接近的代码来打印,
其实这样代码很不好看,并且不好阅读
我们知道,要打印的图案是这种:
   *
  ***
 *****
  ***
   *

满足上下对称,左右对称,那么,你能不能也弄一个二重循环,同样是对称的?
很简单,首先我们要抛开习惯性思维,for循环不一定要在0开始或者0结束
我们可以让循环从 -c 到 c ,这样不就轻松产生一个对称的吗?(只要取个绝对值)
我们把菱形的中心看成是坐标0,0,那么,会输出星号的坐标,是 |x| + |y| <= c 的点

由此可得
view plaincopy to clipboardprint?#include <stdio.h>  
#define IABS(x) ( (x) >= 0 ? (x) : -(x) ) //定义一个计算绝对值的宏  
void print(int size) // size是这个菱形的半径,直径会是size * 2 + 1  

int x, y; 
for (y = -size; y <= size; y++) 

for (x = -size; x <= size; x++) 

if ( IABS(x) + IABS(y) <= size ) //x和y各自的绝对值的和,即 |x| + |y| <= size  
putchar('*'); 
else 
putchar(' '); 

putchar('\n'); 


 
int main() 

print(5); //输出一个半径为5的菱形  
getchar(); 
return 0; 

#include <stdio.h>
#define IABS(x) ( (x) >= 0 ? (x) : -(x) ) //定义一个计算绝对值的宏
void print(int size) // size是这个菱形的半径,直径会是size * 2 + 1
{
int x, y;
for (y = -size; y <= size; y++)
{
for (x = -size; x <= size; x++)
{
if ( IABS(x) + IABS(y) <= size ) //x和y各自的绝对值的和,即 |x| + |y| <= size
putchar('*');
else
putchar(' ');
}
putchar('\n');
}
}

int main()
{
print(5); //输出一个半径为5的菱形
getchar();
return 0;
}
如果我需要得到空心菱形呢?非常非常简单,因为菱形边界上的点,满足的是|x| + |y| == c
所以,我们只要把那个if里的小于等于号,改成双等于号 == 就可以了

再类似地,如果我不要*号,我要最外层是字母A,然后里一层是B这样呢?即:
    A
  ABA
ABCBA
  ABA
    A

那么,我们只要在putchar那里做一个字符计算:
view plaincopy to clipboardprint?void print(int size) // size是这个菱形的半径,直径会是size * 2 + 1  

int x, y; 
for (y = -size; y <= size; y++) 

for (x = -size; x <= size; x++) 

if ( IABS(x) + IABS(y) <= size ) //x和y各自的绝对值的和,即 |x| + |y| <= size  
putchar( 'A' + (size - IABS(x) - IABS(y)) ); //留意这里的计算方法  
else 
putchar(' '); 

putchar('\n'); 


void print(int size) // size是这个菱形的半径,直径会是size * 2 + 1
{
int x, y;
for (y = -size; y <= size; y++)
{
for (x = -size; x <= size; x++)
{
if ( IABS(x) + IABS(y) <= size ) //x和y各自的绝对值的和,即 |x| + |y| <= size
putchar( 'A' + (size - IABS(x) - IABS(y)) ); //留意这里的计算方法
else
putchar(' ');
}
putchar('\n');
}
}
类似地,如果我们要打印的是X形:
*   *
 * *
  *
 * *
*   *
同样可以利用这个思路完成,这题就作为思考题吧

 

3. 奇数阶幻方
所谓幻方(最基本的那种),就是横,竖,对角线上的数的和等于一个常数的数字方阵
4 3 8
9 5 1
补充:软件开发 , C语言 ,

CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,