案例目录
- 数学类程序
- 完数(完全数)
- 求亲密数
- 水仙花数(阿姆斯特朗数)
- 求自守数
- 求勾股数
- 求三角形面积
- 最大公约数
- 小公倍数
- 一元二次方程求根
- 素数(质数、哥德巴赫猜想)
- 猴子吃桃
- 斐波那契数列(兔子生崽)
- 回文数
- 九九乘法表
- 百钱买百鸡问题
- 给5位的正整数求…
- 三个整数顺序输出
- 求n个数相同数相加
- 判断输入整数位数
- 求阶乘:n!
- 求π
- 求一个分数序列的前20项之和
- 球自由落体
- 判断无重复三位数
- 评委打分
- 输入10个数交换首尾输出
- 求三位数各个数之和
- 极坐标转直角坐标
- 温度转换
- 分段函数
- 泰勒级数展开式
- 有穷级数相加
- 打印图形类程序
- 打印棱形
- 杨辉三角
- 打印回文塔
- 字符型类程序
- 删除字符串某字符
- 单行统计字符个数
- 多行统计字符个数
- 将一行电文译成密码
- 不使用函数连接字符串
- 不使用函数比较字符串
- 不使用函数复制字符串
- 将两字符串中的字符比较并输出
- 求一个字符串的长度
- 字符串排序
- 统计字符串中出现最多次的小写字母
- 统计字符串是元音(A E I O U)的个数
- 数字字符串转整数
- 时间类程序
- 输入月份号,输出该月的英文月名
- 输入某年某月某日在本年中是第几天
- 数组类程序
- 求一个3 X 3的整形矩阵对角线元素之和
- 数组的逆置
- 输出"魔方阵"
- 矩阵转置
- 输入6个整数,按对称矩阵排列
- 鞍点数(马鞍数)
- 结构体类程序
- 编写一个函数print
- 有10个学生输入……
- 约瑟夫环问题(三种方法)
- 链表类程序
- 删除动态链表中指定节点
- 动态链表插入结点
- 链表排序
- 查找删除节点
- 按年龄删除节点
- 排序算法程序
- 冒泡排序(Bubble Sort)
- 选择排序(Selection Sort)
- 插入排序
- 查找算法程序
- 查找算法 -- 简介
- 顺序查找
- 二分查找(折半查找)
数学类程序
完数(完全数)
问题描述
求某一范围内完数的个数。
如果一个数等于它的因子之和,则称该数为“完数”(或“完全数”)。例如,6的因子为1、2、3,而 6=1+2+3,因此6是“完数”。
问题分析
根据完数的定义,解决本题的关键是计算出所选取的整数i(i的取值范围不固定)的因子(因子就是所有可以整除这个数的数),将各因子累加到变量s (记录所有因子之和),若s等于i,则可确认i为完数,反之则不是完数。
算法设计
对于这类求某一范围(由于本题范围不固定,在编程过程中采用键盘输入的方式)内满足条件的数时,一般釆用遍历的方式,对给定范围内的数值一个一个地去判断是否满足条件,这一过程可利用循环来实现。
本题的关键是求出选取数值i
的因子,即从1到i-1
范围内能整除i的数,看某一个数j是否为i的因子,可利用语句if(i%j==0)
进行判断,求某一个数的所有因子,需要在1到i-1
范围内进行遍历,同样釆用循环实现。因此,本题从整体上看可利用两层循环来实现。外层循环控制该数的范围2〜n;内层循环j控制除数的范围为1〜i
,通过i
对j
取余,是否等于0,找到该数的各个因子。
注意每次判断下一个选定数之前,必须将变量s的值重新置为0
下面是完整的代码:
#include <stdio.h>
int main()
{int i, j, s, n; /*变量i控制选定数范围,j控制除数范围,s记录累加因子之和*/printf("请输入所选范围上限:");scanf("%d", &n); /* n的值由键盘输入*/for (i = 2; i <= n; i++){s = 0; /*保证每次循环时s的初值为0*/for (j = 1; j < i; j++){if (i % j == 0) /*判断j是否为i的因子*/s += j;}if (s == i) /*判断因子这和是否和原数相等*/printf("It's a perfect number:%d\n", i);}return 0;
}
运行结果:
请输入所选范围上限:10000↙︎It's a perfect number:6It's a perfect number:28It's a perfect number:496It's a perfect number:8128
求亲密数
问题描述
如果整数A的全部因子(包括1,不包括A本身)之和等于B;且整数B的全部因子(包括1,不包括B本身)之和等于A,则将整数A和B称为亲密数。求3000以内的全部亲密数。
问题分析
根据问题描述,该问题可以转化为:给定整数A,判断A是否有亲密数。
为解决该问题,首先定义变量a,并为其赋初值为某个整数。则按照亲密数定义,要判断a中存放的整数是否有亲密数,只要计算出该整数的全部因子的累加和,并将该累加和存放到另一个变量b中,此时b中存放的也是一个整数。再计算b中存放整数的全部因子的累加和,将该累加和存放到变量n中。
若n等于a则可判定变量a和b中所存放的整数是亲密数。
算法设计
计算数A的各因子的算法:用A依次对i(i的范围可以是1〜A-1、1〜(A/2-1)中之一) 进行模(“%”,在编程过程中一定注意求模符号两边参加运算的数据必须为整数)运算,若模运算结果等于0,则i为A的一个因子加;否则i就不是A的因子。将所求得的因子累到变量B。
接下来求变量B的因子:算法同上,将B的因子之和累加到变量n。根据亲密数的定义判断变量n是否等于变量A(if(n==a)),若相等,则A和B是一对亲密数,反之则不是。
代码:
#include <stdio.h>
int main()
{int a, i, b, n;printf("There are following friendly--numbers pair smaller than 3000:\n");for (a = 1; a < 3000; a++) /*穷举3000以内的全部整数*/{for (b = 0, i = 1; i <= a / 2; i++) /*计算数a的各因子,各因子之和存放于b*/if (!(a % i))b += i;for (n = 0, i = 1; i <= b / 2; i++) /*计算b的各因子,各因子之和存于n*/if (!(b % i))n += i;if (n == a && a < b) /*使每对亲密数只输出一次*/printf("%4d--%4d ", a, b); /*若n=a,则a和b是一对亲密数,输出*/}return 0;
}
运行结果:
There are following friendly--numbers pair smaller than 3000:220-- 284 1184--1210 2620--2924
水仙花数(阿姆斯特朗数)
阿姆斯特朗数也就是俗称的水仙花数,是指一个三位数,其各位数字的立方和等于该数本身。例如:153=13+53+33,所以 153 就是一个水仙花数。求出所有的水仙花数。
算法思想
对于阿姆斯特朗数问题,根据水仙花数的定义,需要分离出个位数、十位数和百位数。然后按其性质进行计算并判断,满足条件则打印输出,否则不打印输出。
因此,阿姆斯特朗数问题可以利用循环语句解决。设循环变量为 i,初值为 100,i 从 100 变化到 1000;依次判断条件是否成立,如果成立则输出,否则不输出。
算法思想具体如下:
- ① 分离出个位数,算术表达式为:
j=i%10
。 - ② 分离出十位数,算术表达式为:
k=i/10%10
。 - ③ 分离出百位数,算术表达式为:
n=i/100
。 - ④ 判断条件是否成立。若是,执行步骤 ⑤;若不是,执行步骤 ⑥。
- ⑤ 打印输出结果。
- ⑥ i 自增 1。
- ⑦ 转到 ① 执行,直到 i 等于 1000。
其判断的条件为:j*j*j+k*k*k+n*n*n==i
。
程序代码
#include <stdio.h>
int main()
{int i, j, k, n;for (i = 100; i < 1000; i++){j = i % 10;k = i / 10 % 10;n = i / 100;if (j * j * j + k * k * k + n * n * n == i)printf("%5d\n", i);}return 0;
}
调试运行结果
所有的阿姆斯特朗数,如下所示:
153370371407
求自守数
自守数是指一个数的平方的尾数等于该数自身的自然数。例如:
52 = 25 252 = 625 762 = 5776 93762 = 87909376
算法思想
用原数字的各个位数字单独去乘原数字 得到一个数值,再对其保留位数求模(求模基数为比原数字大的最小的10^n)然后再乘以这个数字所在位的位权 各位就 1 ,十位就10 ,百位就是 100,
然后把所得各数相加,再对其保留位数求模
得数如果和原数字想等 那这个数就是自守数
求100000以内的自守数。
代码:
#include <stdio.h>
int main()
{int number,mul,k,a,b;for(number=1;number<=100000;number++)//遍历各数 {for(a=1,mul=number;mul>0;mul/=10) a*=10;//计算保留位数求模基数 mul=0;b=1;for(k=number;k>0;k/=10)//循环求各位数与原数字乘积再求模再乘位权 {mul=mul+(number*(k%10))%a*b;a/=10;//每次循环,求模数,降位 b*=10;//每次循环,位权数,升位}mul%=b;//所得和 再求模 if(number==mul) printf("%d ",mul);//满足条件输出 }
}
运行结果:
It exists following automorphic nmbers small than 100000:0 1 5 6 25 76 376 625 9376 90625
求勾股数
问题描述
求100以内的所有勾股数。
所谓勾股数,是指能够构成直角三角形三条边的三个正整数(a,b,c)。
问题分析
根据“勾股数”定义,所求三角形三边应满足条件 a2 + b2 = c2。可以在所求范围内利用穷举法找出满足条件的数。
算法分析
采用穷举法求解时,最容易想到的一种方法是利用3个循环语句分别控制变最a、b、c的取值范围,第1层控制变量a,取值范围是1〜100。在a值确定的情况下再确定b值,即第2层控制变量b,为了避免结果有重复现象,b的取值范围是a+1〜100。a、b的值已确定,利用穷举法在b+1〜100范围内一个一个的去比较,看当前c值是否满足条件 a2 + b2 = c2,若满足,则输出当前a、b、c的值,否则继续寻找。
伪代码如下:
//...
for(a=l; a<=100; a++) /*确定a的取值*/
for(b=a+l; b<=100; b++) /*确定b的取值*/
for(c=b+l; c<=100; c++) /*确定c的取值*/
if(a*a+b*b==c*c)
printf ("%d\t%d\t%d\n", a, b, c) /*判断三个变量是否满足勾股数条件*/
//...
但是上述算法的效率比较低,根据 a2 + b2 = c2 这个条件,在a、b值确定的情况下,没必要再利用循环一个一个去寻找c值。若a、b、c是一组勾股数,则 a2 + b2 的平方根一定等于c,c的平方应该等于a、b的平方和,所以可将的平方根赋给c,再判断c的平方是否等于。根据“勾股数”定义将变量定义为整型,a2 + b2 的平方根不一定为整数, 但变量c的类型为整型,将一个实数赋给一个整型变量时,可将实数强制转换为整型(舍弃小数点之后的部分)然后再赋值,这种情况下得到的c的平方与原来的的值肯定不相等,所以可利用这一条件进行判断。
代码:
#include <stdio.h>
#include <math.h>
int main()
{int a, b, c, count = 0;printf("100以内的勾股数有:\n");printf(" a b c a b c a b c a b c\n");/*求100以内勾股数*/for (a = 1; a <= 100; a++)for (b = a + 1; b <= 100; b++){c = (int)sqrt(a * a + b * b); /*求c值*/if (c * c == a * a + b * b && a + b > c && a + c > b && b + c > a && c <= 100) /*判断c的平方是否等于a2+b2*/{printf("%4d %4d %4d ", a, b, c);count++;if (count % 4 == 0) /*每输出4组解就换行*/printf("\n");}}printf("\n");return 0;
}
运行结果:
100以内的勾股数有:a b c a b c a b c a b c3 4 5 5 12 13 6 8 10 7 24 258 15 17 9 12 15 9 40 41 10 24 2611 60 61 12 16 20 12 35 37 13 84 8514 48 50 15 20 25 15 36 39 16 30 3416 63 65 18 24 30 18 80 82 20 21 2920 48 52 21 28 35 21 72 75 24 32 4024 45 51 24 70 74 25 60 65 27 36 4528 45 53 28 96 100 30 40 50 30 72 7832 60 68 33 44 55 33 56 65 35 84 9136 48 60 36 77 85 39 52 65 39 80 8940 42 58 40 75 85 42 56 70 45 60 7548 55 73 48 64 80 51 68 85 54 72 9057 76 95 60 63 87 60 80 100 65 72 97
求三角形面积
三角形三边分别为 a,b,c,三角形的半周长为p,面积为S
存在公式定理如下:
p = a + b + c 2 p=\frac {a+b+c} {2} p=2a+b+c
S = p ( p − a ) ( p − b ) ( p − c ) S=\sqrt {p(p-a)(p-b)(p-c)} S=p(p−a)(p−b)(p−c)
代码如下
#include <stdio.h>
#include <math.h>
int main()
{int a=3,b=4,c=5;double p=0;double S=0;p = (a+b+c)/2;S = sqrt(p*(p-a)*(p-b)*(p-c));printf("S:%lf\n",S);return 0;
}
最大公约数
问题描述
求任意两个正整数的最大公约数(GCD)。
问题分析
如果有一个自然数a能被自然数b整除,则称a为b的倍数,b为a的约数。几个自然数公有的约数,叫做这几个自然数的公约数。公约数中最大的一个公约数,称为这几个自然数的最大公约数。
算法设计
用穷举法按从小到大(初值为1,最大值为两个整数当中较小的数)的顺序将所有满足条件的公约数列出,输出其中最大的一个
#include <stdio.h>
int main()
{int m, n, temp, i;printf("Input m & n:");scanf("%d%d", &m, &n);if (m < n) /*比较大小,使得m中存储大数,n中存储小数*/{ /*交换m和n的值*/temp = m;m = n;n = temp;}for (i = n; i > 0; i--) /*按照从大到小的顺序寻找满足条件的自然数*/if (m % i == 0 && n % i == 0){ /*输出满足条件的自然数并结束循环*/printf("The GCD of %d and %d is: %d\n", m, n, i);break;}return 0;
}
Input m & n:100 125
The GCD of 125 and 100 is: 25
小公倍数
问题描述
求任意两个正整数的最小公倍数(LCM)。
问题分析
如果有一个自然数a能被自然数b整除,则称a为b的倍数,b为a的约数,对于两个整数来说,指该两数共有倍数中最小的一个。计算最小公倍数时,通常会借助最大公约数来辅助计算。
最小公倍数=两数的乘积/最大公约(因)数,解题时要避免和最大公约(因)数问题混淆。
对于最小公倍数的求解,除了利用最大公约数外,还可根据定义进行算法设计。要求任意两个正整数的最小公倍数即,求出一个最小的能同时被两整数整除的自然数。
算法设计
对于输入的两个正整数m和n每次输入的大小顺序可能不同,为了使程序具有一般性,首先对整数所m和n进行大小排序,规定变量m中存储大数、变量n中存储小数。
输入的两个数,大数m是小数n的倍数,那么大数m即为所求的最小公倍数;若大数m不能被小数n整除则需要寻找一个能同时被两数整除的自然数。从大数m开始依次向后递增直到找到第一个能同时被两数整除的数为止,所以循环变量i的初值为寻找第一个能同时被两整数整除的自然数,并将其输出。需要注意的是,在找到第一个满足条件的i值后,循环没必要继续下去,所以用break来结束循环。
代码
#include <stdio.h>
int main()
{int m, n, temp, i;printf("Input m & n:");scanf("%d%d", &m, &n);if (m < n) /*比较大小,使得m中存储大数,n中存储小数*/{temp = m;m = n;n = temp;}for (i = m; i > 0; i++) /*从大数开始寻找满足条件的自然数*/if (i % m == 0 && i % n == 0){ /*输出满足条件的自然数并结束循环*/printf("The LCW of %d and %d is: %d\n", m, n, i);break;}return 0;
}
运行结果:
Input m & n:6 24
The LCW of 24 and 6 is: 24
最大公约数&最小公倍数
辗转相除法
#include<stdio.h>
int main()
{ int m, n, a, b, t, c;printf("Input:\n");scanf("%d%d", &a, &b);m=a; n=b;while(b!=0) /* 余数不为0,继续相除,直到余数为0 */ { c=a%b; a=b; b=c;}printf("最大公约数:%d\n", a);printf("最小公倍数:%d\n", m*n/a);
}
辗转相除法(函数调用方式)
#include <stdio.h>
int gcd(int,int);
int main()
{int m, n;printf("input:");scanf("%d%d", &m, &n); printf("最大公约数:%d最小公倍数:%d\n", gcd(m, n) , m*n/gcd(m, n));
}
int gcd(int m,int n) {int r; while(r = m % n) {m = n;n = r; }return n;
}
一元二次方程求根
求 a x 2 + b x + c = 0 ax^2+bx+c=0 ax2+bx+c=0的根。
分别考虑 d = b 2 − 4 a c d=b^2-4ac d=b2−4ac大于0,等于0和小于0这三种情况。
1.获取a、b、c的值
2.计算 b 2 − 4 a c b^2 - 4ac b2−4ac的结果并给d
3.如果d < 0, 则方程没有实根
4.如果d == 0,则方程有一个实根b/2a
5.如果d > 0, 则方程有两个实根 x = − b ± b 2 − 4 a c 2 a x=\frac{-b\pm\sqrt{b^2-4ac}}{2a} x=2a−b±b2−4ac
x1 = ( - b + sqrt(d)) /2*a;
x2 = ( - b - sqrt(d)) /2*a;
eg: a=1 b=2 c=1 只有一个根:-1
#include <stdio.h>
#include <math.h>
int main()
{int a, b, c, d;double x1, x2,m;scanf("%d%d%d", &a, &b, &c);d = b*b - 4*a*c;m = - b/(2*a);if(d < 0) {printf("方程没有实数根");}else if(d == 0) {printf("方程有一个实根:%f", m);}else if(d > 0) {x1 = ( - b + sqrt(d)) /2*a;x2 = ( - b - sqrt(d)) /2*a;printf("%.2f %.2f", x1, x2);}return 0;
}
素数(质数、哥德巴赫猜想)
问题描述
素数又称质数。所谓素数是指除了 1 和它本身以外,不能被任何整数整除的数,例如17就是素数,因为它不能被 2~16 的任一整数整除。
问题分析
1,判断n是否能被2~n-1整除
输入的数n不能被2~(n-1)整除,说明是素数
输入的数n能被2~(n-1)整除,说明不是素数
2,判断n是否能被2~ n \sqrt n n间的整数整除
输入的数n不能被2~ n \sqrt n n整除,说明是素数
输入的数n能被2~ n \sqrt n n整除,说明不是素数
算法设计
1.素数是指大于1且只能被1和它本身整除的正整数,2是最小素数,素数有无穷个;
2.如果整数x大于2,那么就判断x对2~(x-1)取余是否为0,如果是,肯定不是素数,如果都不是,则为素数;
1)判断素数
#include <stdio.h>
int main()
{int n, i, flag = 0;printf("输入一个正整数: ");scanf("%d",&n);for(i=2; i<=n/2; ++i){// 符合该条件不是素数if(n%i==0){flag=1;break;}}if (flag==0)printf("%d 是素数",n);elseprintf("%d 不是素数",n); return 0;
}
2)判断两个数之间的素数
#include <stdio.h>
int main()
{int m, i, h = 0, leap;for (m = 100; m <= 1000; m++){leap = 1;for (i = 2; i * i <= m; i++)if (m % i == 0){leap = 0;break;}if (leap){printf(" %d ", m);}}return 0;
}
3)计算一个数是否可为两个素数之和(哥德巴赫猜想)
#include <stdio.h>int checkPrime(int n);
int main()
{int n, a,b, flag = 0;printf("输入大于4的偶数: ");scanf("%d", &n);for(a= 3; a <= n/2; a++) {// 检测判断b = n - a;if (checkPrime(a)&&checkPrime(b)) {printf("%d = %d + %d\n", n, a, b); }}if (flag == 0) printf("%d 不能分解为两个素数。", n);return 0;
}
// 判断素数
int checkPrime(int n)
{int i, isPrime = 1; for(i = 2; i <= n/2; i++) {if(n % i == 0) {isPrime = 0;break;} }return isPrime;
}
猴子吃桃
题目:猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,只剩下一个桃子了。求第一天共摘了多少。
分析
- 10day 1peach
- 9 d a y ( d a y 10 + 1 ) × 2 = ( 1 + 1 ) × 2 = 4 9day (day10+1)\times2 = (1+1)\times2=4 9day(day10+1)×2=(1+1)×2=4
- 8 d a y ( d a y 9 + 1 ) × 2 = ( 4 + 1 ) × 2 = 10 8day (day9+1)\times2 = (4+1)\times2=10 8day(day9+1)×2=(4+1)×2=10
#include<stdio.h>
int main()
{int cnt = 1,i;for ( i = 0; i < 9; ++i){cnt += 1;cnt *= 2;}printf("第一天共摘%d个", cnt);return 0;
}
递归法
#include <stdio.h> int func(int day)
{if(day==10)return 1; //终止条件elsereturn (func(day+1)+1)*2; //依赖关系} int main(){ printf("第一天有%d个桃子!",func(1));return 0;}
斐波那契数列(兔子生崽)
题目:古典问题(兔子生崽):有一对兔子,从出生后第3个月起每个月都生一对兔子,
小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?(输出前40个月即可)
(斐波那契数列)
#include<stdio.h>
int main()
{int cnt,i;int cnt1 = 1, cnt2 = 1;printf("第1个月:%d\n", cnt1);printf("第2个月:%d\n", cnt2);for ( i = 3; i < 41; ++i){cnt = cnt1 + cnt2;printf("第%d个月:%d\n", i, cnt);cnt1 = cnt2;cnt2 = cnt;}return 0;
}
回文数
回文数就是它的数字反向排列所得的自然数与它的本身是相等的,比如,若n=12321,则称它是一个回文数。
void main(){int num,s,y=0;printf("Please input numbers: ");scanf("%d", &num);s=num;while(s>0){y=y*10+s%10;s=s/10;}if(y==num){printf("%d是一个回文数!\n", num);}else{printf("%d不是一个回文数!\n", num);}
}
求5位整数中,既是质素又是回文数的个数
#include <stdio.h>
int main()
{int i,j,ge,shi,qian,wan,flag,count=0;for (i = 10000; i <= 99999; i++){//获取每一个5位数,然后得到它的个位,十位,千位,万位ge = i%10;shi = i/10%10;qian = i/1000%10;wan = i/10000%10;flag = 1;if ((ge==wan) && (shi==qian))//把满足条件的数据输出{//判断是否为质素 for (j = 2; j * j < i; j++)if (i % j == 0){flag = 0;break; }if (flag){printf("%d\t", i);count++;} }}printf("总计%d", count);printf("\n");return 0;
}
九九乘法表
#include <stdio.h>
int main()
{int i, j; // i, j控制行或列for (i = 1; i <= 9; i++){for (j = 1; j <= 9; j++)// %2d 控制宽度为两个字符,且右对齐;如果改为 %-2d 则为左对齐// \t为tab缩进printf("%d*%d=%2d\t", i, j, i * j);printf("\n");}return 0;
}
运行结果:
1*1= 1 1*2= 2 1*3= 3 1*4= 4 1*5= 5 1*6= 6 1*7= 7 1*8= 8 1*9= 9
2*1= 2 2*2= 4 2*3= 6 2*4= 8 2*5=10 2*6=12 2*7=14 2*8=16 2*9=18
3*1= 3 3*2= 6 3*3= 9 3*4=12 3*5=15 3*6=18 3*7=21 3*8=24 3*9=27
4*1= 4 4*2= 8 4*3=12 4*4=16 4*5=20 4*6=24 4*7=28 4*8=32 4*9=36
5*1= 5 5*2=10 5*3=15 5*4=20 5*5=25 5*6=30 5*7=35 5*8=40 5*9=45
6*1= 6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 6*7=42 6*8=48 6*9=54
7*1= 7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 7*8=56 7*9=63
8*1= 8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 8*9=72
9*1= 9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
【代码二】输出右上三角形和左上三角形:
#include <stdio.h>int main() {int i,j;for(i=1;i<=9;i++){for(j=1;j<=9;j++){if(j<i)//打印八个空格,去掉空格就是左上三角形 printf(" ");elseprintf("%d*%d=%2d ",i,j,i*j);}printf("\n"); }return 0;}
运行结果:
1*1= 1 1*2= 2 1*3= 3 1*4= 4 1*5= 5 1*6= 6 1*7= 7 1*8= 8 1*9= 92*2= 4 2*3= 6 2*4= 8 2*5=10 2*6=12 2*7=14 2*8=16 2*9=183*3= 9 3*4=12 3*5=15 3*6=18 3*7=21 3*8=24 3*9=274*4=16 4*5=20 4*6=24 4*7=28 4*8=32 4*9=365*5=25 5*6=30 5*7=35 5*8=40 5*9=456*6=36 6*7=42 6*8=48 6*9=547*7=49 7*8=56 7*9=638*8=64 8*9=729*9=81
去掉八个空格后的运行结果:
1*1= 1 1*2= 2 1*3= 3 1*4= 4 1*5= 5 1*6= 6 1*7= 7 1*8= 8 1*9= 9
2*2= 4 2*3= 6 2*4= 8 2*5=10 2*6=12 2*7=14 2*8=16 2*9=18
3*3= 9 3*4=12 3*5=15 3*6=18 3*7=21 3*8=24 3*9=27
4*4=16 4*5=20 4*6=24 4*7=28 4*8=32 4*9=36
5*5=25 5*6=30 5*7=35 5*8=40 5*9=45
6*6=36 6*7=42 6*8=48 6*9=54
7*7=49 7*8=56 7*9=63
8*8=64 8*9=72
9*9=81
【代码三】输出右下和左下三角形:
#include <stdio.h>int main(){int i,j,n;for(i=1;i<=9;i++){// 将下面的for循环注释掉,就输出左下三角形for(n=1; n<=9-i; n++)printf(" ");for(j=1;j<=i;j++)printf("%d*%d=%2d ",i,j,i*j);printf("\n");}return 0;}
运行结果:
1*1= 12*1= 2 2*2= 43*1= 3 3*2= 6 3*3= 94*1= 4 4*2= 8 4*3=12 4*4=165*1= 5 5*2=10 5*3=15 5*4=20 5*5=256*1= 6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=367*1= 7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=498*1= 8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
9*1= 9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
去掉循环后的运行结果:
1*1= 1
2*1= 2 2*2= 4
3*1= 3 3*2= 6 3*3= 9
4*1= 4 4*2= 8 4*3=12 4*4=16
5*1= 5 5*2=10 5*3=15 5*4=20 5*5=25
6*1= 6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
7*1= 7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
8*1= 8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
9*1= 9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
百钱买百鸡问题
题目分析
如果用数学的方法解决百钱买百鸡问题,可将该问题抽象成方程式组。设公鸡 x 只,母鸡 y 只,小鸡 z 只,得到以下方程式组:
A: 5 x + 3 y + 1 3 z = 100 5x+3y+\frac {1}{3z} = 100 5x+3y+3z1=100
B: x + y + z = 100 x+y+z = 100 x+y+z=100
C: 0 ≤ x ≤ 100 0 \le x \le 100 0≤x≤100
D: 0 ≤ y ≤ 100 0 \le y \le 100 0≤y≤100
E: 0 ≤ z ≤ 100 0 \le z \le100 0≤z≤100
用穷举法的方式来解题,需要 10 1 3 101^3 1013 次猜解
#include <stdio.h>int main(){int i, j, k;printf("百元买百鸡的问题所有可能的解如下:\n");for( i=0; i <= 100; i++ )for( j=0; j <= 100; j++ )for( k=0; k <= 100; k++ ){if( 5*i+3*j+k/3==100 && k%3==0 && i+j+k==100 ){printf("公鸡 %2d 只,母鸡 %2d 只,小鸡 %2d 只\n", i, j, k);}}return 0;}
运行结果:
百元买百鸡的问题所有可能的解如下:
公鸡 0 只,母鸡 25 只,小鸡 75 只
公鸡 4 只,母鸡 18 只,小鸡 78 只
公鸡 8 只,母鸡 11 只,小鸡 81 只
公鸡 12 只,母鸡 4 只,小鸡 84 只
给5位的正整数求…
要求:
- ①求出它是几位数;
- ②分别输出每一位数字;
- ③按逆序输出各位数字,
例如原数为321,应输出123。
①求出它是几位数;
解题思路: 大于10000就是5位,否则大于1000就是四位,否则大于100是三位…
答案:
#include <stdio.h>
int main()
{int num;printf("enter num:");scanf("%d", &num);if (num > 99999 || num < 0) {printf("请输入0~99999之间的正数\n");return -1;}if (num >= 10000) {printf("5\n");}else if (num >= 1000) {printf("4\n");}else if (num >= 100) {printf("3\n");}else if (num >= 10) {printf("2\n");}else {printf("1\n");}return 0;
}
②分别输出每一位数字;
解题思路: 99999除以10000则输出9;9999除以1000则输出9,…
答案:
#include <stdio.h>
int main()
{int num;printf("enter num:");scanf("%d", &num);if (num > 99999 || num < 0) {printf("请输入0~99999之间的数字\n");return -1;}if (num / 10000 > 0) {//取出万位数字printf("%d ", num / 10000);}if (num%10000 >= 1000) {//取余10000则可以取出低四位的数据,除以1000则得到千位的数字printf("%d ", (num % 10000) / 1000);}if (num%1000 >= 100) {//取余1000则可以取出低三位的数据,除以100则得到百位的数字printf("%d ", (num % 1000) / 100);}if (num%100 >= 10) {//取余100则可以取出低两位的数据,除以10则得到十位的数字printf("%d ", (num % 100) / 10);}if (num%10 >= 0) {//取余10则取出个位数字printf("%d ", num % 10);}printf("\n");return 0;
}
③按逆序输出各位数字,例如原数为321,应输出123。
解题思路: 思路与第二题相同,只不过将整个过程逆序即可
答案:
#include <stdio.h>
int main()
{int num;printf("enter num:");scanf("%d", &num);if (num > 99999 || num < 0) {printf("请输入0~99999之间的数字\n");return -1;}if (num % 10 >= 0) {printf("%d ", num % 10);}if (num % 100 >= 10) {printf("%d ", (num % 100) / 10);}if (num % 1000 >= 100) {printf("%d ", (num % 1000) / 100);}if (num % 10000 >= 1000) {printf("%d ", (num % 10000) / 1000);}if (num / 10000 > 0) {printf("%d ", num / 10000);}printf("\n");return 0;
}
三个整数顺序输出
输入三个整数,按由小到大的顺序输出
答案:
#include<stdio.h>
int main()
{int a,b,c,t=0;scanf("%d%d%d",&a,&b,&c);if(a>b){t=a;a=b;b=t;}if(a>c){t=a;a=c;c=t;} if(b>c){t=b;b=c;c=t;}printf("%d %d %d ",a,b,c);return 0;}
输入4个整数,要求按由小到大的顺序输出。
解题思路: 四个数中先找到最小的,剩下的三个数中找到第二小的,剩下的两个数中找到第三小的。
答案:
#include <stdio.h>
int main()
{int a, b, c, d;int max_num;scanf("%d %d %d %d", &a, &b, &c, &d);int tmp;//找到最小的数if (a > b) {tmp = a; a = b; b = tmp; // a>b两个数据交换,则给a存储小的b}if (a > c) {tmp = a; a = c; c = tmp;}if (a > d) {tmp = a; a = d; d = tmp;}//找到第二小的数,不需要和最小的数比较if (b > c) {tmp = b; b = c; c = tmp;}if (b > d) {tmp = b; b = d; d = tmp;}//找到第三小的数据,不需要和第一和第二小比较if (c > d) {tmp = c; c = d; d = tmp;}printf("%d %d %d %d\n", a, b, c, d);return 0;
}
编写一个C程序,运行时输人a,b,c三个值,输出其中值最大者
代码示例:
#include<stdio.h>int main()
{int a, b, c, max;printf("请输入三个数:\n");scanf("%d%d%d", &a, &b, &c);if (a > b){max = a;}else{max = b;}if (c > max){max = c;}printf("三个数中最大的数为:%d", max);return 0;}
求n个数相同数相加
S n = a + a a + a a a a a + … + a ⏞ n个a 之值,其中 a 是一个数字, n 表示 a 的位数, n 由键盘输入 Sn=a+aa+aaa\overbrace{aa+…+a}^{\text{n个a}}之值,其中a是一个数字,n表示a的位数,n由键盘输入 Sn=a+aa+aaaaa+…+a n个a之值,其中a是一个数字,n表示a的位数,n由键盘输入
答案解析:
该题目可以将数字拆分为 a * 10^n + 前一个数字
,例如:
2 = 2 * 10^0 + 0 :
默认2的前一个数字为0,也就是没有任何值
22 = 2 * 10^1 + 2 :
22的前一个数字为2
222 = 2*10^2 + 22 :222
的前一个数字为22
以此类推…
所以,在每次循环的时候,需要保存下,上一次结果的值,方便下一次计算
还需要使用到C库当中使用的pow函数,来计算某个数的n次方,在该题目当中使用的是10的n次方,n随着循环的次数,以此递增。
代码示例:
#include <stdio.h>
#include <math.h>int main()
{//n为a的个数int n,i;double a, prev_sum = 0.0, total_sum = 0.0;printf("请输入a的值以及n的值: ");scanf("%lf %d", &a, &n);//循环n次求总和for (i = 0; i < n; i++){prev_sum += a * pow(10, i); total_sum += prev_sum;}printf("总和为:%lf\n", total_sum);return 0;
}
##士兵报数
题目
按从1至6报数,最末一个士兵报的数为5;6人一组剩余5人
按从1至7报数,最末一个士兵报的数为4;7人一组剩余4人
最后再按从1至11报数,末一个士兵报的数为10;11人一组剩余10人
算法
使用穷举算法用循环把各种可能的情况都给走一遍
然后用if条件把满足要求的结果给筛选出来。
#include <stdio.h>
int main()
{int n; //士兵数 for(n=1;;n++){if(n%5==1 && n%6==5 && n%7==4 && n%11==10 ){printf("%d",n); break;}}
return 0;
}
判断输入整数位数
// 输入一个整数 输出是几位数
#include <stdio.h>
int main()
{int n, count = 0;scanf("%d", &n);if (n == 0){count = 1;printf("%d", count);}else{while (n != 0){n /= 10;count++;}printf("%d", count);}return 0;
}
求阶乘:n!
求 ∑ n = 1 20 n ! ( 即求 1 ! + 2 ! + 3 ! + 4 ! + … + 20 ! ) 。 求\sum\limits_{n=1}^{20}n! (即求1!+2!+3!+4!+…+20!)。 求n=1∑20n!(即求1!+2!+3!+4!+…+20!)。
求阶乘sum的和
#include<stdio.h>
int main()
{int i = 0;int ret = 1;int sum = 0;for (i = 1; i <= 10; i++){ret *= i;//ret单个阶乘sum += ret;//sum=阶乘和}printf("阶乘和sum = %d\n", sum);return 0;
}
求某个数的阶乘
#include<stdio.h>
int main()
{int a = 0;int i = 0;scanf("%d", &a);int j = a;for (i = 1; i < a; i++){j = j * i;}printf("%d", j);return 0;
}
求π
π = 2 × 2 2 1 × 3 × 4 2 3 × 5 × … × ( 2 n ) 2 ( 2 n − 1 ) × ( 2 n + 1 ) … π =2\times \frac {2^2}{1\times3}\times\frac{4^2}{3\times5} \times… \times \frac{(2n)^2}{(2n-1) \times(2n+1)} … π=2×1×322×3×542×…×(2n−1)×(2n+1)(2n)2…
#include <stdio.h>
main()
{double s, i = 1, p = 2;int n;scanf("%d", &n);while (i <= n){s = (4.0 * i * i) / ((2 * i - 1) * (2 * i + 1));p *= s;i++;}printf("%lf", p);
}
求一个分数序列的前20项之和
3 2 , 5 3 , 8 5 , 13 8 , 25 13 , … \frac{3}{2}, \frac{5}{3} , \frac{8}{5} ,\frac{13}{8}, \frac{25}{13} ,… 23,35,58,813,1325,…
答案解析:
从题目当中可以看出来,下一个分式当中的分子为上一个分式中分子和分母的和,分母为上一个分式的分子。通过这个规律不难推出下一个分式的分子和分母,需要注意的是,保存分式的结果不能使用到整数,因为有可能会有小数的存在,所以我们需要选用浮点数double
#include <stdio.h>
//定义循环次数
#define COUNT 20int main()
{//定义第一个分式的分子为a, 值为2; 定义分母为b,值为1//定义相加的和为sum,初始值为0int i;double a = 2, b = 1, sum = 0;double temp;for (i = 0; i < COUNT; i++){sum += a / b;//记录前一项分子temp = a;//前一项分子与分母之和为后一项分子a = a + b;//前一项分子为后一项分母b = temp;}printf("前%d项之和为:sum=%9.7f\n", COUNT, sum);return 0;
}
球自由落体
一个球从100m高度自由落下,每次落地后反弹回原高度的一半,再落下,再反弹。求它在第10次落地时共经过多少米,第10次反弹多高
答案解析:
该题目需要循环10次,在每一循环的时候,需要将下落的高度和回弹的高度加起来。需要注意的点,第10次下落不需要在计算回弹的距离了,所以需要特殊处理下。在计算每次高度的时候,会有小数存在,所以需要选用浮点数
代码示例:
#include <stdio.h>int main()
{int i;//总高度double total_m = 100.0;//小球经历的米数double total_sum = 0.0;for (i = 0; i < 10; i++){total_sum += total_m;total_m /= 2;total_sum += total_m;}//不需要计算第10次的反弹高度,所以减去total_sum -= total_m;printf("小球总共经历%lf米, 第10次反弹%lf米\n", total_sum, total_m);return 0;
}
判断无重复三位数
#include <stdio.h>
int main()
{int a, b, c, count = 0; for(a = 1; a <= 4; a++) for(b = 1; b <= 4; b++) for(c = 1; c <= 4; c++) {if(a == b||b == c||c == a) continue;printf("%d%d%d\n", a, b, c);count++; }printf("count=%d\n", count);
}
评委打分
#include<stdio.h>
void main()
{int sum = 0,i;double avg,b;int a[10];int max,min;for(i=0;i<10;i++){scanf("%d",&a[i]);if(i==0)//只有第一次赋值max=min=a[0]{max = a[0];min = a[0];}if(max<a[i])max = a[i];if(min>a[i])min = a[i];sum = sum+a[i];}b = sum-max-min;avg = b/8.0;printf("平均分为:%.2lf\n",avg);//保留两位小数
}
输入10个数交换首尾输出
#include <stdio.h>
int main()
{int i, t, n, maxi = 0, mini = 0, a[10];n = 10;for(i = 0; i < n; i++) {scanf("%d", &a[i]); if(a[i] > a[maxi]) maxi = i;else if(a[i] < a[mini]) mini = i;}printf("最大的数是%d,是第%d个数\n", a[maxi], maxi + 1);//增加功能输出最大数printf("最小的数是%d,是第%d个数\n", a[mini], mini + 1);//增加功能输出最小数//将寻找的最大最小值与开头结束交换t = a[0]; a[0] = a[mini]; a[mini] = t;t = a[n - 1];a[n - 1] = a[maxi];a[maxi] = t;printf("输出交换以后的数组:\n");for(i = 0; i < n; i++) printf("%d ", a[i]);return 0;
}
求三位数各个数之和
1 + 3 + 4 = 8 1+3+4=8 1+3+4=8
#include <stdio.h>
int main()
{int n, s;printf("请输入一个三位数:"); scanf("%d", &n); s = n/100 + n % 100/10 + n % 10; printf("s=%d\n", s);
}
极坐标转直角坐标
x = r . c o s θ x=r.cos\theta x=r.cosθ
y = r . s i n θ y=r.sin\theta y=r.sinθ
#include <stdio.h>
#include <math.h>
#define PI 3.1415926
int main()
{double r, thet, x, y; printf("input:"); scanf("%lf%lf", &r, &thet); x = r*cos(thet*PI/180); y = r*sin(thet*PI/180); printf("x=%f,y=%f\n", x, y);
}
温度转换
C = 5 9 ( f − 32 ) ( 摄氏温度 ) C=\frac {5} {9}(f-32)(摄氏温度) C=95(f−32)(摄氏温度)
K = 273.16 + 7 ( 绝对温度 ) K=273.16+7(绝对温度) K=273.16+7(绝对温度)
#include <stdio.h>
int main()
{double f, c, k; printf("input:"); scanf("%lf", &f); c = 5*(f - 32) /9; k = 273.16 + c; printf("c=%f,k=%f\n", c, k);
}
分段函数
输入x的值,输出y相应的值
y = { x ( x < 1 ) 2 x − 1 ( 1 < = x < 10 ) 3 x − 11 ( x > = 10 ) y= \begin{cases} x & (x<1) \\ 2x−1 & (1<=x<10) \\ 3x−11 & (x>=10) \end{cases} y=⎩ ⎨ ⎧x2x−13x−11(x<1)(1<=x<10)(x>=10)
解题思路: 根据输入的不同x值进行条件判断,不同的条件采用不同的表达式进行计算即可
答案:
#include <stdio.h>
int main()
{int x, y;scanf("%d", &x);if (x < 1) {y = x;}else if (x >= 1 && x < 10) {y = 2 * x - 1;}else {y = 3 * x - 11;}printf("y = %d\n", y);return 0;
}
泰勒级数展开式
e x = 1 + x + x 2 2 ! + x 3 3 ! + … + x n n ! … e^x=1+x+\frac{x^2}{2!} +\frac{x^3}{3!} +…+\frac{x^n}{n!} … ex=1+x+2!x2+3!x3+…+n!xn…
#include <stdio.h>
int main()
{int n, i;double x, t = 1, s = 1;printf("input n,x");scanf("%d%f", &n, &x);for(i = 1 ; i <= n; i++) {t = t*x/i;s += t;} printf("s=%f\n", s);return 0;
}
有穷级数相加
求 ∑ k = 1 100 k + ∑ k = 1 50 k 2 + ∑ k = 1 10 1 k 求\sum\limits_{k=1}^{100}k +\sum\limits_{k=1}^{50}{k}^2 +\sum\limits_{k=1}^{10}{\frac{1}{k}} 求k=1∑100k+k=1∑50k2+k=1∑10k1
1. 对于 ∑ k = 1 100 k 而言,指的是求从 1 到 100 的和。每个数字为整数,求和也为整数 1. 对于 \sum\limits_{k=1}^{100}k 而言,指的是求从1到100的和。每个数字为整数,求和也为整数 1.对于k=1∑100k而言,指的是求从1到100的和。每个数字为整数,求和也为整数
2. 对于 ∑ k = 1 50 k 2 而言,指的是求从 1 2 ⋅ 50 2 的和。每个数字为整数,求和也为整数 2. 对于 \sum\limits_{k=1}^{50}{k}^2而言,指的是求从{{1}^{2·50}}^2的和。每个数字为整数,求和也为整数 2.对于k=1∑50k2而言,指的是求从12⋅502的和。每个数字为整数,求和也为整数
3. 对于 ∑ k = 1 10 1 k 而言,指的是求从 1 1 到 1 10 的和。每个数字不是整数,求和也不是整数 3. 对于 \sum\limits_{k=1}^{10}{\frac{1}{k}} 而言,指的是求从 \frac{1}{1} 到 \frac{1}{10} 的和。每个数字不是整数,求和也不是整数 3.对于k=1∑10k1而言,指的是求从11到101的和。每个数字不是整数,求和也不是整数
该题目,最大的求和是从从1到100,所以需要一个循环,从1遍历到100。针对第一种情况,则遍历100次停下来。针对第二种情况,则遍历50次的时候停下来,针对第三种情况,则遍历10遍就停下来。
最后,在遍历每一个数字的时候,针对三种不同的情况求和。最后将三种不同请求的和加起来就是总体的和
代码示例:
#include <stdio.h>int main()
{int k;double total_sum = 0, sum1 = 0, sum2 = 0, sum3 = 0.0;for (k = 1; k <= 100; k++){sum1 += k;//遍历50次就不在执行情况2if (k <= 50){sum2 += k * k;}//遍历10次就不在执行情况3if (k <= 10){sum3 += 1.0 / k;}}total_sum = sum1 + sum2 + sum3;printf("三种情况求和结果为:%lf\n", total_sum);return 0;
}
打印图形类程序
打印棱形
*********
****************
#include<stdio.h>
int main()
{int space, i, j;for (i = 0; i < 4; ++i) //上半棱形{for (space = 3 - i; space > 0; --space) printf(" ");for (j = 0; j <= 2 * i; ++j) printf("*");printf("\n");}for (i = 3; i > 0; --i) //下半棱形{for (space = 4 - i; space > 0; --space) printf(" ");for (j = 2 * (i - 1); j >= 0; --j) printf("*");printf("\n");} return 0;
}
杨辉三角
题目描述
以下的图形:
11 11 2 11 3 3 11 4 6 4 11 5 10 10 5 11 6 15 20 15 6 11 7 21 35 35 21 7 11 8 28 56 70 56 28 8 11 9 36 84 126 126 84 36 9 1
输入
输入数据包含多个测试实例,每个测试实例的输入只包含一个正整数n(1<=n<=30),表示将要输出的杨辉三角的层数。
输出
对应于每一个输入,请输出相应层数的杨辉三角,每一层的整数之间用一个空格隔开,每一个杨辉三角后面加一个空行。
样例输入
2 3
样例输出
11 11 2 11 3 3 11 4 6 4 11 5 10 10 5 11 6 15 20 15 6 11 7 21 35 35 21 7 11 8 28 56 70 56 28 8 11 9 36 84 126 126 84 36 9 1
【答案解析】
仔细观察杨辉三角可以得到:
第0列和对角线上的数据全部为1,其余位置上的数据为上一行正对数据与上一行正对前一个数据之和。
比如:a[4][2] = a[3][2] + a[3][1]
代码
#include<stdio.h>
int main()
{int array[10][10],i,j;for (i = 0; i < 10;i++){for (j = 0; j <= i; j++){// 对角线和第0列上全部为1if (i == j || 0 == j)array[i][j] = 1;elsearray[i][j] = array[i - 1][j] + array[i - 1][j - 1];}}// 打印杨慧三角的前10行for (i = 0; i < 10; i++){for (j = 0; j <= i; j++){printf("%5d", array[i][j]);}printf("\n");}return 0;
}
打印回文塔
打印如下回文塔
左对齐回文塔>
*
***
*****
*******
*********
#include<stdio.h>
int main(){int i, j, n;scanf("%d", &n);for (i = 1; i <= n; i++) {for (j = 1; j <= 2*i - 1; j++) {printf("*"); }printf("\n");}return 0;
}
右对齐回文塔
****************
*********
#include<stdio.h>
int main(){int i, j, n;scanf("%d", &n);for (i = 1; i <= n; i++) {for (j = 1; j <= 2*(n - i); j++) {printf(" ");}for (j = 1; j <= 2*i - 1; j++) {printf("*"); }printf("\n");}return 0;
}
居中对齐回文塔
****************
*********
#include<stdio.h>
int main(){int i, j, n;scanf("%d", &n);for (i = 1; i <= n; i++) {for (j = 1; j <= n - i; j++) {printf(" ");}for (j = 1; j <= 2*i - 1; j++) {printf("*"); }printf("\n");}return 0;
}
数字回文塔
1121123211234321
123454321
#include<stdio.h>
int main(){int i, j, n;scanf("%d", &n);for (i = 1; i <= n; i++) {for (j = 1; j <= n - i; j++) {printf(" ");}for (j = 1; j <= i; j++) {printf("%d",j); }for (j = i-1; j >= 1; j--) {printf("%d",j); }printf("\n");}return 0;
}
字母回文塔
AABAABCBAABCDCBA
ABCDEDCBA
#include<stdio.h>
int main(){int i, j, n;scanf("%d", &n);for (i = 1; i <= n; i++) {for (j = 1; j <= n - i; j++) {printf(" ");}for (j = 1; j <= i; j++) {printf("%c",j+64); }for (j = i-1; j >= 1; j--) {printf("%c",j+64); }printf("\n");}return 0;
}
字符型类程序
删除字符串某字符
#include <stdio.h>
int main()
{char s[100], *p, *q,del;puts("input:");gets(s);printf("delete char:");scanf("%c",&del);for (p = s, q = s; *p != '\0'; p++)if (*p != del)*q++ = *p;*q = *p;puts(s);return 0;
}
单行统计字符个数
输入一行字符,分别统计出其中英文字母、空格、数字和其他字符的个数
答案解析:
该题可以调用getchar
函数,从stdin
流中读入一个字符,当输入多个字符时,getchar()
再执行时就会直接从缓冲区中读取了。等同于getc(stdin)
。所以,我们循环调用getchar
,直到将标准输入的内容读到换行符\n
为止。同时判断,读取到的字符是英文字母、空格、数字或者其他字符,并计数;
代码示例:
#include <stdio.h>int main()
{char c;//定义eng_char为英文字母的个数,初始值为0//定义space_char为空格字符的个数,初始值为0//定义digit_char为数字字符的个数,初始值为0//定义other_char为其他字符的个数,初始值为0int eng_char = 0, space_char = 0, digit_char = 0, other_char = 0;printf("请输入一行字符:");while ((c = getchar()) != '\n'){if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'){eng_char++;}else if (c == ' '){space_char++;}else if (c >= '0' && c <= '9'){digit_char++;}else{other_char++;}}printf("英文字母数量:%d\n空格数量:%d\n数字数量:%d\n其他字符数量:%d\n", eng_char, space_char, digit_char, other_char);return 0;}
多行统计字符个数
有一篇文章,共有3行文字,每行有80个字符。要求分别统计出其中英文大写字母、小写字母、数字、空格以及其他字符的个数
【答案解析】
获取文章中的3行文本,并对每行文本进行以下操作
- 定义保存结果变量:upp、low、digit、space、other
- 遍历每行文本中的字符
- 如果该字符
ch
:ch >= ‘a’ && ch <=‘z’
,则该字符是小写字母,给low++
- 如果该字符
ch
:ch >= ‘A’ && ch <=‘Z’
,则该字符是小写字母,给up++
- 如果该字符
ch
:ch >= ‘0’ && ch <=‘9’
,则该字符是小写字母,给digit++
- 如果该字符
ch
:ch == ’ '
,则该字符是小写字母,给space++
- 否则为其他字符,给
other++
输入统计结果
【代码实现】
#include <stdio.h>
int main()
{int i,upp = 0, low = 0, digit = 0, space = 0, other = 0;char text[3][80];for (i=0; i<3; i++){// 获取一行文本printf("please input line %d:\n",i+1);gets(text[i]);// 统计该行文本中小写字母、大写字母、数字、空格、其他字符的个数for (int j=0; j<80 && text[i][j]!='\0'; j++){if (text[i][j]>='A'&& text[i][j]<='Z') // 大写字母upp++;else if (text[i][j]>='a' && text[i][j]<='z') // 小写字母low++;else if (text[i][j]>='0' && text[i][j]<='9') // 数字digit++;else if (text[i][j]==' ') // 控制space++;elseother++; // 其他字符}}printf("\nupper case: %d\n", upp);printf("lower case: %d\n", low);printf("digit : %d\n", digit);printf("space : %d\n", space);printf("other : %d\n", other);return 0;}
将一行电文译成密码
按下面规律译成密码
A--->Z a--->z
B--->Y b--->Y
C--->X c--->x
……
即第1个字母编程第26个字母,第i个字母编程第(26-i+1)个字母,非字母字符不变,要求编程序将密码译回原文,并输出密码和原文。
【答案解析】
从题目给的实例中可以看到,编码规则非常简单,就是将从前往后数的第i个字母转化为从后往前数的第i个字母。
那解压时直接反过来转换即可:
即’Z’—>‘A’ ‘z’—>‘a’
‘Y’—>‘B’ ‘y’—>‘b’
‘X’—>‘C’ ‘x’—>‘c’
假设如果当前拿到的是小写字母,转换方式如下:
- 先用
s[i] - 'a’
计算出s[i]
是26个字母中从前往后数的第几个 - 再用
26 - (s[i]- ‘a’) - 1
转换为26个字母中从后往前数的第几个 - 在2的结果上加上
’a’
,即转换为对应从后往前的第几个字母
大写字母转换方式与上述相同,将上述每条中的’a’换为‘A’即可。
【代码实现】
#include<stdio.h>
int main()
{char s[1024] = {0};scanf("%s", s);int i,len = strlen(s);// 转换for (i = 0; i < len; ++i){// 如果是小写字母(大写字母出来类似):// 1. 先用s[i] - 'a'计算出s[i]是26个字母中从前往后数的第几个// 2. 再用26 - (s[i]- 'a') - 1 转换为26个字母中从后往前数的第几个// 3. 在2的结果上加上'a',即转换为对应从后往前的第几个字母if (s[i] >= 'a' && s[i] <= 'z')s[i] = 'a' + 26 - (s[i]-'a')-1;else if (s[i] >= 'A' && s[i] <= 'Z')s[i] = 'A' + 26 - (s[i] - 'A')-1;}printf("%s", s);return 0;
}
不使用函数连接字符串
【答案解析】
直接将s2中的字符逐个拷贝到s1的末尾即可,用户需要保证s1中能存的下s2中的字符
- 获取s1末尾的位置
- 将s2中的字符逐个拷贝到s1中
【代码实现】
1)字符串方式
#include <stdio.h>
main(){int i,j; char s1[20]="abcd";char s2[20]="1234";for(i = 0; s1[i] != '\0'; ++i); /*移动到s1尾*/for(j = 0; s2[j] != '\0'; ++j, ++i){s1[i] = s2[j];//将s2接到s1末}s1[i] = '\0';//拼接完成,手动为s1末添上结束标记printf("连接后: %s", s1);return 0;
}
2)指针方式
#include <stdio.h>int main()
{char str1[20]="abcd", str2[20]="1234", *p = str1,n = 0;while (*p++ != '\0');/*移动指针到str1尾*/--p;//回退一个单元,以便覆盖str1末的'\0p;//回退一个单元,以便覆盖str1末的'\0'while (str2[n] != '\0'){*p++ = str2[n];//将str2接到str1末++n;};*p = '\0';//拼接完成,手动为str1末添上结束标记printf("结果为:\n%s\n\n",str1);return 0;
}
不使用函数比较字符串
写一函数,实现两个字符串的比较。即自己写一个strcmp函数,函数原型为int strcmp(char * p1 ,char * p2); 设p1指向字符串s1, p2指向字符串s2。要求当s1=s2时,返回值为0;若s1≠s2,返回它们二者第1个不同字符的ASCII码差值(如"BOY"与"BAD" ,第2个字母不同,0与A之差为79- 65=14)。如果s1>s2,则输出正值;如果s1<s2,则输出负值。
【答案解析】
使用两个指针指向两个字符串首部,逐个往后进行比较,不相等的时候则将数据进行相减,作为返回值。
【代码实现】
#include<stdio.h>
#include<string.h>int mystrcmp(char *str1, char *str2)
{char *ptr1 = str1;char *ptr2 = str2;int res;while (*ptr1 != '\0' && *ptr2 != '\0') {if (*ptr1 != *ptr2) {res = *ptr1 - *ptr2;break;}ptr1++;ptr2++;}if (*ptr1 == '\0' || *ptr2 == '\0') {//注意一个字符串到达结尾或者两个都到达结尾的情况res = *ptr1 - *ptr2;}return res;
}
int main()
{char buf1[1024] = { 0 };char buf2[1024] = { 0 };while (1) {printf("Please enter two strings:\n");gets_s(buf1, 1024);gets_s(buf2, 1024);printf("mystrcmp:%d", mystrcmp(buf1, buf2));printf("\n");}return 0;
}
不使用函数复制字符串
编写一个程序,将字符数组s2中的全部字符复制到字符数组s1中,不用strcpy函数。复制时,‘\0’也要赋值过去。’\0’之后的字符不复制。
【答案解析】
首先必须保证s1能否放的下s2中的字符,然后将s2中的每个字符逐个搬移到s1中即可。
【代码实现】
#include<stdio.h>int main()
{char s1[100] = { 0 };char s2[50] = { 0 };int index1 = 0, index2 = 0;printf("请输入字符串s2:");scanf("%s", s2);printf("将s2拷贝到s1中, s1现在为: ");// 将s2[index2]位置字符拷贝到s1[index]位置,// 然后以s1[index1]的值作为循环条件判断是否拷贝到s2的末尾while (s1[index1++] = s2[index2++]);printf("%s\n", s1);return 0;
}
将两字符串中的字符比较并输出
编写一个程序,将两个字符串s1和s2比较,如果s1 > s2
,输出一个整数;若s1 = s2
,输出0;若s1 < s2
,输出一个负数。不要用strcpy()
函数。两个字符串用gets函数读入。输出的正数或负数的绝对值应是相比较的两个字符串相对应字符的ASCII码的差值。例如,“A"和“C”相比,由于"A” < “C”,应输出负数,同时由于‘A’与‘C’的ASCII码差值为2,因此应输出"-2"。同理:“And”和"Aid"相比较,根据第2个字符比较结果,“n"比"i"大5,因此应输出"5”。
【答案解析】
字符串比较规则:从前往后逐个字符进行比较,相等时继续往后,不相等时返回该位置两个字符差值。
【代码实现】
#include <stdio.h>int main()
{int ret = 0;int index = 0;char s1[100] = { 0 };char s2[100] = { 0 };printf("请输入s1:");gets(s1);printf("请输入s2:");gets(s2);// 将s1和s2中的字符从前往后逐个进行比较,相等继续往后,// 不相等时ret中结果不为0,!ret则为0 循环结束// 如果一个走到末尾,一个未走到末尾 ret也不为0, !ret为0,循环结束// 如果两个字符串相等,同时达到末尾,循环结束while (!(ret = s1[index] - s2[index]) && '\0' != s1[index] && '\0' != s2[index]){++index;}printf("%d\n", ret);return 0;
}
求一个字符串的长度
写一函数,求一个字符串的长度。在main函数中输入字符串,并输出其长度。
解题思路: 字符串以\0作为结尾,则从第一个字符开始向后移动遇到\0认为字符串结束。
答案:
#include <stdio.h>
int mystrlen(char *str)
{int len = 0;char *ptr = str;while (*ptr != '\0') {ptr++;len++;}return len;
}
int main()
{char buf[1024];printf("Please enter a string: ");scanf("%s", buf, 1024);printf("string len:%d\n", mystrlen(buf));return 0;
}
字符串排序
解题思路: 排序方式与数字比较大致相同,先遍历比较找出最大的字符串,与第一个字符串进行交换,然后剩下的进行比较找出最大的字符串与第二个交换…
#include<stdio.h>
#include<string.h>
void sort(char s[10][32])
{int i, j;for (i = 0; i < 10; i++){for (j = i; j < 10; j++){if (strcmp(s[i], s[j])> 0){char tmp[32];strcpy(tmp, 32, s[i]);strcpy(s[i], 32, s[j]);strcpy(s[j], 32, tmp);}}}
}
int main()
{char str[10][32];printf("Please enter ten strings:\n");for (int i = 0; i < 10; i++){scanf("%s", str[i], 32);}sort(str);printf("\n");for (int i = 0; i < 10; i++){printf("%s\n", str[i]);}return 0;
}
用指针数组处理
#include<stdio.h>
#include<string.h>void change(int n, char* strings[]) {char* temp;int i, j;for (i = 0; i < n; i++) {for (j = i + 1; j < n; j++) {if (strcmp(strings[i], strings[j])>0) {temp = strings[i];strings[i] = strings[j];strings[j] = temp;}}}
}int main() {int n;int i;char** p;char* strings[] = { "C", "C++", "JAVA", "C#", "GO" };n = sizeof(strings) / sizeof(strings[0]);printf("排序前的数组为:");for (i = 0; i < n; i++) {printf("%s ", strings[i]);}printf("\n");change(n, strings);printf("排序后的数组为:");for (i = 0; i < n; i++) {printf("%s ", strings[i]);}printf("\n");return 0;
}
统计字符串中出现最多次的小写字母
#include <stdio.h>
main()
{char ch, c[20]={0};int i, max=0;while ((ch = getchar()) != '\n')//输入字符串 if (ch >= 'a' && ch <= 'z')c[ch - 'a']++;for (i = 0; i < 20; i++)//将出现次数最多的下标赋值给maxif(c[i] > max)max = c[i];for (i = 0; i < 20; i++)if (max == c[i]){printf("出现最多的小写字母:%c 总数:%d", 'a' + i,max);break;//如果遇到 aaa bbb 则输出第一个出现最多的小写字母 }return 0;
}
统计字符串是元音(A E I O U)的个数
输入一个字符串,统计字符串是元音(A E I O U)的个数;通过switch-case来实现
#include <stdio.h>
int main()
{char str[20];int i, n, j = 0;printf("请随意输入一段字符串:");gets(str);for (i = 0; i < 20; i++){switch (str[i]){case 'a':case 'o':case 'e':case 'i':case 'u':case 'A':case 'O':case 'E':case 'I':case 'U':j++;break;}}printf("元音数是:%d",j);return 0;
}
数字字符串转整数
#include <stdio.h> // 把一个数字字符串转换为一个整数。
int main()
{char* numStr = "4562";int value=0;while( *numStr >= '0' && *numStr <= '9' ){ // 逐个把字符串的字符转换为数字。value *= 10;value += *numStr - '0';numStr++;}printf("%d\n",value); return 0;
}
时间类程序
##判断年龄大小
输入出生日期和目前日期判断年龄大小
#include <stdio.h>
int main()
{ int year, year1, month, month1, day, day1, age;printf("请输入您的生日:");scanf("%d%d%d", &year, &month, &day);printf("请输入当前日期:");scanf("%d%d%d", &year1, &month1, &day1);if(year1 == year) age = 0;else{age = year1 - year;if(month1 < month||(month1 == month&&day1 < day)) age = age - 1;}printf("您的年龄是:%d", age);
}
输入月份号,输出该月的英文月名
编一程序,输入月份号,输出该月的英文月名。例如,输人3,则输出"March" ,要求用指针数组处理。
解题思路: 首先定义字符串指针数字,数组中每一个元素都存放一个字符串指针,每个指针指向不同字符串的位置。则输入月份数字后,根据下标获取对应月份字符串的地址即可
答案:
#include<stdio.h>
int main()
{int month;char* Month[12] = { "January","February","March","April","May","June","July","August","September","October","November","December" };while (1) {printf("Please enter the month: ");scanf("%d", &month);if (month < 1 && month>12) {printf("Input error, Month should be greater than 0 and less than 12\n");}printf("%s\n", Month[month - 1]);}return 0;
}
输入某年某月某日在本年中是第几天
1.首先明确我国的月份和天数之间的关系:
- 规定
1
,3
,5
,7
,8
,10
,12
月每月31天 - 规定
4
,6
,9
,11
月每月30天 - 2月特别(如果是闰年29天,如果是平年28天)
2.看清题目要求什么
1)只求给定年份这一年有多少天(例如2021年这一天有多少天
)
思路分析:
那么我们可以直接转化为 判断这一年是闰年还是平年 这一问题
题目举例:从屏幕输入一个年份(要求该年份为从1980年后的某一年),并输出该年总共有多少天,如果输入的年份早于或等于 1980年则提示无效的输入。(闰年为366天,平年为365天,能被4整除但不能被100整除的年份或者能被400整除的年份是闰年。)
2)给定一个准确日期 求这一年的这一个月有多少天?
思路分析:
首先开始判断这一年是否是闰年(立flag),主要用 if else if 来判断月份 将2月份单独挑出来判断
3)输入一个日期 ,求这是这一年的第几天?
思路分析:
先来一个判断是否为闰年,因为求第几天肯定有不同的年份,需要不断将每个月的天数加起来(来一个for循环解决),将每月的天数放在一个数组当中,再将2月单独挑出来修改
#include <stdio.h>
main()
{struct date{int y;int m;int d;};struct date dt;int i, count, mon[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};printf("请输入年 月 日:");scanf("%d%d%d", &dt.y, &dt.m, &dt.d);count = dt.d;for (i = 0; i < dt.m; i++)//累加天数 {count += mon[i];}//判断是否为闰年,闰年+1天数;如果是闰年且月份大于2,总天数应该加一天if (dt.m > 2 && (dt.y % 4 == 0 && dt.y % 100 != 0 || dt.y % 400 == 0)){count += 1;}printf("这一日是这一年的第%d天\n", count);return 0;
}
写一个函数days,实现第上面的计算
#include <stdio.h>struct Date{int year;int month;int day;
};int Days(struct Date date)
{static int Days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };int i, days = 0;for (i = 1; i < date.month; i++)days += Days[i];days += date.day;//如果包含闰年的二月,天数加1if (date.month > 2){if (date.year % 400 == 0 || (date.year % 4 == 0 && date.year % 100 != 0)){++days;}}return days;
}int main(){struct Date date;printf("请输入年 月 日: ");scanf("%d%d%d", &date.year, &date.month, &date.day);int days = Days(date);printf("It's day %d in the year.\n", days);return 0;
}
数组类程序
求一个3 X 3的整形矩阵对角线元素之和
【答案解析】
矩阵:即二维数组,矩阵行和列相等的二维数组称为方阵。
1 2 3
4 5 6
7 8 9
左上角到右下角对角线上数字:行下标和列下标相等
右上角到左下角对角线上数字:列下标减1 行下标加一
通过两个循环来取到对角线上的元素,并对其求和即可。
【代码实现】
#include<stdio.h>
int main()
{int i,array[3][3];int sumLT2RB = 0; // 标记左上角到右下角对角线元素之和int sumRT2LB = 0; // 标记右上角到左下角对角线元素之和printf("请输入3行3列的矩阵:\n");for (i = 0; i < 3; ++i){for (int j = 0; j < 3; ++j)scanf("%d", &array[i][j]);}// 左上角到右下角对角线for (i = 0; i < 3; ++i)sumLT2RB += array[i][i];for (i = 0, j = 2; i < 3; ++i, j--)sumRT2LB += array[i][j];printf("左上角到右下角对角线元素之和: %d\n", sumLT2RB);printf("右上角到左下角对角线元素之和: %d\n", sumRT2LB);return 0;
}
数组的逆置
将一个数组中的值按逆序重新存放。例如:原来顺序为8,6,5,4,1。要求改为1,4,5,6,8。
【答案解析】
该题为数组的逆置,具体处理方式如下:
如果begin < end
时,则循环进行一下操作
- 给定两个下标
begin
和end
,begin
放在数组起始的位置,end
放在数组最后一个元素的位置 - 交换
begin
和end
位置的元素 begin
往后移动,end
往前移动
#include<stdio.h>
int main()
{int i,array[5] = {8,6,5,4,1};int begin = 0, end = 4;printf("逆序之前数组为:");for (i = 0; i < 5; ++i)printf("%d ", array[i]);printf("\n");// 逆序:begin在数组最左侧,end在数组最右侧// 只要begin < end,将begin和end位置元素进行交换// 然后begin往后移动一步,end往前移动一步while (begin < end){int temp = array[begin];array[begin] = array[end];array[end] = temp;begin++;end--;}printf("逆置之后数组为:");for (i = 0; i < 5; ++i)printf("%d ", array[i]);printf("\n");return 0;
}
输出"魔方阵"
所谓魔方阵是指这样的方阵,它的每一行、每一列和对角线之和均相等。例如:
8 1 6 3 5 7 4 9 2
要求输出1~ n 2 n^2 n2的自然数构成的魔方阵。
【答案解析】
| 17 | 24 | 1 | 8 | 15 | -------------------------- | 23 | 5 | 7 | 14 | 16 | -------------------------- | 4 | 6 | 13 | 20 | 22 | -------------------------- | 10 | 12 | 19 | 21 | 3 | -------------------------- | 11 | 18 | 25 | 2 | 9 |
上述矩阵,可以看到以下规律:
魔方阵的生成方法为:在第 0 行中间置 1 ,对从 2 开始的其余 n 2 − 1 个数依次按下列规则存放: 魔方阵的生成方法为:在第0行中间置1,对从2开始的其余n^2-1个数依次按下列规则存放: 魔方阵的生成方法为:在第0行中间置1,对从2开始的其余n2−1个数依次按下列规则存放:
- 将1放在第1行的中间一列。
- 从2开始直到
n*n
止,各数依次按此规律存放:每一个数存放的行比前一个数的行数减1,列数加1。 - 如果上一行的行数为1,则下一个数的行数为n(指最下一行)。
- 当上一个数的列数为n时,下一个数的列数应该为1。
- 如果按上面规律确定的位置有数,或者上一个数是第1行第n列时,则把下一个数放在上一个数的下面。
【代码实现】
#include <stdio.h>
int main()
{int a[15][15], n, i, j, k;while (1){printf("请输入n(1~15):");scanf("%d", &n);if (n != 0 && n <= 15 && n % 2 != 0)break;else{printf("请输入奇数\n");}}for (i = 1; i <= n; i++){for (j = 1; j <= n; j++)a[i][j] = 0;}j = n / 2 + 1;a[1][j] = 1;i = 1;for (k = 2; k <= n*n; k++){i -= 1;j += 1;if (i<1 && j>n){i += 2;j -= 1;}else if (i<1){i = n;}else if (j>n){j = 1;}if (a[i][j] == 0){a[i][j] = k;}else{i += 2;j -= 1;a[i][j] = k;}}for (i = 1; i <= n; i++){for (j = 1; j <= n; j++)printf("%5d", a[i][j]);printf("\n");}return 0;
}
矩阵转置
【答案解析】
进行数组的行列互换,其关键在于数组互换的表达式 ar[i] [j] = ar[j] [i];
其次在循环的时候,内层循环不能到达最大列,需要根据此时是第几行的交换来决定循环的次数,否则有可能数组行列交换之后最后又交换回原来的形状了。
Example Input
2 3
1 2 3
4 5 6
Example Output
1 4
2 5
3 6
【代码实现】
#include<stdio.h>int main(){int n,m,i,j;printf("Example Input\n");scanf("%d %d",&n,&m);int num[n][m];int num1[m][n];for(i=0;i<n;i++){for(j=0;j<m;j++){scanf("%d",&num[i][j]); //输入}}for(i=0;i<m;i++){for(j=0;j<n;j++){num1[i][j]=num[j][i]; //转换}}printf("Example Output\n");for(i=0;i<m;i++){for(j=0;j<n;j++){printf("%d ",num1[i][j]); //输出}printf("\n"); }return 0;
}
输入6个整数,按对称矩阵排列
#include <stdio.h>
int main()
{int n,i,j,k,a[6] = {};printf("请输入6个整数\n");for ( n = 0; n < 6; n++){scanf("%d",&a[n]);}for (i = 0; i < 6; i++) { //结果for (k = 6 - i; k < 6; k++) //i=0 a[k]=0 a[j]=1 2 3 4 5 6 1 2 3 4 5 6printf("%d ", a[k]); //i=1 a[k]=6 a[j]=1 2 3 4 5 6 1 2 3 4 5for (j = 0; j < 6 - i; j++) //i=2 a[k]=5 6 a[j]= 1 2 3 4 5 6 1 2 3 4printf("%d ", a[j]); // …… 4 5 6 1 2 3printf("\n"); // …… 3 4 5 6 1 2} //i=5 a[k]=2 3 4 5 6 a[j]= 1 2 3 4 5 6 1return 0;
}
鞍点数(马鞍数)
请编程找出一个M*N矩阵中的鞍点,即该位置上的元素是该行上的最大值,是该列上的最小值。如果矩阵中没有鞍点,则输出“没有鞍点!”
#include<stdio.h>
#define M 3
#define N 3
int main()
{int m, n;printf("输入行数和列数:");scanf("%d %d", &m, &n);int i, j, max, maxj, k, flag = 0;int a[M][N] = { 0 };printf("请输入数组:");for (i = 0; i < m; i++) {for (j = 0; j < n; j++) scanf("%d", &a[i][j]);}printf("\n");for (i = 0; i < m; i++) {max = a[i][0];maxj = 0;for (j = 0; j < n; j++) {if (a[i][j] > max) {max = a[i][j];maxj = j;}}flag = 1;for (k = 0; k < m; k++) {if (max > a[k][maxj]) flag = 0;continue;}if (flag) {printf("存在鞍点a[%d][%d]=%d", i, maxj, max);break;}}if (!flag) printf("没有鞍点");printf("\n");return 0;
}
结构体类程序
编写一个函数print
编写一个函数print,打印一个学生的成绩数组,该数组中有5个学生的数据记录,每个记录包括num,name,score[3],用主函数输人这些记录,用print函数输出这些记录。
#include <stdio.h>#define NAMLEN 20
//定义一个student结构体数组,包含5个元素
struct student_t{int num;char name[NAMLEN];int score[3];
} students[5];void print(struct student_t *stu);int main(){int i;for (i = 0; i < 5; i++){scanf("%d%s%d%d%d", &students[i].num, students[i].name, &students[i].score[0],&students[i].score[1], &students[i].score[2]);}print(students);return 0;
}void print(struct student_t *stu){int i;for (i = 0; i < 5; i++){printf("%d %s %d %d %d\n", students[i].num, students[i].name, students[i].score[0],students[i].score[1], students[i].score[2]);}
}
有10个学生输入……
有10个学生,每个学生的数据包括学号、姓名、3门课程的成绩,从键盘输人10个学生数据,要求输出3门课程总平均成绩,以及最高分的学生的数据(包括学号、姓名、3门课程成绩、平均分数)。
#include <stdio.h>#define NAMLEN 20
#define STUCNT 10typedef struct student_t{int num;char name[NAMLEN];int score[3];
} student;int main(){student students[STUCNT];int i,maxi = 0, maxsum = 0;double aver_0 = 0, aver_1 = 0, aver_2 = 0;for (i = 0; i < STUCNT; i++){scanf("%d%s%d%d%d", &students[i].num, students[i].name, &students[i].score[0], &students[i].score[1], &students[i].score[2]);int sum = students[i].score[0] + students[i].score[1] + students[i].score[2];if (sum > maxsum){maxsum = sum;maxi = i;}aver_0 += students[i].score[0];aver_1 += students[i].score[1];aver_2 += students[i].score[2];}aver_0 /= STUCNT;aver_1 /= STUCNT;aver_2 /= STUCNT;printf("%lf %lf %lf\n", aver_0, aver_1, aver_2);printf("%d %s %d %d %d %lf\n", students[maxi].num, students[maxi].name, students[maxi].score[0], students[maxi].score[1], students[maxi].score[2],(students[maxi].score[0] + students[maxi].score[1] + students[maxi].score[2]) / 3.0);return 0;
}
约瑟夫环问题(三种方法)
经典问题约瑟夫环:有n个人围成一圈,第一个人从1开始报数,报m的人将被淘汰出圈,下一个人接着从1开始报。如此反复,直到最后留下一个胜利者
【答案解析】
每个人的编号存放在一个数组 a 中,主函数中决定人数的个数以及报数的上限值 m,设计一个函数实现对应的操作。函数的形参有整型数组 a、整数 n 和 m,n 用来接收传递的人数,m 用来接收报数上限,函数的返回值为空;函数体中输出出列人的顺序。
函数中利用循环访问数组中 n 个元素,每次访问元素,设定内循环连续访问 m 个元素,元素访问的下标为 k,访问到第 m 个元素时,如果元素不是 0,此时输出元素 a[k],再设定 a[k] 为 0,继续访问后面的元素。
主函数中设定数组 a,从键盘输入 n 和 m,利用循环产生 n 的位置序号存放到数组 a 中,调用函数实现相应的操作。
【代码实现】
#include <stdio.h>
#define NUM 13
typedef struct people
{int num;struct people *next;
} people;int main()
{int count = NUM;people p[NUM];people *head;head = p; //head 指向p[0]//1~13编号for (int i = 0; i < NUM; i++){head->num = i + 1;head->next = &p[i + 1];head = head->next;}//最后一个元素指向第一个元素 , 形成环p[NUM - 1].next = p; int i = 1;head = p;while (count > 1){//跳过已经被淘汰的节点if (head->num == 0){head = head->next;continue;}if (i == 3){//被淘汰的节点,num置为0printf("第 %d 位置被淘汰\n", head->num);head->num = 0;count--;}head = head->next;i++;if (i > 3){i = 1;}}printf("--------------\n");while (head->num == 0){//非0节点即为最后留下的head = head->next;if (head->num != 0){printf("留到最后的是 %d \n", head->num);}}return 0;
}
数组方式
#include <stdio.h>
#define N 100
int josef(int a[],int n,int m)
{int i,j,k=0;for(i=0;i<n;i++){j=1;while(j<m){while(a[k]==0)k=(k+1)%n;j++;k=(k+1)%n;}while(a[k]==0)k=(k+1)%n;printf("%d ",a[k]);a[k]=0;}return 0;
}int main()
{int a[100];int i,j,m,n;printf("input n and m:");scanf("%d%d",&n,&m);for(i=0;i<n;i++)a[i]=i+1;printf("\n output:\n");josef(a,n,m);printf("\n");return 0;
}
指针方法
#include <stdio.h>
int main()
{int people[128], n;printf("Please input how many people: ");scanf_s("%d", &n);for (int i = 0; i < n; i++) {people[i] = i + 1; //对每个人顺序排号}int remain = n;int num_off = 0;int *p = NULL;while (remain > 1) {p = people;while (p != people + n) { // 每次从第一个位置开始,直到最后一个位置,报数是一直递增的if ((*p) != 0) {//若这个位置人还在num_off++; //则报数if (num_off == 3) {//否则当前的人即将要报的数字是3*p = 0; //则剔除这个人num_off = 0; //并且重新开始计数,下边会++,所以是从1开始报数remain--;//剩余人数-1}}p++;}}for (int i = 0; i < n; i++) {if (people[i] != 0) {printf("Serial number of the remaining person:%d\n", people[i]);}}printf("\n");system("pause");return 0;
}
链表类程序
删除动态链表中指定节点
写一个函数del,用来删除动态链表中指定的节点
解题思路及答案:
首先创建一个带头的单链表,然后让用户输入需要删除的节点,调用del函数,找到需要删除的节点,把待删除节点的前驱和后继重新链接。
#include <stdio.h>
#include <stdlib.h>typedef struct LNode
{int num;struct LNode *next;
} LNode;//创建含有n个值的节点
LNode* creat(int n)
{LNode *head, *p;head = (LNode *)malloc(sizeof(LNode));p = head; //头节点为0 加上头节点共n + 1个节点head->num = 0;head->next = NULL;for (int i = 1; i <= n; i++){LNode *newNode = (LNode *)malloc(sizeof(LNode));newNode->num = i;newNode->next = NULL;p->next = newNode;p = p->next;}return head;
}//删除值为n的节点
void del(int n, LNode *head)
{LNode *pre, *current;pre = head;current = head->next;//从第一个有效节点开始查找待删除节点printf("delete node %d\n", n);while (current != NULL){//找到待删除节点,重新链接,释放待删除节点if (current->num == n){pre->next = current->next;free(current);break;}//更新查找位置pre = current;current = current->next;}
}int main()
{LNode *head, *p;int n;head = creat(10);printf("请输入需要删除的节点:1-10\n");scanf("%d", &n);del(n, head);int i = 1;p = head->next;while (p != NULL){printf("p %d.num -> %d\n", i, p->num);p = p->next;i++;}return 0;
}
动态链表插入结点
写一个函数insert,用来向一个动态链表插入结点
#include <stdio.h>
#include <stdlib.h>typedef struct LNode
{int num;struct LNode *next;
} LNode;void insert(int n, LNode *node)
{//创建新节点LNode *newNode = (LNode *)malloc(sizeof(LNode));newNode->num = n;LNode* next = node->next;// node ---> newNode ---> nextnewNode->next = next;node->next = newNode;
}LNode* creat(int n)
{LNode *head, *p;head = (LNode *)malloc(sizeof(LNode));p = head; //头节点为0 加上头节点共11个节点head->num = 0;head->next = NULL;for (int i = 1; i <= n; i++){LNode *newNode = (LNode *)malloc(sizeof(LNode));newNode->num = i;newNode->next = NULL;p->next = newNode;p = p->next;}return head;
}void printNode(LNode* head)
{LNode* p = head->next;while (p != NULL){printf("num -> %d\n", p->num);p = p->next;}
}int main()
{LNode *head;int n;head = creat(10);printNode(head);printf("请输入需要插入的节点:\n");scanf("%d", &n);insert(n, head);printf("链表的新内容:\n");printNode(head);return 0;
}
链表排序
已有a,b两个链表,每个链表中的结点包括学号、成绩。要求把两个链表合并, 按学号升序排列
解题思路及答案:
首先合并两个链表,然后采用选择排序,给合并之后的链表进行排序。
#include <stdio.h>
typedef struct student
{int num;double grade;struct student *next;
} student;student *merge(student *a, student *b)
{//先合并,后排序student *head = a;while (a->next != NULL){a = a->next;}a->next = b;//选择排序,每次选最小的,放在未排序的链表头部student *pre;pre = head;while (pre->next != NULL){a = pre->next;while (a != NULL){if (pre->num > a->num){int num = pre->num;double grade = pre->grade;pre->num = a->num;pre->grade = a->grade;a->num = num;a->grade = grade;}a = a->next;}pre = pre->next;}return head;
}
int main()
{student a[3] = {{1, 79}, {4, 36}, {5, 79}};for (int i = 0; i < 2; i++){a[i].next = &a[i + 1];}student b[2] = {{2, 38}, {6, 98}};for (int i = 0; i < 1; i++){b[i].next = &b[i + 1];}student *combine = merge(a, b);while (combine != NULL){printf("%d -> %.2lf\n", combine->num, combine->grade);combine = combine->next;}return 0;
}
查找删除节点
有两个链表a和b,设结点中包含学号、姓名。从a链表中删去与b链表中有相同学号的那些结点。
解题思路及答案:
对于b链表中的每一个节点,都从a链表的表头开始查找,如果可以找到,直接删除,如果找不到,继续从a链表表头找下一个b的节点。
#include <stdio.h>
typedef struct student
{int num;double grade;struct student *next;
} student;
student *del(student *a, student *b)
{student *pre, *current, *head;head = a;while (b != NULL){//重置指针指向a链表的头部pre = head;current = head->next;//a 链表的头等于bif (pre->num == b->num){pre->next = NULL;pre = current;current = current->next;//更新表头head = pre;}else{while (pre->next != NULL){if (current->num == b->num){//找到就删除pre->next = current->next;break;}else{//否则继续遍历pre = pre->next;current = current->next;}}}b = b->next;}return head;
}void printList(student *root)
{printf("----\n");int i = 0;while (root != NULL){printf("student %d -> %d -> %.2lf\n", i, root->num, root->grade);root = root->next;i++;}
}int main()
{student a[3] = { { 1, 79 }, { 4, 36 }, { 5, 79 } };for (int i = 0; i < 2; i++){a[i].next = &a[i + 1];}a[2].next = NULL;printf("链表a:\n");printList(&a[0]);student b[2] = { { 5, 38 }, { 4, 98 } };for (int i = 0; i < 1; i++){b[i].next = &b[i + 1];}b[1].next = NULL;printf("链表b:\n");printList(&b[0]);student *combine = del(a, b);printf("删除之后:\n");while (combine != NULL){printf("%d -> %.2lf\n", combine->num, combine->grade);combine = combine->next;}return 0;
}
按年龄删除节点
建立一个链表,每个结点包括:学号、姓名、性别、年龄。输入一个年龄,如果链表中的结点所包含的年龄等于此年龄,则将此结点删去
#include <stdio.h>
#include <stdio.h>
typedef struct student
{int num;char sex[10];char name[100];int age;struct student *next;
} student;void printList(student *root)
{printf("----\n");while (root != NULL){printf("num:%d, sex: %s, name: %s, age: %d\n", root->num, root->sex, root->name, root->age);root = root->next;}
}int main()
{student a[] = { { 1, "woman", "apple", 12 }, { 4, "woman", "banbana", 36 }, { 5, "man", "candy", 79 }, { 5, "man", "danny", 36 }, { 4, "man", "enjoy", 98 } };for (int i = 0; i < 4; i++){a[i].next = &a[i + 1];}a[4].next = NULL;printList(&a[0]);int n;printf("请输入要删除的年龄:\n");scanf("%d", &n);student *pre = a, *current = a->next, *head;head = a;while (current != NULL){//如果头结点需要删除,则更新头结点if (head->age == n){pre->next = NULL;pre = current;current = current->next;head = pre;}else{//删除节点,重新链接if (current->age == n){pre->next = current->next;}pre = current;current = current->next;}}printList(head);return 0;
}
排序算法程序
1 、排序算法分类
常见排序算法可以分为两大类:
- 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。
- 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。
2、 算法复杂度
3、相关概念
- 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
- 不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
- 时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
- 空间复杂度:是指算法在计算机
内执行时所需存储空间的度量,它也是数据规模n的函数。
冒泡排序(Bubble Sort)
冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
1.1 算法描述
- 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
- 针对所有的元素重复以上的步骤,除了最后一个;
- 重复步骤1~3,直到排序完成。
1.2 动图演示
1.3 代码实现
//冒泡排序算法
/*第一轮 排序过程
3 2 4 1 (最初)
2 3 4 2 (比较3和2,交换)
2 3 4 1 (比较3和4,不交换)
2 3 1 4 (比较4和1,交换)
第一轮结束,最大的数字 4 已经在最后面,因此第二轮排序只需要对前面三个数进行比较。第二轮 排序过程
2 3 1 4 (第一轮排序结果)
2 3 1 4 (比较2和3,不交换)
2 1 3 4 (比较3和1,交换)
第二轮结束,次大的数字 3 已经排在倒数第二个位置,所以第三轮只需要比较前两个元素。第三轮 排序过程
2 1 3 4 (第二轮排序结果)
1 2 3 4 (比较2和1,交换)
*/
#include <stdio.h>
int main()
{int num[10] = {4, 5, 2, 10, 7, 1, 8, 3, 6, 9};int i, j, temp;//冒泡排序算法:进行 n-1 轮比较for (i = 0; i < 10 - 1; i++){//每一轮比较前 n-1-i 个,已经排序好的最后 i 个不用比较//对拥有 n 个元素的数组 R[n] 进行 n-1 轮比较。for (j = 0; j < 10 - 1 - i; j++){if (num[j] > num[j + 1]){temp = num[j];num[j] = num[j + 1];num[j + 1] = temp;}}}//输出排序后的数组for (i = 0; i < 10; i++){printf("%d ", num[i]);}printf("\n");return 0;
}
//整个数组从小到大排序:1 2 3 4 5 6 7 8 9 10
选择排序(Selection Sort)
选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
2.1 算法描述
n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。具体算法描述如下:
- 初始状态:无序区为R[1…n],有序区为空;
- 第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1…i-1]和R(i…n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1…i]和R[i+1…n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;
- n-1趟结束,数组有序化了。
2.2 动图演示
2.3 代码实现
//选择排序
#include <stdio.h>
int main()
{int i, j, min, temp, a[10] = {9, 8, 7, 4, 5, 6, 3, 2, 1, 10};for (i = 0; i < 10 - 1; i++){min = i; //min:当前最小值下标for (j = i + 1; j < 10; j++) //扫描余下的部分if (a[min] > a[j]) //若有其它元素更小,就记录其下标min = j;if (min != i){ //保若最小值不在排序区首位,就换到首位temp = a[min];a[min] = a[i];a[i] = temp;}}for (i = 0; i < 10; i++) //输出打印排序后的元素{printf("%d ", a[i]);}return 0;
}
插入排序
#include <stdio.h>
#define N 10
void insertsort(int a[]) {int i, j, x;for(i = 1; i < N - 1; i++) {x=a[i];for (j=i-1;j>=0;j--) {if(a[j] > x) a[j + 1] = a[j];else break;}a[j + 1] = x;}
}
int main()
{int a[N] = {3, 4, 2, 6, 7, 8, 5, 4, 2, 12}, i;insertsort(a);for(i = 0; i < N; i++) {printf("%5d", a[i]);}
}
2.4 算法分析
表现最稳定的排序算法之一,因为无论什么数据进去都是O(n2)的时间复杂度,所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。
查找算法程序
查找算法 – 简介
查找(Searching)就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素。 查找表(Search Table):由同一类型的数据元素构成的集合 关键字(Key):数据元素中某个数据项的值,又称为键值 主键(Primary Key):可唯一的标识某个数据元素或记录的关键字
查找表按照操作方式可分为:
1.静态查找表(Static Search Table):
只做查找操作的查找表。它的主要操作是:
①查询某个“特定的”数据元素是否在表中
②检索某个“特定的”数据元素和各种属性
2.动态查找表(Dynamic Search Table):
在查找中同时进行插入或删除等操作:
①查找时插入数据
②查找时删除数据
顺序查找
说明:顺序查找适合于存储结构为顺序存储或链接存储的线性表。
基本思想: 顺序查找也称为线形查找,属于无序查找算法。从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结点关键字与给定值k相比较,若相等则表示查找成功;若扫描结束仍没有找到关键字等于k的结点,表示查找失败。
复杂度分析:
查找成功时的平均查找长度为:(假设每个数据元素的概率相等) ASL = 1/n(1+2+3+…+n) = (n+1)/2 ;
当查找不成功时,需要n+1次比较,时间复杂度为O(n);
所以,顺序查找的时间复杂度为O(n)。
//顺序查找C语言实现
//基本思路:用顺序结构存储数据(数组、链表),从前到后依次查询目标值,
// 如果发现则返回查找到的值,否则返回0.
#include<stdio.h>int FindBySeq(int *ListSeq, int ListLength, int KeyData);int main()
{int TestData[5] = { 34, 35, 26, 89, 56 };int retData = FindBySeq(TestData, 5, 89);printf("retData: %d\n", retData);return 0;
}int FindBySeq(int *ListSeq, int ListLength, int KeyData)
{int tmp = 0;int length = ListLength;for (int i = 0; i < ListLength; i++){if (ListSeq[i] == KeyData)return i;}return 0;
}
二分查找(折半查找)
说明:元素必须是有序的,如果是无序的则要先进行排序操作。
基本思想:也称为是折半查找,属于有序查找算法。用给定值k先与中间结点的关键字比较,中间结点把线形表分成两个子表,若相等则查找成功;若不相等,再根据k与该中间结点关键字的比较结果确定下一步查找哪个子表,这样递归进行,直到查找到或查找结束发现表中没有这样的结点。
复杂度分析:最坏情况下,关键词比较次数为log2(n+1)
,且期望时间复杂度为O(log2n)
;
二分查找的执行过程如下
1.从已经排好序的数组或区间中,取出中间位置的元素,将其与我们的目标值进行比较,判断是否相等,如果相等则返回。
2.如果 nums[mid]
和 target
不相等,则对 nums[mid]
和 target
值进行比较大小,通过比较结果决定是从 mid的左半部分还是右半部分继续搜索。
如果 target > nums[mid]
则右半区间继续进行搜索,即 left = mid + 1;
若target < nums[mid]
则在左半区间继续进行搜索,即 right = mid -1;
动图解析
//二分查找-C语言实现
//基本思路:将排序好的数据存放到数组里(不能是链表)
// 这只前中后标签,与中间元素比,若小于就将后变为原来的中
// 继续计算中,比较,循环,直至等于中,或循环结束。
#include <stdio.h>binarySearch(int a[], int n, int key){int low = 0;int high = n - 1;while(low<= high){int mid = (low + high)/2;int midVal = a[mid];if(midVal<key)low = mid + 1;else if(midVal>key)high = mid - 1;elsereturn mid;}return -1;
}int main(){int i, val, ret;int a[8]={-32, 12, 16, 24, 36, 45, 59, 98};for(i=0; i<8; i++)printf("%d\t", a[i]);printf("\n请输人所要查找的元素:");scanf("%d",&val);ret = binarySearch(a,8,val);if(-1 == ret)printf("查找失败 \n");elseprintf ("查找成功 \n");return 0;
}