1. 编写程序,找出一个二维数组中的鞍点,即该位置上的元素在该行上最大,在该列上最小,也有可能没有鞍点。设二维数组a有3行4列。

//一个不是局部极值点的驻点称为鞍点。
//在矩阵中,一个数在所在行中是最大值,在所在列中是最小值,则被称为鞍点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <stdio.h>
int main()
{
int a[3][4];
int temp, i, j, k, x, y;
int count=0;
int flag; //鞍点的标志
printf("Please in put a array(3*4):\n");
for(i=0;i<3;i++)
for(j=0;j<4;j++)
{
scanf("%d",&temp);
a[i][j]=temp; //读取矩阵的行列值并储存到二维数组中
}
printf("You input the :\n");
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
printf ("%d ",a[i][j]); //打印一遍矩阵,查看输入是否正确
}
printf("\n");
}
for(i=0;i<3;i++)
{
temp=a[i][0]; //找出第i行的最大值,记录其列号y
x = i;
y = 0;
for (j=1;j<4;j++)
{
if (temp<a[i][j])
{
temp = a[i][j];
y = j;
}
}
flag = 1; //假设当前点为鞍点
for (k=0;k<3;k++) //判断上述第i行,列号为y的最大值是否为第y列的最小值
{
if ( temp >= a[k][y] && (k!=i))//去除重复的值
{
flag = 0;
break;
}
}
if (flag==1)
{
printf("鞍点是 a[%d][%d]=%d\n",x,y,a[x][y]);
count++;
}
}
if (count == 0) printf("\n这个矩阵没有鞍点.");
return 0;
}

3. 从键盘接受10个3位正整数(各个数位都不包含0)并存入一个数组中,打印输出该数组,将数组中每个数的百位与个位进行交换。例如,123交换后成为321,将交换后的新数仍然存入原数组中,并打印输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
int main()
{
int i, j, k, l;
int a[10];
printf("Please input 10 numbers(>100) :\n");
for (i=0;i<10;i++)
scanf("%d",&a[i]); //读取十个数字,储存进数组
printf("You input array is:\n");
for (i=0;i<10;i++)
printf("%d ",a[i]); //输出数组,查看读取是否正确
printf("\nAfter change.\n"); //将百位和十位进行交换
for (i=0;i<10;i++)
{
j = a[i]/100; //得到百位的数字
k = (a[i]-j*100)/10; //得到十位的数字
l = a[i] - j*100 - k*10; //得到个位的数字
a[i] = (k*100+j*10+l); //将十位百位数字交换重新赋值给 a[i]
printf("%d ",a[i]);
}
printf("\n");
return 0;
}

4.编写一个函数,输出一个整数的全部素数因子,例如,m=120,m的素数因子有2,3,5. 其中,判断某个因子是否是素数的功能用子函数来实现,在主函数中调用此函数。

质因子(或质因数)在数论里是指能整除给定正整数的质数。根据算术基本定理,不考虑排列顺序的情况下,每个正整数都能够以唯一的方式表示成它的质因数的乘积。两个没有共同质因子的正整数称为互质。因为1没有质因子,1与任何正整数(包括1本身)都是互质。

将一个正整数表示成质因数乘积的过程和得到的表示结果叫做质因数分解。显示质因数分解结果时,如果其中某个质因数出现了不止一次,可以用幂次的形式表示。例如360的质因数分解是:

其中的质因数2、3、5在360的质因数分解中的幂次分别是3,2,1.

这里用到了整数分解算法,试除法是整数分解中最简单的算法,其他的还有筛选法。给定一个合数n(这里,n是待分解的正整数),试除法是用小于等于 的每个素数去试除待分解的整数。如果找到一个数能够整除除尽,这个数就是待分解整数的因子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
int is_prime(int i)
{
int j=0;
for( j=2; j*j <= i ; j++) //试除法
if ( i%j == 0 )
return 0;
return 1;
}
int main (void)
{
int num=0;
printf("Please input a num:" );
scanf("%d" ,&num );
for( int i=2 ; i<=num ; i++ ) //开始遍历小于等于num的每个数
if ( num % i == 0 && is_prime(i) ) //如果 num 刚好整除 i 且判断函数的值为真(1),输出这个数。
printf("%d " , i ) ;
printf("\n");
return 0;
}

埃拉托斯特尼筛法

