20201022-成信大-C语言程序设计-20201学期《C语言程序设计B》C-trainingExercises15
P216

/*
编写一程序P216.C实现以下功能
求任意的一个m×m矩阵的最大数及其所在的行列数,m(2<=m<=20)及矩阵元素从键盘输入(只考虑int型)。
编程可用素材:
printf("Please input m: ");
printf("\nPlease input array:\n");
printf("\nmax=…,i=…,j=…\n");
程序的运行效果应类似地如图1所示,图1中的红色部分是从键盘输入的内容。
Please input m: 5
Please input array:
1 45 67 235 464
35 6 89 32342 8
347 9346 47 95 746
46 785 436 19434 634
3235 567 24 8465 25
max=32342,i=1,j=3
图1 程序运行效果示例
思路:
1. 最简单的搜索方式:比较得结果
记录最大值
记录行号
记录列号
2. 注意:
矩阵到了C语言下,一般用二维数组来表示,但行和列标的索引是从0开始的,因数二进制计数,0不能浪费
而人在数数时,是从1开始有计数的。
*/
#include <stdio.h>
#define N 20 // m(2<=m<=20) 按题目要求,给定常量
int main(void)
{
int i,j;
int arr[N][N]; // 使用二维数组
int m;
int max, iMark, jMark; // 搜索过程中进行标记和记录
printf("Please input m: ");
scanf("%d", &m);
// 输入矩阵
printf("\nPlease input array:\n");
for ( i = 0; i < m; i++)
{
for ( j = 0; j < m; j++)
{
scanf("%d", &arr[i][j]);
}
}
// 搜索矩阵,找最大,并标记。默认0行0列最大
max = arr[0][0];
iMark = jMark = 0;
for ( i = 0; i < m; i++)
{
for ( j = 0; j < m; j++)
{
if (max < arr[i][j] ) // 如果有更大的,则更新标记和记录
{
max = arr[i][j];
iMark = i;
jMark = j;
}
}
}
// 输出
printf("\nmax=%d,i=%d,j=%d\n", max, iMark, jMark);
return 0;
}
P262

/*
编写一程序P262.C实现以下功能
先从键盘读入整数m和n(约定(2<=m<=20、2<=n<=20)),再从键盘读入m行(每行n个,即一个m×n矩阵)整数,
然后从键盘读入一个列序号,按示例格式显示该列的内容。
编程可用素材:
printf("请输入 m 和 n: ");
printf("请输入 %d 行, 每行 %d 列整数:\n"…);
printf("请输入要显示列的列号: ");
printf("\n该列的内容为: ");
程序的运行效果应类似地如图1所示,图1中的红色部分是从键盘输入的内容。
请输入 m 和 n: 5 6
请输入 5 行, 每行 6 列整数:
31 42 36 74 2358 88
1447 32 57 37 43 47
97 51 257 7 445 459
33 65 44 3 425 43
68 3425 82 789 123 2134
请输入要显示列的列号: 2
该列的内容为: 36 57 257 44 82
图1 程序运行效果示例
*/
#include <stdio.h>
#define N 20
int main(void)
{
int i, j;
int arr[N][N];
int m, n; // m行,n列
int col; // 操作列号
printf("请输入 m 和 n: ");
scanf("%d%d", &m, &n);
printf("请输入 %d 行, 每行 %d 列整数:\n", m, n);
for ( i = 0; i < m; i++)
{
for ( j = 0; j < n; j++)
{
scanf("%d", &arr[i][j]); // 对每一个元素取地址进行初始化
}
}
printf("请输入要显示列的列号: ");
scanf("%d", &col);
printf("\n该列的内容为: ");
for ( i = 0; i < m; i++) // 列固定,按行遍历
{
printf("%d ", arr[i][col]);
}
return 0;
}
P748

