第 4章 循环结构
4.1 当型循环与直到型循环
4.2 for 循 环
4.3 循环的嵌套与其他有关语句
4.4 程序举例
4.1 当型循环与直到型循环
4.1.1 当型循环结构
当型循环结构的流程图如图 4.1所示 。
当条件满足
循环体
图 4.1 当型循环结构流程图
在图 4.1中, 条件在程序中一般是一个逻辑表达式,
条件满足是指逻辑表达式的值为真 。 循环体可以是单个
语句, 也可以是由若干可执行语句组成的复合语句, 它
们是需要重复执行的操作 。
当型循环的执行过程是:当条件满足 ( 即逻辑表
达式的值为真 ) 时, 执行循环体中所包括的操作, 当循
环体执行完后, 将再次判断条件, 直到条件不满足 ( 即
逻辑表达式的值为假 ) 为止, 从而退出循环结构 。
实现当型循环结构的 C语句形式为
while (表达式 ) 循环体语句
功能:当表达式值 ≠0时,执行循环体,执行完
后继续判断表达式值,只有当表达式值= 0时才退
出循环。
例 4.2 从键盘输入各学生成绩, 并对 90分以
上 ( 包括 90分 ) 的学生人数进行计数, 直到输入
的成绩为负为止, 最后输出成绩在 90分以上的学
生人数 。
计数 cou nt = 0
输入成绩 gr ade
当 gr ade ≥ 0.0
gr ade ≥ 90,0
Y es No
C ou nt=cou nt+1
输入成绩 gr ade
输出 cou nt
图 4.3 例 4.2的流程图
其流程图如图 4.3所示。其中变量 count为整型,用于
对 90分以上的学生人数进行计数。
相应的 C程序如下:
#include "stdio.h"
main()
{ int count;
float grade;
count= 0;
scanf("%f",&grade);
while (grade>= 0.0)
{ if (grade>= 90.0) count= count+ 1;
scanf("%f",&grade);
}
printf("count= %d\n",count);
}
4.1.2 直到型循环结构
直到型循环结构的流程图如图 4.4所示 。
直到条件满足
循环体
图 4.4 直到型循环结构流程图
直到型循环的执行过程是, 首先执行循环体, 然后
判断条件 ( 即计算逻辑表达式 ), 如果条件满足 ( 即逻
辑表达式值为真 ), 则退出循环结构;如果条件不满足
( 即逻辑表达式值为假 ), 则继续执行循环体 。
实现直到型循环结构的 C语句形式为
do 循环体语句 while(表达式);
功能:先执行循环体, 然后判断表达式值, 若表达
式值 ≠0,则再次执行循环体, 如此循环, 直到表达式值
= 0为止 。
例 4.3 计算并输出下列级数和:
直到某项的绝对值小于 为止 。
?? ?????????? )1( )1(32 121 11S U M KK
K
104?
相应的流程图如图 4.5所示 。 其中 f用于改变每一项的符号,
因为这是一个各项符号相间的级数 。
s u m = 1,0, k = 0, f = 1,0
k = k + 1, f= – f
d = 1,0 /((k (k + 1 ))
s u m = s u m + f * d
直到 d < 10
– 4
输出 s u m 值
图 4.5 例 4.3的流程图
相应的 C程序如下:
#include "stdio.h"
main()
{ int k;
double sum,d,f;
sum= 1.0; k= 1; f= 1.0;
do
{ k= k+ 1; f=- f; d= 1.0/(k*(k+ 1)); sum= sum+ f*d; }
while(d>= 1.0e- 4);
printf("sum= %lf\n",sum);
}
4.1.3 当型循环结构与直到型循环结构的区别与联系
当型循环结构与直到型循环结构既有共同之处, 又有区
别 。 主要体现在以下几个方面 。
( 1)在当型循环中,其循环体可以一次也不执行(即执行
当型循环结构的一开始,其条件就不满足)。
( 2)不管是当型循环结构还是直到型循环结构,在循环体
内部必须要有能改变条件 (即逻辑表达式值 )的语句,否则将
造成死循环。
( 3) 对于有些问题既可以用当型循环结构来处理, 也可以
用直到型循环结构来处理 。
( 4) 不管是当型循环结构还是直到型循环结构, 其循环体
如果包含一个以上的语句, 应以复合语句形式出现 。
4.2 for 循 环
C语言提供的 for循环属于当型循环结构, 其一般形式为
for(表达式 1;表达式 2;表达式 3) 循环体语句(组)
它等价于下列的当型循环结构:
表达式 1;
while( 表达式 2)
{ 循环体语句
表达式 3;
}
下面对 for循环语句作几点说明:
( 1)在 for语句中,三个表达式中的任何一个表达式均可
省略,但其中的两个, ;, 不能省略。
( 2) 下列两个循环都是死循环:
for(表达式 1;;表达式 3) 循环体
与
for(;; ) 循环体
因为它们都没有用于判断循环是否结束的条件(即表达
式 2)。
( 3) for循环本质上也是当型循环结构,只不过它对于事
先可以确定循环次数的问题特别方便。
( 4) 在 for循环中, 循环体也可以是复合语句 ( 即用一对
花括号 { }括起来的语句组 ) 。
4.3 循环的嵌套与其他有关语句
4.3.1 循环的嵌套
所谓循环的嵌套是指一个循环体内又包含了另一个完整
的循环结构 。 C语言允许循环结构嵌套多层 。 循环的嵌套结构
又称为多重循环 。
例 4.6 计算并输出 10以内 (包括 10)所有自然数的阶乘
值。即计算 1!,2!,3!,4!,5!,6!,7!,8!,9!,10!。
采用的方法是, 对于 10以内的每一个自然数分别求它们
的阶乘值 。 其流程图如图 4.7所示 。 显然, 这是一个二重循环
结构 。
FO R N = 1 T O 1 0
S= 1,0
FO R K = 1 T O N
S= S* K
输出 S
图 4.7 例 4.6的流程图
相应的 C程序如下:
#include "stdio.h"
main()
{ int n,k;
double s;
for (n= 1; n<= 10; n= n+ 1)
{ s= 1.0;
for (k= 1; k<= n; k= k+ 1) s= s*k;
printf("%2d!= %16.7f\n ",n,s);
}
}
4.3.2 break 语句
C语言中的 break语句有以下两个功能:
( 1) 跳出 switch 结构;
( 2) 退出当前循环结构, 包括 while 结构, do… while 结
构和 for循环结构 。
4.3.3 continue 语句
continue语句的功能是结束本次循环的执行, 但不退
出循环结构 。
下面举两个例子来说明 continue语句的使用 。
例 4.10 输出 100~ 200之间所有能被 7或 9整除的自然数。
相应的 C程序如下:
#include "stdio.h"
main()
{ int n;
for (n= 100; n<= 200; n= n+ 1)
{ if (n%7!= 0)&&(n%9!= 0)) continue; /*结束本次循环,继续进行下
次循环 */
printf("%d \n",n);
}
}
实际上, 上述程序等价于
#include "stdio.h"
main()
{ int n;
for (n= 100; n<= 200; n= n+ 1)
{ if (n%7== 0) | | (n%9== 0)) printf("%d \n",n);
}
}
4.4 程序举例
4.4.1 列举算法
所谓列举算法,是指根据提出的问题,列举所有可能的
情况,并根据条件检验哪些是需要的,哪些是不需要的。
例 4.11 某单位要在 A,B,C,D,E,F 6人中选派若干人去
执行一项任务, 选人的条件如下:
( 1) 若 C不去, 则 B也不去;
( 2) C和 D两人中去一个;
( 3) D和 E要么都去, 要么都不去;
( 4) A,B,F3人中要去两个;
( 5) C和 F不能一起去:
( 6) E和 F两人中至少去一个 。
问应该选哪几个人去?
C程序如下:
#include "stdio.h"
main()
{ int a,b,c,d,e,f;
for (a= 0; a<= 1; a++ )
for (b= 0; b<= 1; b++ )
for (c= 0; c<= 1; c++ )
for (d= 0; d<= 1; d++ )
for (e= 0; e<= 1; e++ )
for (f= 0; f<= 1; f++ )
if ((b+ c== 0 | | c== 1) &&
(c+ d== 1) &&
(d+ e== 0 | | d+ e== 2) &&
(a+ b+ f== 2) &&
(c+ f!= 2) &&
(e+ f> 1))
{ printf("A will %s be assigned.\n",a?"":"not");
printf("B will %s be assigned.\n",b?"","not");
printf("C will %s be assigned.\n",c?"","not");
printf("D will %s be assigned.\n",d?"","not");
printf("E will %s be assigned.\n",e?"","not");
printf("F will %s be assigned.\n",f?"","not");
}
}
4.4.2 密码问题
在报文通信中, 为使报文保密, 发报人往往要按一定规
律将其加密, 收报人再按约定的规律将其解密 ( 即将其译回
原文 ) 。
例 4.13 从键盘输入一行字符, 将其中的英文字母进行加密输
出 ( 非英文字母不用加密 ) 。
C程序如下:
#include "stdio.h"
main()
{ char c;
int k;
printf("input k:");
scanf("%d",&k);
scanf("%c",&c); /*吃掉上次输入的回车符 */
c= getchar();
while(c!= '\n')
{ if ((c>= 'a' && c<= 'z') | | (c>= 'A' && c<= 'Z'))
{ c= c+ k;
if (c> 'z' | | (c> 'Z' && c<= 'Z'+ k))
c= c- 26;
}
printf("%c",c);
c= getchar();
}
}
4.4.3 对分法求方程实根
设非线性方程为
f (x)= 0
用对分法求在区间 [a,b]上的实根 。
具体方法如下:
从区间端点 x0= a出发, 以 h为步长, 逐步往后进行扫描 。
对于每一个被扫描的子区间 [xi,xi+ 1](其中 xi+ 1= xi+ h)作如
下处理:
若在子区间两个端点上的函数值 f (xi)与 f (xi+ 1)同号, 则说
明在该子区间上没有实根, 将扫描下一个子区间;否则说明在
该子区间上至少有一个实根 。 此时就可以在该子区间上采用对
分法进一步搜索实根 。
对分法的基本过程如下:
取子区间 [xi,xi+ 1]的中点
如果 f(x)与 f(xi)同号,则令 xi= x;否则令 xi+ 1= x。
然后重复这个过程,直到满足条件
为止。其中 ε为事先给定的精度要求。
2
1??? ii xxx
???? || 1 ii xx
图 4.9 对分法求方程实根的流程图
X 1= A, Y 1= F(X 1), X 2= X 1+ H, Y 2= F(X 2)
当 X1 ≤ B
Y 1* Y 2 > 0
Y e s No
FL A G = 0
当 FL A G = 0
X = (X 1+ X 2)/ 2
| X 2 – X 1| < ?
Y e s No
输出 X
X 1= X + H /2
Y 1= F(X 1)
X 2= X 1+ H
Y 2= F(X 2)
FL A G = 1
X 1= X 2
Y 1= Y 2
X 2= X 1+ H
Y 2= F(X 2)
Y = F(X )
Y 1* Y < 0
X 2= X
Y 2= Y
X 1= X
Y 1= Y
Y e s No
对分法求方程实根的流程图如图 4.9所示。
例 4.15 用对分法求方程
f (x)= x2―6 x―1 = 0
在区间 [- 10,10]上的实根, 即 A=- 10,B= 10。 取扫
描步长 H= 0.1,精度要求 。
? ? ?10 6
相应的 C程序如下:
#include "stdio.h"
main()
{ int flag;
double a= ― 10.0,b= 10.0,h= 0.1,x1,y1,x2,y2,x,y;
x1= a; y1= x1*x1- 6*x1- 1.0;
x2= x1+ h; y2= x2*x2- 6*x2- 1.0;
while (x1<= b)
{ if (y1*y2> 0.0)
{ x1= x2; y1= y2; x2= x1+ h; y2= x2*x2- 6*x2- 1.0; }
else
{ flag= 0;
while (flag== 0)
{ x= (x1+ x2)/2;
if (fabs(x2- x1)< 0.000001)
{ printf("x= %11.7f\n",x);
x1= x+ 0.5*h; y1= x1*x1- 6*x1- 1.0;
x2= x1+ h; y2= x2*x2- 6*x2- 1.0;
flag= 1;
}
else
{ y= x*x- 6*x- 1.0;
if (y1*y< 0.0) { x2= x; y2= y; }
else { x1= x; y1= y; }
}
}
}
}
}
4.4.4 迭代法求方程实根
设非线性方程为
f (x)= 0
用迭代法求一个实根的基本方法如下:
首先将方程
f (x)= 0
改写成便于迭代的格式
x= φ(x)
然后初步估计方程实根的一个初值 x0,作如下迭代:
,n= 0,1,2,…
直到满足条件
| |<ε
或者迭代了足够多的次数还不满足这个条件为止 。 其中 ε为事
先给定的精度要求 。
)(1 nn xΦx ??
nn xx ??1
反映上述过程的流程图如图 4.10所示 。
给定初值 x,精度要求
?
输入最大迭代次数 M
x
0
=x
输出,F A IL !,
x= ? (x
0
)
M =M – 1
直到 M =0 或 ?x – x
0
?<
?
M =0
Y es No
输出 x
图 4.10 迭代法求方程实根流程图
例 4.16 求非线性方程 x- 1- arctanx= 0 的一个实根 。 取初值 x0
= 1.0,精度要求 ε= 0.000001。 并改写成如下迭代格式:
nn xx a r c t a n11 ???
相应的 C程序如下:
#include "stdio.h"
#include "math.h"
main()
{ int m;
double x= 1.0,eps= 0.000001,x0;
printf("input m,");
scanf("%d",&m); /*输入最大迭代次数 */
do { x0= x; x= 1.0+ atan(x0); m= m- 1; }
while ((m!= 0)&&(fabs(x- x0)>= eps);
if (m== 0) printf("FAIL!\n ");
else printf("x= %11.f\n",x);
}
4.4.5 牛顿法求方程实根
设非线性方程为
f (x)= 0
在选取一个初值 x0后, 牛顿迭代格式为
实际上牛顿迭代格式是一种特殊的简单迭代格式, 相当于
上述迭代过程一直进行到满足条件
| |<ε
或者迭代了足够多的次数还不满足这个条件为止 。 其中 ε为事
先给定的精度要求 。
)(
)(
1
n
nnn
xf
xfxx
????
)(
)()(
n
n
nn xf
xfxxΦ
???
nn xx ??1
反映上述过程的流程图如图 4.11所示 。
给定初值 x,精度要求
?
输入最大迭代次数 M
x
0
=x
输出,F A IL !,
x = x
0
– f
(x
0
)/ f ′ (x
0
)
M = M – 1
直到 M = 0 或 ?x – x
0
?<
?
M = 0
Y e s No
输出 x
图 4.11 牛顿法求方程实根流程图
例 4.17 求非线性方程 x- 1- cosx= 0的一个实根 。 取初值 x0
= 1.0,精度要求 ε= 0.000001。 其牛顿迭代格式为
其中 f (xn)= xn― 1―cos xn,f? (xn)= 1+ sin xn。
n
nn
nn x
xxxx
s i n1
c o s1
1 ?
????
?
相应的 C程序如下:
#include "stdio.h"
#include "math.h"
main()
{ int m;
double x= 1.0,eps= 0.000001,x0;
printf("input m,");
scanf("%d",&m); /*输入最大迭代次数 */
do
{ x0= x; x= x0- (x0- 1- cos(x0))/(1.0+ sin(x0)); m= m- 1; }
while ((m!= 0)&&(fabs(x- x0)>= eps);
if (m== 0) printf("FAIL!\n ");
else printf("x= %11.f\n",x);
}
4.4.6 梯形法求定积分
设定积分为
由微积分的知识可以知道, 该积分值的几何意义是在区间 [a,
b]内的曲线 f (x)下的面积, 如图 4.12所示 。
?? ba xxfS d)(
Y
0
X
a x i x i +1 b
f ( x )
h
图 4.12 定积分几何意义
梯形法求定积分的基本思想是:
首先将积分区间 [a,b]n等分,得到 n个子区间 [xi,xi+ 1](i=
0,1,2,…, n- 1),每一个子区间的长度为 h= (b- a)/n,如
图 4.12所示,其中 xi= a+ i× h。
然后在每一个子区间上用梯形的面积
来近似代替该子区间上小长条的面积 。
最后将所有小长条的面积近似值 Si累加就可得到积分值的近
似值 。 即
S=
=
)]()([2 1??? iii xfxfhS
?ba xxf d)( )]()([2 1
1
0
?
?
?
?? ? i
n
i
i xfxf
h
)()]()([
2
1
1
?
?
?
??
n
i
ixfhbfaf
h
其流程图如图 4.13所示 。
输入等分数 n
给 a, b 赋值
h =(b – a)/n
S =h [ f (a)+f (b )] /2
i=1, P =0
当 i<n
X =a +i* h
P =P +f (x)
S =S+P * h
输出 S
图 4.13 梯形法求定积分
例 4.18 用梯形法求积分
dx
即 a= 0,b= 1,f(x)= 。
? ?? 10 2e xS
2e x?
相应的 C程序如下:
#include "stdio.h"
#include "math.h"
main()
{ int n,k;
double a= 0.0,b= 1.0,h,s,p,x;
printf("input n,");
scanf("%d",&n); /*输入等分数 */
h= (b- a)/n;
s= h*(exp(- a*a)+ exp(- b*b))/2;
p= 0.0;
for (k= 1; k< n; k= k+ 1)
{ x= a+ k*h; p= p+ exp(- x*x); }
s= s+ p*h;
printf("s= %11.7f\n",s);
}
4.1 当型循环与直到型循环
4.2 for 循 环
4.3 循环的嵌套与其他有关语句
4.4 程序举例
4.1 当型循环与直到型循环
4.1.1 当型循环结构
当型循环结构的流程图如图 4.1所示 。
当条件满足
循环体
图 4.1 当型循环结构流程图
在图 4.1中, 条件在程序中一般是一个逻辑表达式,
条件满足是指逻辑表达式的值为真 。 循环体可以是单个
语句, 也可以是由若干可执行语句组成的复合语句, 它
们是需要重复执行的操作 。
当型循环的执行过程是:当条件满足 ( 即逻辑表
达式的值为真 ) 时, 执行循环体中所包括的操作, 当循
环体执行完后, 将再次判断条件, 直到条件不满足 ( 即
逻辑表达式的值为假 ) 为止, 从而退出循环结构 。
实现当型循环结构的 C语句形式为
while (表达式 ) 循环体语句
功能:当表达式值 ≠0时,执行循环体,执行完
后继续判断表达式值,只有当表达式值= 0时才退
出循环。
例 4.2 从键盘输入各学生成绩, 并对 90分以
上 ( 包括 90分 ) 的学生人数进行计数, 直到输入
的成绩为负为止, 最后输出成绩在 90分以上的学
生人数 。
计数 cou nt = 0
输入成绩 gr ade
当 gr ade ≥ 0.0
gr ade ≥ 90,0
Y es No
C ou nt=cou nt+1
输入成绩 gr ade
输出 cou nt
图 4.3 例 4.2的流程图
其流程图如图 4.3所示。其中变量 count为整型,用于
对 90分以上的学生人数进行计数。
相应的 C程序如下:
#include "stdio.h"
main()
{ int count;
float grade;
count= 0;
scanf("%f",&grade);
while (grade>= 0.0)
{ if (grade>= 90.0) count= count+ 1;
scanf("%f",&grade);
}
printf("count= %d\n",count);
}
4.1.2 直到型循环结构
直到型循环结构的流程图如图 4.4所示 。
直到条件满足
循环体
图 4.4 直到型循环结构流程图
直到型循环的执行过程是, 首先执行循环体, 然后
判断条件 ( 即计算逻辑表达式 ), 如果条件满足 ( 即逻
辑表达式值为真 ), 则退出循环结构;如果条件不满足
( 即逻辑表达式值为假 ), 则继续执行循环体 。
实现直到型循环结构的 C语句形式为
do 循环体语句 while(表达式);
功能:先执行循环体, 然后判断表达式值, 若表达
式值 ≠0,则再次执行循环体, 如此循环, 直到表达式值
= 0为止 。
例 4.3 计算并输出下列级数和:
直到某项的绝对值小于 为止 。
?? ?????????? )1( )1(32 121 11S U M KK
K
104?
相应的流程图如图 4.5所示 。 其中 f用于改变每一项的符号,
因为这是一个各项符号相间的级数 。
s u m = 1,0, k = 0, f = 1,0
k = k + 1, f= – f
d = 1,0 /((k (k + 1 ))
s u m = s u m + f * d
直到 d < 10
– 4
输出 s u m 值
图 4.5 例 4.3的流程图
相应的 C程序如下:
#include "stdio.h"
main()
{ int k;
double sum,d,f;
sum= 1.0; k= 1; f= 1.0;
do
{ k= k+ 1; f=- f; d= 1.0/(k*(k+ 1)); sum= sum+ f*d; }
while(d>= 1.0e- 4);
printf("sum= %lf\n",sum);
}
4.1.3 当型循环结构与直到型循环结构的区别与联系
当型循环结构与直到型循环结构既有共同之处, 又有区
别 。 主要体现在以下几个方面 。
( 1)在当型循环中,其循环体可以一次也不执行(即执行
当型循环结构的一开始,其条件就不满足)。
( 2)不管是当型循环结构还是直到型循环结构,在循环体
内部必须要有能改变条件 (即逻辑表达式值 )的语句,否则将
造成死循环。
( 3) 对于有些问题既可以用当型循环结构来处理, 也可以
用直到型循环结构来处理 。
( 4) 不管是当型循环结构还是直到型循环结构, 其循环体
如果包含一个以上的语句, 应以复合语句形式出现 。
4.2 for 循 环
C语言提供的 for循环属于当型循环结构, 其一般形式为
for(表达式 1;表达式 2;表达式 3) 循环体语句(组)
它等价于下列的当型循环结构:
表达式 1;
while( 表达式 2)
{ 循环体语句
表达式 3;
}
下面对 for循环语句作几点说明:
( 1)在 for语句中,三个表达式中的任何一个表达式均可
省略,但其中的两个, ;, 不能省略。
( 2) 下列两个循环都是死循环:
for(表达式 1;;表达式 3) 循环体
与
for(;; ) 循环体
因为它们都没有用于判断循环是否结束的条件(即表达
式 2)。
( 3) for循环本质上也是当型循环结构,只不过它对于事
先可以确定循环次数的问题特别方便。
( 4) 在 for循环中, 循环体也可以是复合语句 ( 即用一对
花括号 { }括起来的语句组 ) 。
4.3 循环的嵌套与其他有关语句
4.3.1 循环的嵌套
所谓循环的嵌套是指一个循环体内又包含了另一个完整
的循环结构 。 C语言允许循环结构嵌套多层 。 循环的嵌套结构
又称为多重循环 。
例 4.6 计算并输出 10以内 (包括 10)所有自然数的阶乘
值。即计算 1!,2!,3!,4!,5!,6!,7!,8!,9!,10!。
采用的方法是, 对于 10以内的每一个自然数分别求它们
的阶乘值 。 其流程图如图 4.7所示 。 显然, 这是一个二重循环
结构 。
FO R N = 1 T O 1 0
S= 1,0
FO R K = 1 T O N
S= S* K
输出 S
图 4.7 例 4.6的流程图
相应的 C程序如下:
#include "stdio.h"
main()
{ int n,k;
double s;
for (n= 1; n<= 10; n= n+ 1)
{ s= 1.0;
for (k= 1; k<= n; k= k+ 1) s= s*k;
printf("%2d!= %16.7f\n ",n,s);
}
}
4.3.2 break 语句
C语言中的 break语句有以下两个功能:
( 1) 跳出 switch 结构;
( 2) 退出当前循环结构, 包括 while 结构, do… while 结
构和 for循环结构 。
4.3.3 continue 语句
continue语句的功能是结束本次循环的执行, 但不退
出循环结构 。
下面举两个例子来说明 continue语句的使用 。
例 4.10 输出 100~ 200之间所有能被 7或 9整除的自然数。
相应的 C程序如下:
#include "stdio.h"
main()
{ int n;
for (n= 100; n<= 200; n= n+ 1)
{ if (n%7!= 0)&&(n%9!= 0)) continue; /*结束本次循环,继续进行下
次循环 */
printf("%d \n",n);
}
}
实际上, 上述程序等价于
#include "stdio.h"
main()
{ int n;
for (n= 100; n<= 200; n= n+ 1)
{ if (n%7== 0) | | (n%9== 0)) printf("%d \n",n);
}
}
4.4 程序举例
4.4.1 列举算法
所谓列举算法,是指根据提出的问题,列举所有可能的
情况,并根据条件检验哪些是需要的,哪些是不需要的。
例 4.11 某单位要在 A,B,C,D,E,F 6人中选派若干人去
执行一项任务, 选人的条件如下:
( 1) 若 C不去, 则 B也不去;
( 2) C和 D两人中去一个;
( 3) D和 E要么都去, 要么都不去;
( 4) A,B,F3人中要去两个;
( 5) C和 F不能一起去:
( 6) E和 F两人中至少去一个 。
问应该选哪几个人去?
C程序如下:
#include "stdio.h"
main()
{ int a,b,c,d,e,f;
for (a= 0; a<= 1; a++ )
for (b= 0; b<= 1; b++ )
for (c= 0; c<= 1; c++ )
for (d= 0; d<= 1; d++ )
for (e= 0; e<= 1; e++ )
for (f= 0; f<= 1; f++ )
if ((b+ c== 0 | | c== 1) &&
(c+ d== 1) &&
(d+ e== 0 | | d+ e== 2) &&
(a+ b+ f== 2) &&
(c+ f!= 2) &&
(e+ f> 1))
{ printf("A will %s be assigned.\n",a?"":"not");
printf("B will %s be assigned.\n",b?"","not");
printf("C will %s be assigned.\n",c?"","not");
printf("D will %s be assigned.\n",d?"","not");
printf("E will %s be assigned.\n",e?"","not");
printf("F will %s be assigned.\n",f?"","not");
}
}
4.4.2 密码问题
在报文通信中, 为使报文保密, 发报人往往要按一定规
律将其加密, 收报人再按约定的规律将其解密 ( 即将其译回
原文 ) 。
例 4.13 从键盘输入一行字符, 将其中的英文字母进行加密输
出 ( 非英文字母不用加密 ) 。
C程序如下:
#include "stdio.h"
main()
{ char c;
int k;
printf("input k:");
scanf("%d",&k);
scanf("%c",&c); /*吃掉上次输入的回车符 */
c= getchar();
while(c!= '\n')
{ if ((c>= 'a' && c<= 'z') | | (c>= 'A' && c<= 'Z'))
{ c= c+ k;
if (c> 'z' | | (c> 'Z' && c<= 'Z'+ k))
c= c- 26;
}
printf("%c",c);
c= getchar();
}
}
4.4.3 对分法求方程实根
设非线性方程为
f (x)= 0
用对分法求在区间 [a,b]上的实根 。
具体方法如下:
从区间端点 x0= a出发, 以 h为步长, 逐步往后进行扫描 。
对于每一个被扫描的子区间 [xi,xi+ 1](其中 xi+ 1= xi+ h)作如
下处理:
若在子区间两个端点上的函数值 f (xi)与 f (xi+ 1)同号, 则说
明在该子区间上没有实根, 将扫描下一个子区间;否则说明在
该子区间上至少有一个实根 。 此时就可以在该子区间上采用对
分法进一步搜索实根 。
对分法的基本过程如下:
取子区间 [xi,xi+ 1]的中点
如果 f(x)与 f(xi)同号,则令 xi= x;否则令 xi+ 1= x。
然后重复这个过程,直到满足条件
为止。其中 ε为事先给定的精度要求。
2
1??? ii xxx
???? || 1 ii xx
图 4.9 对分法求方程实根的流程图
X 1= A, Y 1= F(X 1), X 2= X 1+ H, Y 2= F(X 2)
当 X1 ≤ B
Y 1* Y 2 > 0
Y e s No
FL A G = 0
当 FL A G = 0
X = (X 1+ X 2)/ 2
| X 2 – X 1| < ?
Y e s No
输出 X
X 1= X + H /2
Y 1= F(X 1)
X 2= X 1+ H
Y 2= F(X 2)
FL A G = 1
X 1= X 2
Y 1= Y 2
X 2= X 1+ H
Y 2= F(X 2)
Y = F(X )
Y 1* Y < 0
X 2= X
Y 2= Y
X 1= X
Y 1= Y
Y e s No
对分法求方程实根的流程图如图 4.9所示。
例 4.15 用对分法求方程
f (x)= x2―6 x―1 = 0
在区间 [- 10,10]上的实根, 即 A=- 10,B= 10。 取扫
描步长 H= 0.1,精度要求 。
? ? ?10 6
相应的 C程序如下:
#include "stdio.h"
main()
{ int flag;
double a= ― 10.0,b= 10.0,h= 0.1,x1,y1,x2,y2,x,y;
x1= a; y1= x1*x1- 6*x1- 1.0;
x2= x1+ h; y2= x2*x2- 6*x2- 1.0;
while (x1<= b)
{ if (y1*y2> 0.0)
{ x1= x2; y1= y2; x2= x1+ h; y2= x2*x2- 6*x2- 1.0; }
else
{ flag= 0;
while (flag== 0)
{ x= (x1+ x2)/2;
if (fabs(x2- x1)< 0.000001)
{ printf("x= %11.7f\n",x);
x1= x+ 0.5*h; y1= x1*x1- 6*x1- 1.0;
x2= x1+ h; y2= x2*x2- 6*x2- 1.0;
flag= 1;
}
else
{ y= x*x- 6*x- 1.0;
if (y1*y< 0.0) { x2= x; y2= y; }
else { x1= x; y1= y; }
}
}
}
}
}
4.4.4 迭代法求方程实根
设非线性方程为
f (x)= 0
用迭代法求一个实根的基本方法如下:
首先将方程
f (x)= 0
改写成便于迭代的格式
x= φ(x)
然后初步估计方程实根的一个初值 x0,作如下迭代:
,n= 0,1,2,…
直到满足条件
| |<ε
或者迭代了足够多的次数还不满足这个条件为止 。 其中 ε为事
先给定的精度要求 。
)(1 nn xΦx ??
nn xx ??1
反映上述过程的流程图如图 4.10所示 。
给定初值 x,精度要求
?
输入最大迭代次数 M
x
0
=x
输出,F A IL !,
x= ? (x
0
)
M =M – 1
直到 M =0 或 ?x – x
0
?<
?
M =0
Y es No
输出 x
图 4.10 迭代法求方程实根流程图
例 4.16 求非线性方程 x- 1- arctanx= 0 的一个实根 。 取初值 x0
= 1.0,精度要求 ε= 0.000001。 并改写成如下迭代格式:
nn xx a r c t a n11 ???
相应的 C程序如下:
#include "stdio.h"
#include "math.h"
main()
{ int m;
double x= 1.0,eps= 0.000001,x0;
printf("input m,");
scanf("%d",&m); /*输入最大迭代次数 */
do { x0= x; x= 1.0+ atan(x0); m= m- 1; }
while ((m!= 0)&&(fabs(x- x0)>= eps);
if (m== 0) printf("FAIL!\n ");
else printf("x= %11.f\n",x);
}
4.4.5 牛顿法求方程实根
设非线性方程为
f (x)= 0
在选取一个初值 x0后, 牛顿迭代格式为
实际上牛顿迭代格式是一种特殊的简单迭代格式, 相当于
上述迭代过程一直进行到满足条件
| |<ε
或者迭代了足够多的次数还不满足这个条件为止 。 其中 ε为事
先给定的精度要求 。
)(
)(
1
n
nnn
xf
xfxx
????
)(
)()(
n
n
nn xf
xfxxΦ
???
nn xx ??1
反映上述过程的流程图如图 4.11所示 。
给定初值 x,精度要求
?
输入最大迭代次数 M
x
0
=x
输出,F A IL !,
x = x
0
– f
(x
0
)/ f ′ (x
0
)
M = M – 1
直到 M = 0 或 ?x – x
0
?<
?
M = 0
Y e s No
输出 x
图 4.11 牛顿法求方程实根流程图
例 4.17 求非线性方程 x- 1- cosx= 0的一个实根 。 取初值 x0
= 1.0,精度要求 ε= 0.000001。 其牛顿迭代格式为
其中 f (xn)= xn― 1―cos xn,f? (xn)= 1+ sin xn。
n
nn
nn x
xxxx
s i n1
c o s1
1 ?
????
?
相应的 C程序如下:
#include "stdio.h"
#include "math.h"
main()
{ int m;
double x= 1.0,eps= 0.000001,x0;
printf("input m,");
scanf("%d",&m); /*输入最大迭代次数 */
do
{ x0= x; x= x0- (x0- 1- cos(x0))/(1.0+ sin(x0)); m= m- 1; }
while ((m!= 0)&&(fabs(x- x0)>= eps);
if (m== 0) printf("FAIL!\n ");
else printf("x= %11.f\n",x);
}
4.4.6 梯形法求定积分
设定积分为
由微积分的知识可以知道, 该积分值的几何意义是在区间 [a,
b]内的曲线 f (x)下的面积, 如图 4.12所示 。
?? ba xxfS d)(
Y
0
X
a x i x i +1 b
f ( x )
h
图 4.12 定积分几何意义
梯形法求定积分的基本思想是:
首先将积分区间 [a,b]n等分,得到 n个子区间 [xi,xi+ 1](i=
0,1,2,…, n- 1),每一个子区间的长度为 h= (b- a)/n,如
图 4.12所示,其中 xi= a+ i× h。
然后在每一个子区间上用梯形的面积
来近似代替该子区间上小长条的面积 。
最后将所有小长条的面积近似值 Si累加就可得到积分值的近
似值 。 即
S=
=
)]()([2 1??? iii xfxfhS
?ba xxf d)( )]()([2 1
1
0
?
?
?
?? ? i
n
i
i xfxf
h
)()]()([
2
1
1
?
?
?
??
n
i
ixfhbfaf
h
其流程图如图 4.13所示 。
输入等分数 n
给 a, b 赋值
h =(b – a)/n
S =h [ f (a)+f (b )] /2
i=1, P =0
当 i<n
X =a +i* h
P =P +f (x)
S =S+P * h
输出 S
图 4.13 梯形法求定积分
例 4.18 用梯形法求积分
dx
即 a= 0,b= 1,f(x)= 。
? ?? 10 2e xS
2e x?
相应的 C程序如下:
#include "stdio.h"
#include "math.h"
main()
{ int n,k;
double a= 0.0,b= 1.0,h,s,p,x;
printf("input n,");
scanf("%d",&n); /*输入等分数 */
h= (b- a)/n;
s= h*(exp(- a*a)+ exp(- b*b))/2;
p= 0.0;
for (k= 1; k< n; k= k+ 1)
{ x= a+ k*h; p= p+ exp(- x*x); }
s= s+ p*h;
printf("s= %11.7f\n",s);
}