埃拉托斯特尼筛法(英语:sieve of Eratosthenes ),簡稱埃氏筛,是一種簡單且年代久遠的演算法,用來找出一定範圍內所有的質數。
所使用的原理是從2開始,將每個質數的各個倍數,標記成合數。一個質數的各個倍數,是一個差為此質數本身的等差數列。此為這個篩法和試除法不同的關鍵之處,後者是以質數來測試每個待測數能否被整除。
埃拉托斯特尼篩法是列出所有小質數最有效的方法之一,其名字來自於古希臘數學家埃拉托斯特尼,並且被描述在尼科馬庫斯所著Introduction to Arithmetic中。

算式

给出要筛数值的范围n,找出\(\sqrt{n}\)以内的素数\(p_1,p_2,···,p_k\)。先用2去筛,即把2留下,把2的倍数剔除掉;再用下一個質數,也就是3筛,把3留下,把3的倍数剔除掉;接下去用下一個質數5筛,把5留下,把5的倍数剔除掉;不斷重複下去……

步驟

详细列出算法如下:

  1. 列出2以後的所有序列:
    • 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
  2. 标出序列中的第一个質数,也就是2,序列变成:
    • 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
  3. 将剩下序列中,劃摽2的倍数(带括号的数字),序列变成:
    • 2, 3, {4}, 5, {6}, 7, {8}, 9, {10}, 11, {12}, 13, {14}, 15, {16}, 17, {18}, 19, {20}, 21, {22}, 23, {24}, 25)
  4. 如果现在这个序列中最大数小于最後一個標出的質數的平方,那么剩下的序列中所有的数都是質数,否则回到第二步。
  1. 本例中,因为25大于2的平方,我们返回第二步:
  2. 剩下的序列中第一个質数是3,将主序列中3的倍数划出(变为下标的数字),主序列变成:
    • 2, 3, {4}, 5, {6}, 7, {8}, {9}, {10}, 11, {12}, 13, {14} ,{15}, {16}, 17, {18}, 19, {20}, {21}, {22}, 23, {24}, 25
  3. 我们得到的質数有:2,3
  4. 25仍然大于3的平方,所以我们还要返回第二步:
  5. 现在序列中第一个質数是5,同样将序列中5的倍数划出,主序列成了:
    *2, 3, {4}, 5, {6}, 7, {8}, {9}, {10}, 11, {12}, 13, {14}, {15}, {16}, 17, {18}, 19, {20}, {21}, {22}, 23, {24}, {25}
  6. 我们得到的質数有:2 3 5 。
  7. 因为25等于5的平方,跳出循环.

结论:去掉红色的数字,2到25之间的質数是:2 3 5 7 11 13 17 19 23。

演算法
埃拉托斯特尼篩法,可以用以下的伪代码來表示:

1
2
3
4
5
6
7
8
9
10
11
Input: an integer n > 1
Let A be an array of Boolean values, indexed by integers 2 to n,
initially all set to true.
for i = 2, 3, 4, ..., not exceeding √n:
if A[i] is true:
for j = i2, i2+i, i2+2i, i2+3i, ..., not exceeding n :
A[j] := false
Output: all i such that A[i] is true.

以上演算法可以得到小於等於n的所有素数,它的複雜度是O(n log log n)。

6.打印杨辉三角

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
#define N 14
int main()
{
int i, j, k, n=0, a[N][N]; /*定义二维数组a[14][14]*/
while(n<=0||n>=13){ /*控制打印的行数不要太大,过大会造成显示不规范*/
printf("请输入要打印的行数:");
scanf("%d",&n);
}
printf("%d行杨辉三角如下:\n",n);
for(i=1;i<=n;i++)
a[i][1] = a[i][i] = 1; /*两边的数令它为1,因为现在循环从1开始,就认为a[i][1]为第一个数*/
for(i=3;i<=n;i++)
for(j=2;j<=i-1;j++)
a[i][j]=a[i-1][j-1]+a[i-1][j]; /*除两边的数外都等于上两顶数之和*/
for(i=1;i<=n;i++){
for(k=1;k<=n-i;k++)
printf(" "); /*这一行主要是在输出数之前打上空格占位,让输出的数更美观*/
for(j=1;j<=i;j++) /*j<=i的原因是不输出其它的数,只输出我们想要的数*/
printf("%6d",a[i][j]);
printf("\n"); /*当一行输出完以后换行继续下一行的输出*/
}
printf("\n");
}

实际参数和形式参数

定义带形式参数的函数

函数定义从下面 ANSI C 风格的函数头开始:
void show_n_char(char ch, int num)

该行告知编译器void show_n_char使用两个参数 ch和 num,ch 是 char 类型,num 是 int 类型。这两个变量被称为形式参数。和定义在函数中的变量一样,形式参数也是局部变量,属该函数私有。这意味着在其他函数中使用同名变量不会引起名称冲突。每次调用函数,就会给这些变量赋值。ANSI C 要求在每个变量前都声明其类型。