/*
编写一程序P748.C实现以下功能
从键盘上输入矩阵的阶数n(n<=14), 矩阵中元素的值等于其位置的行数和列数之和的n倍(行列的值从0开始计数),如n=3时,矩阵为
0 3 6
3 6 9
6 9 12
先输出该矩阵(显示时每个数宽度为4、右对齐),然后计算输出sum1和sum2的值:
sum1为矩阵中所有不靠边元素之和、
sum2为矩阵的一条对角线元素之和。
编程可用素材:
printf("Enter n: ");
printf("\nsum1=…\nsum2=…\n");
程序的运行效果应类似地如图1所示,图1中的3是从键盘输入的内容。
Enter n: 3
0 3 6
3 6 9
6 9 12
sum1=6
sum2=18
图1 程序运行效果示例
*/
#include <stdio.h>
#define N 14
int main(void)
{
int n;
int i, j;
int arr[N][N];
int sum1 = 0, sum2 = 0;
printf("Enter n: ");
scanf("%d", &n);
// 矩阵元素值生成
for ( i = 0; i < n; i++)
{
for ( j = 0; j < n; j++)
{
arr[i][j] = (i + j) * n; // 元素的值等于其位置的行数和列数之和的n倍,这是最朴素的业务算法实现
}
}
// 先输出该矩阵(显示时每个数宽度为4、右对齐)
for ( i = 0; i < n; i++)
{
for ( j = 0; j < n; j++)
{
printf("%4d", arr[i][j]); // 注意值的宽度
}
printf("\n"); // 二维,一定要有换行控制
}
/*
计算输出sum1和sum2的值
sum1为矩阵中所有不靠边元素之和、
sum2为矩阵的一条对角线元素之和。
*/
for ( i = 0; i < n; i++)
{
for ( j = 0; j < n; j++)
{
/*
对于不靠边元素的判断,有很多种逻辑判断方法
比如:
1. 首行首列,尾行尾列,一定是靠边的,则取反即可
2. 也可以使用i>0 && j>0 && i<n-1 && j<n-1
3. 表达式如果太长,不建议这样写,但如果有规律,还是易读,可以这样写
要特别注意运算符的优先级和结合性
*/
if( i!=0 && j!=0 && i!=n-1 && j!= n-1) // 不靠边元素
{
sum1 += arr[i][j];
}
if(i==j) // 对角线元素
{
sum2 += arr[i][j];
}
}
}
printf("\nsum1=%d\nsum2=%d\n", sum1, sum2);
return 0;
}
P313

/*
编写一程序P313.C实现以下功能
求任意的一个m×n矩阵的鞍点——鞍点是指该位置上的元素在该行上为最大、在该列上为最小,矩阵中可能没有鞍点,但最多只有一个鞍点。
m、n(2<=m<=20、2<=n<=20)及矩阵元素从键盘输入(只考虑int型和每行、每列中没有并列最大/最小的情况)。
编程可用素材:
printf("Please input m and n:");
printf("Please input a juZhen(... hang, ... lie):\n...);
printf("\nmei you an dian.\n");
printf("\nyou an dian, wei: juZhen[...][...]=...\n...);
程序的运行效果应类似地如图1和图2所示,图1中的5 6和
31 42 36 74 2358 88
32 57 37 43 47 1447
97 51 257 7 445 459
33 65 44 3 425 43
68 3425 82 789 123 2134
及图2中的5 6和
31 42 1136 74 2358 88
32 57 4137 43 47 1447
97 51 1257 7 445 459
33 65 744 3 425 43
68 3425 2182 789 123 2134
思路:
1. 可以直接搜行上最大,然后测这个最大是不是列上最小?
也就是说,默认认为这个最大,就是列上最小,然后再测试它是不是最小
成功了,则就是鞍点,程序完成,给结果;
如果没成功,则没有鞍点,给结果;
2. 会有一次行上的列扫描,找最大值,然后按该值所在的列,进行再一次的行扫描,判断最小
整体上扫描行
再行上扫描列,找最大【一定可以找到】
再最大列上,扫描行,判断最小【不一定可以判断成功】
有鞍
无鞍
另一种思路:
1. 两个矩阵并行
a[][]为原始数据矩阵,b[][]为标记阵,初始为为全0
2. 如果某元素a[i][j]在行上最大,则b[i][j]++,即标记为1
3. 如果某元素a[i][j]在列上最小,则b[i][j]++,b[i][j]++即标记为2
4. 最后,扫描b矩阵,如果有b[i][j] == 3 则,a[i][j] 即为对应的鞍点;否则,不存在鞍点
这种思路,比较费空间
还有一种思路:
1. 直接创建相应的数据结构,把行列及值都封装到该结构中
2. 然后再判断,直接返回鞍点或是null
*/
#include <stdio.h>
#define N 20
#define M 20
int main(void)
{
int i, j, k;
int n, m;
int arr[N][M];
int flag = 0;
int max;
int jMark;
printf("Please input m and n:");
scanf("%d %d", &n, &m);
printf("Please input a juZhen(%d hang, %d lie):\n", n, m);
for(i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
scanf("%d", &arr[i][j]);
}
}
// 寻找鞍点
// 先找行上最大,再测是不是列上最小
for(i = 0; i < n; i++)
{
// 不妨先取第i行第1列为最大
max = arr[i][0];
jMark = 0; // 列号记录
// 测试之后还有没有更大的值,如果有,则更新并记录
for (j = 1; j < m; j++)
{
if (max < arr[i][j])
{
max = arr[i][j];
jMark = j; // 更新列号
}
}
// 得到行上最大之后,测试是否列上最小
// min = arr[i][jMark]; // 就当它是最小的
flag = 1; // 这个最大的行值,就当它是鞍点了
for (k = 0; k < n; k++) // 测试是否满足条件
{
if (arr[k][jMark] < arr[i][jMark])
{
flag = 0; // 这个最大的行值,仍然不是鞍点
break; // 一旦不是最小的,本层循环就已经不用再测别的行了
}
}
// 只有一个鞍点,一旦找到,就可以退出外层循环了
if (flag)
{
printf("\nyou an dian, wei: juZhen[%d][%d]=%d\n",i,jMark,max);
break;
}
}
// 未找到鞍点
if(!flag)
{
printf("\nmei you an dian.\n");
}
return 0;
}
P412

