博文
[048] 整数各位的分离(由低位到高位)(2006-04-06 22:55:00)
摘要:出处: 《C程序设计》(夏宝岚) P62
练习将一个整数的各位分离处理的方法:
5.9 统计正整数的各位数字中的0的个数,并求各位数字中最大者。例如:31040,其中0的个数是2,最大数是4。
#include <stdio.h>
int main()
{
int n, count, max, t;
count = max = 0; /* count记录0的个数, max记录最大者 */
scanf("%d", &n);
do
{
t = n % 10; /* 取当前的最低位 */
if(t == 0)
count++;
else
if(max < t)
max = t;
n /= 10;
}while(n);
printf("co......
[047] 求传递闭包(2006-04-01 23:36:00)
摘要:问题的提出参见: 《图像工程上册图像处理和分析》(清华) P34
数字图像处理课上讲到图像和视觉基础时涉及到了离散数学中的一个概念: 传递闭包。刚好我的C语言刚看到数组,就编来看看吧。
二值矩阵是一种常用的描述关系的形式。我们可取矩阵中对应相关元素相交处的值为1,其它地方的的值为0。从R={{a, a), (a, b), (b, d), (d, b), (c, e)}}可得如下矩阵B:
a b c d e
┌ 1 1 0 0 0 ┐a
│ 0 0 0 1 0 │b
B =│ 0 0 0 0 1 │c
│ 0 1 0 0 0 │d
└ 0 0 0 0 0 ┘e
传递性指出,如果 a~R~b, b~R~c, 则a~R~c。在以上矩阵中,a与b相连且b与d相连,因为(a,b)和(b,d)在R中。但我们注意到(a,d)不在集合R中。包含这些隐含关系的集合称为R的传递闭包,并记为R+ 。所以R+ = {(a, a), (a, b), (a, d) , (b, b) , (b, d), (d, b), (d, d) , (c, e)}。这个集合包含(a, d), (b, b), (d, d)是根据传递性定义(即由a~R~b, b~R~d, 推出a~R~d; 由b~R~d, d~R~b, 推出b~R~b; 由d~R~b, b~R~d, 推出d~R~d)而来的。描述关系R+的矩阵如下:
a b c d ......
[046] 字符数组与字符串(2006-03-30 21:29:00)
摘要: C语言中没有专门的字符串变量,如果要将一个字符串存放在变量中,必须使用字符数组,即用一个字符型数组来存放一个字符串,数组中每一个元素存放一个字符。
<1> 定义: char c[10]
字符型与整型互相通用,因此 int c[10] 也可以定义字符数组。但由于两种类型分配字节不同, 用整型来定义会浪费空间, 另外这样定义实际意义也不大, 只是为了说明其合法性。
<2> 初始化:
最简单的方法即逐个赋值: char c[10]={'I', ' ', 'a', 'm', ' ', 'h', 'a', 'p', 'p', 'y'}; 10个字符分别赋绐c[0]到c[9]10个元素。
如果初值个数小于数组长度,则只将这些字符赋绐数组中前面的元素,其余元素自动定为空字符(即'\0')。
如char c[12]={'I', ' ', 'a', 'm', ' ', 'h', 'a', 'p', 'p', 'y'}; 则c[10]、c[11]值都为'\0' 。
C语言中,将字符串作为字符数组来处理。一般我们用字符数组来存放字符串时,都要先确定一个足够大的数组,而实际并用不了那么多,而我们只关心其有效位,为测定字符串实际长度,C规定了一个"字符串结束标志",以字符 '\0' 代表。如果有一个字符串,其中第10个字符为'\0',则此字符串的有效字符为9个。也就是说,在遇到字符'\0'时,表示字符串结束,由它前面的字符组成字符串。
系统对字符串常量也自动加一个'\0'作为结束符。
对于语句: pirntf("How do you do? \n"); 实际上该字符串在内存中存放时,系统自动在最后一个字符'\0'的后面加了一个'\0'作为字符串结束标志,在执行printf函数时,每输出一个字符检查一次,看下一个字符是否'\0'。遇'\0'就停止输出。
&nbs......
[045] 二维数组(2006-03-25 23:06:00)
摘要:<谭> 7.2.3
C语言中,二维数组中元素排列的顺序是:按行存放,即在内存中先顺序放第一行的元素,再存放第二行的元素。
二维数组的初始化:
(1) 分行给二维数组赋初值。如
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
这种赋初值方法比较直观,把第1个花括弧内的数据给第1行的元素,第2个花括弧内的数据赋给第2行的元素……即按行赋初值。
(2) 可以将所有数据写在一个花括弧内,按数组排列的顺序对各元素赋初值。如:
int a[3][4]={1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12};
效果与前相同。但以第1种方法为好,一行对一行,界限清楚。用第2种方法如果数据多,写成一大片,容易遗漏,也不易检查。
(3) 可以对部分元素赋初值。
int a[3][4]={{1},{5},{9}};
它的作用是只对各行第1列的元素赋初值,其余元素值自动为0。赋初值后数组各元素为
1 0 0 0
5 0 0 0
9 0 0 0
也可以对各行中的某一元素赋初值:
int a[3][4]={{1},{0,6},{0,0,11}};
初始化后的数组元素如下:
1 0 0 0
0 6 0 0
0 0 11 0
这种方法对非0元素少时比较方便,不必将所有的0都写出来,只需输入少量数据。也可以只对某几行元素赋初值:
int a[3][4]={{1},{5,6}};
数组元素为
1 0 0 0
5 6 0 0
0 0 0 0
第3行不赋初值。也可以对第2行不赋初值:
int a[3][4]={{1},{},{9}};
(4) 如果对全部元素都赋初值(即提供全部初始数据),则定义数组时对第一维的长度可以不指定,但第二维的长度不能省。如:
......
[044] 起泡排序(2006-03-25 21:15:00)
摘要:<谭> 例7.3
用起泡法对10个数排序(由小到大)
若有n个数。第一次将第1和第2个数比较,若第1个数大于第2个数,刚两数对调,否则不操作。第二次将第2和第3个数比较,如上操作,刚经过n-1次这样的操作,最大的数排到了最后(即所谓的沉底)。以上为第一趟操作的结果。第二趟要对余下的n-1个数作同样的操作(因为最大的数已排到最后,不必考虑)。第二趟中要作n-2次比较……依次类推可得出结论:n个数排序,要进行n-1趟比较。第一趟中比较n-1次,第 i 趟中比较 n-i 次。
#include <stdio.h>
int main()
{
int a[11]; /* 为了符合习惯, 第0号元素不用 */
int i, j, cup;
printf("Input 10 numbers:\n");
for(i = 1; i < 11; i++)
scanf("%d", &a[i]);
for(i = 1; i <= 9; i++) /* 趟数 */
for(j = 1; j <= 10 - i; j++) /* 每趟要比较数 */
if(a[j] > a[j+1]) /* 前面数大于后面数刚对调 */
&......
[043] 一维数组的定义(2006-03-25 20:32:00)
摘要:一维数组的定义方式为:
类型说明符 数组名[常量表达式];
如: int a[10];
它表示数组名为a,此数组有10个元素。
(1) 数组名定名规则和变量名相同,遵循标识符定名规则。
(2) 数组名后是用方括弧括起来的常量表达式。
(3) 常量表达式表示元素的个数,即数组长度。例如,在a[10]中,10表示a数组有10个元素,下标从0开始,这10个元素是,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9]。注意不能使用数组元素a[10] 。
(4) 常量表达式中可以包括常量和符号常量,不能包含变量。也就是说,c不允许对数组的大小作动态定义,即数组的大小不依赖于程序运行过程中变量的值。例如,下面这样定义数组是不行的:
int n;
scanf("%d",&n);
int a[n];
★ 所以用到数组时数组的大小是确定的,不能动态分配。
关于一维数组的初始化: 可以只绐一部分元素赋值, 例如:
int a[10] = {0, 1, 2, 3, 4};
此时只绐前面5个元素赋初值,后5个元素值为0 。
[更新] C语言中动态分配数组(一维) 。由此看来上面书中“不能动态分配”的说法还是太绝对了。......
[042] 比赛对手(2006-03-19 16:50:00)
摘要:<谭> 6.15
两个乒乓球队进行比赛, 各出三人。甲队为A、B、C三人,乙队为X、Y、Z三人。已抽签决定比赛名单。有人向队员打听比赛的名单,A说他不和X比,C说他不和X、Z比。请编程序找出三赛手的名单。
分析:
① X既不与A比,又不与C比,必然与B比;
② C既不与X比,又不与Z比,必然与Y比;
③ A只能与Z比.
以上为逻辑推理得到结论,而用计算机处理此问题,必须对所有组合一一检验,看是否符合条件。
#include <stdio.h>
int main()
{
char _A, _B, _C; /* 分别表示A,B,C的对手 */
for(_A = 'X'; _A <= 'Z'; _A++)
for(_B = 'X'; _B <= 'Z'; _B++)
for(_C = 'X'; _C <= 'Z'; _C++)
if(_A != _B && _A != _C && _B != _C && _A != 'X' && _C != 'X' && _C != 'Z')
printf("A--%c\tB--%c\tC--%c\n", _A, _B, _C);
retu......
[041] 练习循环打印*图案(2006-03-19 16:29:00)
摘要:<谭> 6.14
打印出以下图案:
*
***
*****
*******
*****
***
*
#include <stdio.h>
int main()
{
int i, j, k;
for (i = 1; i <= 4; i++)
{
for (j = 1; j <= 4 - i; j++)
printf(" ");
for (k = 1; k <= 2 * i - 1; k++)
printf("*");
printf("\n");
}
for (i = 1; i <= 3; i++)
{
for (j = 1; j <= i; j++)
printf(" ");
for (k = 1; k <......
[040] 迭代法求平方根(2006-03-19 14:01:00)
摘要:<谭> 6.11
用迭代法求某数a的平方根。已知求平方根的迭代公式为:x n+1 = (xn + a / xn) / 2
要求前后两次求出的差的绝对值小于10-5。
算法如下:
① 设定一个x的初值x0 ; (在如下程序中取x0=a/2, 通过迭代公式求出x1,可以肯定与真正的平方根相比,误差很大。)
② 用上述公式求出x的下一个值 x1 ;
③ 如此继续下去,直到前后两次求出的x值(x n+1和xn)满足以下关系:|x n+1-xn|<10-5 .
#include <stdio.h>
#include <math.h>
int main()
{
float a; /* 被开方数 */
float x0, x1; /* 分别代表前一项和后一项 */
printf("Input a positive number:\n");
scanf("%f", &a);
x0 = a / 2; /* 任取初值 */
x1 = (x0 + a / x0) / 2;
while (fabs(x1 - x0) >= 1e-5)
{
x0 = x1;
x1 = (x0 + a / x0) / 2;
}
printf("The square root of %5.2f is %8.5f\n", a, x1);
&nb......
[039] 猴子吃桃问题(2006-03-19 12:37:00)
摘要:<谭> 6.10
猴子第一天摘下若干桃子,当即吃了一半,还不过瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘多少桃子。
#include <stdio.h>
int main()
{
int prev ; /* 前一天 */
int next = 1 ; /* 后一天, 初值为第10天 */
int i;
for (i = 9; i >= 1; i--)
{
prev = (next + 1) * 2 ; /* next=prev-(prev/2+1) */
next = prev;
}
printf("total=%d\n", prev);
return 0;
}
运行结果:
====================
total=1534
====================
★ 此题用倒推的办法,所以注意循环结束的条件。多数情况下用循环为递增方式,本题中用递减方式,因此是: i >= 1 。
分步验证如下:
#include <stdio.h>
int main()
{
int prev ;
int next = 1 ;
int i;
&nb......