调用带实际参数的函数

在函数调用中,实际参数提供了 ch 和 num 的值。
show_n_char(SPACE, 12);
实际参数是空格字符和12.这两个值被赋给show_n_char()中相应的形式参数:变量 ch 和 num。形式参数是被调函数中的变量,实际参数是主调函数赋给被调函数的具体值。实际参数可以是常量,变量,甚至是表达式。

注意

实际参数是出现在函数调用圆括号中的表达式。形式参数是函数定义的函数头中声明的变量。调用函数时,创建了声明为形式参数的变量并初始化为实际参数的求值结果。

//输入10个整数,将其中最小的是与第一个数对换,把最大的数与最后一个数对换,
//要求用指针来完成,并写三个函数,1.输入10个整数 2.进行处理 3.输出10个数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <stdio.h>
#define NUM 10
void get_number(int *); //定义get_number来录入10个整数
int process(int *); //定义comp来处理10个整数,这一步需要返回值,所以定义为int
void print(int *); //定义print来输出10个整数
int main()
{
int a[NUM];
get_number(a);
process(a);
print(a);
}
void get_number(int *p)
{
int i=0;
printf("请输入10个整数:\n");
for(;i<10;i++)
scanf("%d",p++);//注意请勿要将p++误写成*p++或&p++,因为p已经定义成
} //指针类型了,p本身就已经是指向地址了的,故不必再加*或&,否则出错
int process(int *f)
{
int i,j=0,k=9,t,r; //用j来记录最小的数的下标,用k来记录最大的数的下标
for(i=0;i<10;i++)
{
if(*(f+j)<*(f+i)) continue;//找出数组中最小的数
j=i; //这个最小的数的下标用j来记录
}
for(i=8;i>=0;i--)
{
if(*(f+k)>*(f+i)) continue; //找出数组中最大的数
k=i; //这个最大的数的下标用k来记录
}
t=*(f+j); *(f+j)=*f; *f=t; //将最小的数与第一个数对换
r=*(f+k); *(f+k)=*(f+9); *(f+9)=r; //将最大的数与最后一个数对换
return 0;
}
void print(int *u)
{
int i;
printf("处理后的结果是:\n");
for(i=0;i<10;i++)
printf("%d ",*u++);
printf("\n");
}

矩阵相乘的方法

假设矩阵 a 为 23
{5, 2, 4}
{6, 3, 9}
矩阵 b 为 3
4
{7, 8, 9, 3}
{1, 4, 2, 5}
{3, 4, 8, 9}

1.矩阵乘法的一般方法:

a[0,0] x b[0,0] = 5 x 7 = 35
a[0,1] x b[1,0] = 2 x 1 = 2
a[0,2] x b[2,0] = 4 x 3 = 12
相加 = c[0,0] = 49

a[0,0] x b[0,1] = 5 x 8 = 40
a[0,1] x b[1,1] = 2 x 4 = 8
a[0,2] x b[2,1] = 4 x 4 = 16
相加 = c[0,1] = 64

a[0,0] x b[0,2] = 5 x 9 = 45
a[0,1] x b[1,2] = 2 x 2 = 4
a[0,2] x b[2,2] = 4 x 8 = 32
相加 = c[0,2] = 81

a[0,0] x b[0,3] = 5 x 3 = 15
a[0,1] x b[1,3] = 2 x 5 = 10
a[0,2] x b[2,3] = 4 x 9 = 36
相加 = c[0,3] = 61

a[1,0] x b[0,0] = 6 x 7 = 42
a[1,1] x b[1,0] = 3 x 1 = 3
a[1,2] x b[2,0] = 9 x 3 = 27
相加 = c[1,0] = 72

a[1,0] x b[0,1] = 6 x 8 = 48
a[1,1] x b[1,1] = 3 x 4 = 12
a[1,2] x b[2,1] = 9 x 4 = 36
相加 = c[1,1] = 96

a[1,0] x b[0,2] = 6 x 9 = 54
a[1,1] x b[1,2] = 3 x 2 = 6
a[1,2] x b[2,2] = 9 x 8 = 72
相加 = c[1,2] = 132

a[1,0] x b[0,3] = 6 x 3 = 18
a[1,1] x b[1,3] = 3 x 5 = 15
a[1,2] x b[2,3] = 9 x 9 = 81
相加 = c[1,3] = 114

所得矩阵为:
49 64 81 61
72 96 132 114