/*
编写一程序P412.C实现以下功能
①程序运行时先显示Please input numbers:,再从键盘上读入一组整数(只考虑int型),数与数之间只使用空格或回车作分隔。
数可正可负,最多10000个,但若读入的数为-222时,则表示输入结束且-222不算在该组数内。
②对这一组数按从小到大的顺序进行排序。
③将排序后的这一组数输出到屏幕上,输出格式为每行6个数,数与数之间使用逗号(,)分隔,两个逗号之间的宽度(不算逗号)为6且使用左对齐格式。注意,行尾没有逗号。
编程可用素材:
printf("Please input numbers: ");
printf("\nOutput:\n");
程序的运行效果应类似地如图1所示,其中的红色部分是从键盘输入的内容。
Please input numbers: 100 120 89 72 -19 200 500 210 235 6 24 1234 78 234 -234
-2342 346 23524 7823 -3411 23423 -222
Output:
-3411 ,-2342 ,-234 ,-19 ,6 ,24
72 ,78 ,89 ,100 ,120 ,200
210 ,234 ,235 ,346 ,500 ,1234
7823 ,23423 ,23524
图1 程序运行效果示例
*/
#include <stdio.h>
#define N 10000
void printArray(int arr[], int n);
void sortArray(int arr[], int n);
void swap(int *a, int *b);
int main(void)
{
int count = 0;
int i = 0;
int dataArr[N];
// 输入
printf("Please input numbers: ");
while (1)
{
scanf("%d", &dataArr[i]);
// 但若读入的数为-222时,则表示输入结束且-222不算在该组数内。
if (dataArr[i] == -222)
{
break;
}
i++; // 计数器一定要读入有效时,才计数
}
count = i; // 这一行,可以不要,直接使用i的结果也是可以的
// 原样输出【调试用,调试完成,记得关闭这个插旗】
// printArray(dataArr, count);
// 排序
sortArray(dataArr, count);
// 输出
printArray(dataArr, count);
return 0;
}
/*
输出功能函数
*/
void printArray(int arr[], int n)
{
int i;
// 输出格式为每行6个数,数与数之间使用逗号(,)分隔,两个逗号之间的宽度(不算逗号)为6且使用左对齐格式。注意,行尾没有逗号。
printf("\nOutput:\n");
// 前n-1个数的输出
for (i = 1; i <= n - 1; i++)
{
printf("%-6d", arr[i - 1]);
if (i % 6 == 0) // 第6列,输出回车
{
printf("\n");
}
else // 非第6列,输出逗号
{
printf(",");
}
}
// 最后一个数,即第n个数的输出
printf("%-6d\n", arr[n - 1]);
}
/*
数组排序
arr 为数组名
n 为数据量
自然为升序,即从小到大,大的往上“冒泡”了,也就是大数往后放
泡是气泡,大气泡在小气泡上面
自然就是人长大的顺序,从小到大到老
*/
void sortArray(int arr[], int n)
{
int i, j;
// 冒泡排序
for (i = 0; i < n - 1; i++) // 冒泡时,外层只对应趟数,N个数冒泡,需要N-1趟,因为最后一个自然有序了
{
for (j = 0; j < n - i - 1; j++) // 冒泡时,内层只对应还需要参与排序的数据个数
{
if (arr[j] > arr[j + 1]) // 前面大于后面,则需要交换,把大的往后面放
{
swap(&arr[j], &arr[j + 1]); // 调用交换函数,注意,这里一定是传地址,才可以完成交换
}
}
}
}
/*
交换数据
1. 传进来的是变量的地址
2. 但交换的是变量的值
3. 要搞明白形参和实参,本质上是内存区的控制:
调用时,函数是使用栈内存
调用时,实参是堆内存
如果使用传值方式,则无法改变实参
只有使用传址方式,对实参内存值的改变,才会有效保留下来,才可以完成值的交换
*/
void swap(int *a, int *b)
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}