2.根据定义直接计算:

c[0,0] = (57) + (21) + (43) = 49
c[0,1] = (5
8) + (24) + (44) = 64
c[0,2] = (59) + (22) + (48) = 81
c[0,3] = (5
3) + (25) + (49) = 61

c[1,0] = (67) + (31) + (93) = 72
c[1,1] = (6
8) + (34) + (94) = 96
c[1,2] = (69) + (32) + (98) = 132
c[1,3] = (6
3) + (35) + (99) = 114

所得矩阵为:
49 64 81 61
72 96 132 114

3.系数-向量的方法:

5[ 7 8 9 3 ] + 2[ 1 4 2 5 ] + 4[ 3 4 8 9 ] = [ 35 40 45 15 ] + [ 2 8 4 10 ] + [ 12 16 32 36 ]
6
[ 7 8 9 3 ] + 3[ 1 4 2 5 ] + 9[ 3 4 8 9 ] = [ 42 48 54 18 ] + [ 3 12 6 15 ] + [ 27 36 72 81 ]

所得矩阵为:
49 64 81 61
72 96 132 114

4.行向量乘以列向量的方法:

[ 5 2 4 ].[ 7 1 3 ] =5 x 7 + 2 x 1 + 4 x 3 = c[0,0] = 49

[ 5 2 4 ].[ 8 4 4 ] =5 x 8 + 2 x 4 + 4 x 4 = c[0,1] = 64

[ 5 2 4 ].[ 9 2 8 ] =5 x 9 + 2 x 2 + 4 x 8 = c[0,2] = 81

[ 5 2 4 ].[ 3 5 9 ] =5 x 3 + 2 x 5 + 4 x 9 = c[0,3] = 61

[ 6 3 9 ].[ 7 1 3 ] =6 x 7 + 3 x 1 + 9 x 3 = c[1,0] = 72

[ 6 3 9 ].[ 8 4 4 ] =6 x 8 + 3 x 4 + 9 x 4 = c[1,1] = 96

[ 6 3 9 ].[ 9 2 8 ] =6 x 9 + 3 x 2 + 9 x 8 = c[1,2] = 132

[ 6 3 9 ].[ 3 5 9 ] =6 x 3 + 3 x 5 + 9 x 9 = c[1,3] = 114

所得矩阵为:
49 64 81 61
72 96 132 114

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define M 2
#define N 3
#define P 4
/*
* A*B=C
* (M,N) * (N,P) =(M,P)
*/
float a[M][N] = {{5, 2, 4},
{6, 3, 9}};
float b[N][P] = {{7, 8, 9, 3},
{1, 4, 2, 5},
{3, 4, 8, 9}};
float c[M][P];
void clear_c()
{//用于清空c数组,
//多种乘法同时使用的时候,某些方法需要清空c数组,否则会重复计算。
int i,j;
for(i=0;i<M;i++)
for(j=0;j<P;j++)
c[i][j]=0;
}
void print_matrix()
{//本函数只打印c 矩阵
int i,j;
for(i=0;i<M;i++)
{
for(j=0;j<P;j++)
{
printf("%.3g\t",c[i][j]);
}
printf("\n");
}
}
void mul_1()
{//一般矩阵乘积
printf("\n1.矩阵乘法的一般方法:\n");
int i,j,k;
float c_key,c_sumkey;
//注意三层循环的顺序。
for(i=0;i<M;i++){
for(j=0;j<P;j++){
c_sumkey=0;//清空后计算下一个元素的值
for(k=0;k<N;k++)
{
c_key=a[i][k]*b[k][j];
c_sumkey+=c_key;
printf("a[%d,%d] x b[%d,%d] = %.3g x %.3g = %.3g\n",i,k,k,j,a[i][k],b[k][j],c_key);
}
c[i][j]=c_sumkey;
printf("相加 = c[%d,%d] = %.3g\n\n",i,j,c_sumkey);
}
}
}
float get_key_val(int i,int j)
{ //求结果矩阵中某点的内积
int n;
float sumkeyval=0;
printf("c[%d,%d] = ",i,j);
for(n=0;n<N;n++)
{
if(n!=0) printf(" + ");
//printf("a[%d,%d]*b[%d,%d]",i,n,n,j);
printf("(%.3g*%.3g)",a[i][n],b[n][j]);
sumkeyval+=a[i][n]*b[n][j];
}
printf(" = %.3g\n",sumkeyval);
return sumkeyval;
}
void mul_2()
{//根据定义求矩阵的乘积
printf("\n2.根据定义直接计算:\n");
int i,j;
for(i=0;i<M;i++){
for(j=0;j<P;j++)
{
c[i][j]=get_key_val(i,j);
}
printf("\n");
}
}
void show_multi_proc(float x,int j)
{//本函数只为显示更详细的乘法过程。
int k;
if(j!=0){printf(" + ");}else{printf(" = ");}
printf("[ ");
for(k=0;k<P;k++)
{
printf("%.3g ",x*b[j][k]);
}
printf("]");
}
void splite_matrix_row(float x,int i,int j)
{ //把B矩阵分割成 N个一维数组,长度为p.
//并用向量 乘以 数组中的每个值。
//然后做矩阵相加,即多个一维数组对应位置相加。并把值写入C矩阵。
int k;
if(j!=0){printf("\n + ");}
printf("%.3g*[ ",x);
for(k=0;k<P;k++)
{
printf("%.3g ",b[j][k]);
c[i][k]+=x*b[j][k];//向量乘以矩阵
}
printf("]");
}
void mul_3()
{//系数-向量方法
//这里只采用了行向量的方法。列向量也会可行的。
// 或者 把矩阵A分为多个行(列)向量,然后把矩阵B分为系数。
printf("\n3.系数-向量的方法:\n");
int i,j;
float xs;//系数
for(i=0;i<M;i++){
for(j=0;j<N;j++)
{
xs=a[i][j];
splite_matrix_row(xs,i,j);
}
for(j=0;j<N;j++)
{
xs=a[i][j];
show_multi_proc(xs,j);
}
printf("\n");
}
}
void mul_4()
{//行向量与列向量相乘。计算结果为最终矩阵中一个元素的值
printf("\n4.行向量乘以列向量的方法:\n");
int i,j,k;
float c_key,c_sumkey;
//注意三层循环的关系。
for(i=0;i<M;i++)
{
for(j=0;j<P;j++)
{
c_sumkey=0;//清空后计算下一个元素的值
printf("[");
for(k=0;k<N;k++)
{
printf(" %.3g ",a[i][k]);
}
printf("].");
printf("[");
for(k=0;k<N;k++)
{
printf(" %.3g ",b[k][j]);
}
printf("] =");
for(k=0;k<N;k++)
{
if(k!=0){printf("+ ");}
c_key=a[i][k]*b[k][j];
c_sumkey+=c_key;
printf("%.3g x %.3g ",a[i][k],b[k][j]);
}
c[i][j]=c_sumkey;
printf("= c[%d,%d] = %.3g\n\n",i,j,c_sumkey);
}
}
}
int main()
{
mul_1();
print_matrix();
mul_2();
print_matrix();
clear_c();
mul_3();
print_matrix();
mul_4();
printf("\n");
print_matrix();
}

//有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <stdio.h>
#define CAL 3 //凡报3的人出列(可任意更改)
//下面是排队编号函数:从h开始的n个人依次编号1到n
void stdline(int *h,int n)
{
int i;
for(i=1;i1;i++)
*(h+i-1)=i;
}
/*下面函数表示从指针h处开始的人数为"boy"个人排队,从1报数,每报到"call"的人出列*/
void outline(int *h,int boy,int call)
{
int *p, chu, callnum;
/*说明:
p 工作指针,表示从头依次指向每个元素,点名
chu 计数器,记录出列的人数
callnum 计数器,记录点名次序
*/
chu=0;
callnum=0;//各计数器清零
p=h; //开始时,工作指针指向数组首
printf("出列顺序是:\n");
while(chu
{
if(*p!=0) callnum++; //每次加报数
if(callnum==call) //如果某一个人报到出列数call...
{
printf("%5d",*p); //打印编号,表示出列
chu++; //出列人数加1
if(chu==boy)//如果全部出列....
{
*h=*p; //把最后一个出列人的编号记入地址开始处
return; //结束
}
if(chu%5==0)printf("\n");//每输出5个换行
callnum=0; //出列后,重新报数
*p=0; //出列后,将其编号赋零,以示区别
}
p++; //工作指针移向下一个人,即下一个数组元素
if(p>h+boy-1)p=h;//如果移到最后一个元素的后面,则让指向地址开头继续报数
}
}
int main()
{
int N;
printf("输入排队的人数:\n");
scanf("%d",&N);
int a[N]; //用数组模拟队列,每个元素代表一个人
stdline(a,N);//编号
outline(a,N,CAL);//计算并打印出列顺序
printf("\n最后留下来的是 %d 号\n",*a);//在函数中,已经把最后一个人的编号写入了数组首地址处,这里输出就可以了
}