省略了
#include <stdio.h>没有
main函数则表示所有代码放在main函数中
闰年
闰年条件: 能被4整除并且不能被100整除, 或者能被400整除的数为闰年
(year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
一元二次方程
一般式:
Δ >= 0 时, 方程有两个实根
Δ < 0 时, 方程没有实根
n的阶乘
n! = 1 * 2 * 3 * ... * n - 1 * n
5! = 1 * 2 * 3 * 4 * 5
n! = (n - 1)! * n
用循环:
long fac(int n) {
long r = 1;
while (n > 1) {
r *= n;
n--;
}
return r;
}
用递归:
long fac(int n) {
if (n == 1) {
return 1;
} else {
return fac(n - 1) * n;
}
}
Fibonacci数列
斐波那契数列指的是这样一个数列:
1, 1, 2, 3, 5, 8, 13, 21...
这个数列从第3项开始,每一项都等于前两项之和
用循环:
int a = 1, // 上上项
b = 1, // 上一项
c, // 当前项
n = 20; // 设n为20
printf("%d %d ", a, b);
for (int i = 3; i <= n; i++) {
c = a + b; // 此轮当前项 = 前两项之和
a = b; // 下一轮上上项 = 此轮上一项
b = c; // 下一轮上一项 = 此轮当前项
printf("%d ", c);
}
数组+循环:
int arr[20] = { 1, 1 }; // 前两位都是1
int i;
for (i = 2; i <= 20; i++) { // 从第2位开始
arr[i] = arr[i - 2] + arr[i - 1]; // 每一位 = 前两位之和
}
// 输出Fibonacci数列
for (i = 0; i < 20; i++) {
printf("%d ", arr[i]);
}
用递归:
long fib(int n) {
if (n == 1 || n == 2) {
return 1;
} else {
return fib(n - 1) + fib(n - 2);
}
}
void main() {
int n = 20;
for (int i = 1; i <= n; i++) {
printf("%ld ", fib(i));
}
}
99乘法表
1*1=1 1*2=2 2*2=4 1*3=3 2*3=6 3*3=9 1*4=4 2*4=8 3*4=12 4*4=16 1*5=5 2*5=10 3*5=15 4*5=20 5*5=25 1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36 1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49 1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64 1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
int i, j;
for (i = 1; i <= 9; i++) {
for (j = 1; j <= i; j++) {
printf("%d*%d=%d\t", j, i, j * i);
}
printf("\n");
}
搬砖问题
有36块砖, 需要36人搬运, 男人每人搬4块, 女人每人搬3块, 儿童两人搬1块
男人取值范围为0 ~ 36 / 4 => 0 ~ 8
女人取值范围为0 ~ 36 / 3 => 0 ~ 12
儿童取值范围为0 ~ 36 => 0 ~ 36, 且为偶数
int man, woman, child;
for (man = 0; man <= 8; man++) {
for (woman = 0; woman <= 12; woman++) {
for (child = 0; child <= 36; child += 2) {
if ((4 * man + 3 * woman + child * 0.5 == 36) && (man + woman + child == 36)) {
printf("men: %d\n", men);
printf("women: %d\n", women);
printf("childs: %d\n", childs);
}
}
}
}
1~100的素数
素数: 除了1和它本身不能被其他数整除的数
int isPrime(int n) {
int i, t = sqrt(n); // 开根号是因为, 自t开始, 后面的步骤都是多余的, 自行推算
for (i = 2; i <= t; i++) { // 从2遍历到t
if (n % i == 0) { // 如果可以整除, 则不是素数
return 0;
}
}
return 1; // 否则是素数
}
void main() {
int i;
for (i = 1; i <= 100; i++) {
if (isPrime(i)) { // 对1~100的数逐个判断
printf("%d ", i);
}
}
}
输出所有的水仙花数
水仙花数是指一个3位数,其各位数字立方和等于该数本身
eg: 153 = 1^3 + 5^3 + 3^3
int i, hundred, ten, indiv;
for (i = 100; i < 1000; i++) { // 遍历所有的三位数
hundred = (int)i / 100, // 百位
ten = (int)i / 10 % 10, // 十位
indiv = i % 10; // 个位
// 如果其各位数字立方和等于它本身, 则为水仙花数
if (i == hundred * hundred * hundred + ten * ten * ten + indiv * indiv * indiv) {
printf("%d ", i);
}
}
印度国王的奖励
在国际象棋棋盘上放麦子, 第一格放1粒, 第二格放2粒, 第三格放4粒, 每个格子的麦子都按前一个格子的2倍计算. 需要64格的麦子. 一共需要多少粒麦子?
int i;
double s = 0,
t = 1; // 第一次放1粒麦子
for (i = 1; i <= 64; i++) { // 放麦子的次数为64次
s += t; // 将这一轮的麦子累加到s里
t *= 2; // 下一格的麦子 = 这一格的麦子 * 2
}
printf("%e\n", s); // 最后用科学计数法输出一共需要多少粒麦子
按照公式计算s的值
每一项的分母也是一个累加求和问题
第n项的分母是前n-1项的分母 + n
float s = 0; // s初值为0
int i,
n = 5, // 设n为5
t = 0; // 分母初值为0
for (i = 1; i <= n; i++) { // 以i代表n, 遍历n次
t += i; // 将分母累加起来(第i项的分母 = 上一项的分母 + i)
s += 1.0 / t;
}
printf("%f", s);
交换变量
void swap(int *p1, int *p2)
{
int t = *p1;
*p1 = *p2;
*p2 = t;
}
冒泡排序
每次将相邻的两个数比较, 将大的数调到后面
如果有 n 个数,则要进行 n - 1 轮比较, 第 i 轮比较中要进行 n - 1 - i 次比较
先定义一个用来交换变量的函数
void swap(int* p1, int* p2) {
int t = *p1;
*p1 = *p2;
*p2 = t;
}
不使用指针遍历:
void sort(int arr[], int len) {
int i, j, temp, current, next;
for (i = 1; i < len; i++) {
for (current = 0; current < len - i; current++) {
next = current + 1;
if (arr[current] > arr[next]) {
swap(&arr[current], &arr[next]);
}
}
}
}
使用指针遍历:
void sort(int arr[], int len) {
int* current,
* next,
temp,
i;
for (i = 1; i < len; i++) {
for (current = arr; current < arr + len - i; current++) {
next = current + 1;
if (*current > *next) {
swap(current, next);
}
}
}
}
二分查找
在升序数组中查找target
begin为首位, end为末位, middle为中位
middle = (begin + end) / 2
-
if (target == arr[middle]) 查找成功;
else if(target > arr[middle]) begin = middle + 1;
else if(target < arr[middle]) end = middle - 1;
-
if(begin > end) 查找失败
// 查找成功返回对应索引值, 查找失败返回-1, target为要查找的值
int search(int target, int arr[], int len) {
int begin = 0, // 首位初始值为0
end = len - 1, // 末位初始值为数组长度 - 1
middle; // 中位暂不设值
if (target < arr[begin] || target > arr[end]) { // 如果target比首位小或比末位大
return -1; // 查找失败
}
// 经上述步骤后, 确定target >= arr[begin] && target <= arr[end]
// ∴ target在arr[begin] ~ arr[end]的范围内, 但并不一定存在于数组中, 现在开始二分查找
do {
middle = (begin + end) / 2; // 确定中位
if (target == arr[middle]) { // 如果target等于中位值
return middle; // 则查找成功, 返回索引值
} else if (target < arr[middle]) { // 如果目标值小于中位值
end = middle - 1; // 确定前半段为下一次查找的范围
} else { // 如果目标值大于中位值
begin = middle + 1; // 确定前半段为下一次查找的范围
}
} while (begin <= end); // 当begin > end时, 数组中不存在target
return -1; // 查找失败
}
统计字符串中的单词
#include <string.h>
int countWords(char str[]) {
int len = strlen(str), // 字符串长度
previous, // 用来表示字符串中的前一位字符
current, // 用来表示字符串中的当前位字符
words = 0; // 单词数量默认为0
if (str[0] != '\0') { // str不是空字符串时开始统计
if (str[0] != ' ') { // 首字符是非空格, 置单词数为1
words = 1;
}
// 从字符串第1位开始遍历, 直到结束
for (current = 1; str[current] != '\0'; current++) {
previous = current - 1;
// 前一位是空格, 当前位不是空格, 表示出现新单词
if (str[previous] == ' ' && str[current] != ' ') {
words++;
}
}
}
return words;
}
使用指针:
int countWords(char str[]) {
char* previous, // 用来表示字符串中的前一位字符
* current = str; // 用来表示字符串中的当前位字符
int words = 0; // 单词数量默认为0
if (*current != '\0') { // str不是空字符串时开始统计
if (*current != ' ') { // 首字符是非空格, 置单词数为1
words = 1;
}
// 将current++, 也就是从字符串第1位开始遍历, 直到结束
for (current++; *current != '\0'; current++) {
previous = current - 1;
// 前一位是空格, 当前位不是空格, 表示出现新单词
if (*previous == ' ' && *current != ' ') {
words++;
}
}
}
return words;
}
矩阵求和
1 2 1 2 2 4
3 4 + 3 4 => 6 8
5 6 5 6 10 12
#define M 3
#define N 2
int a[M][N] = { { 9 , -16 }, { 6, 21 }, { 25, 18 } },
b[M][N] = { { 16, 89 }, { 26, -27 }, { 36, 81 } },
i,
j,
c[M][N];
for (i = 0; i < M; i++) {
for (j = 0; j < N; j++) {
c[i][j] = a[i][j] + b[i][j];
}
}
矩阵转置
1 2 1 3 5
3 4 =>
5 6 2 4 6
#define M 3
#define N 2
int a[M][N] = { { 1, 2 }, { 3, 4 }, { 5, 6 } },
b[N][M];
for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++) {
b[j][i] = a[i][j];
}
}
求矩阵最大值
#define M 3
#define N 2
int a[M][N] = {
{ 1, 2 },
{ 3, 4 },
{ 5, 6 }
};
int i,
j,
row = 0 // 行号
col = 0, // 列号
max = a[0][0]; // 最大值默认为a[0][0]
for (i = 0; i < M; i++) {
for (j = 0; j < N; j++) {
if (a[i][j] > max) {
max = a[i][j]; // 将更大的值保存在max中
row = i; // 记录行号
col = j; // 记录列号
}
}
}
printf("max: a[%d][%d]=%d\n", row, col, max);
求M*M矩阵对角线元素之和
M为偶数时: a[i][i] + a[i][M - i - 1]
M为奇数时: a[i][i] + a[i][M - i - 1] - a[M / 2][M / 2]
#define M 3
int a[M][M] = {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
int sum = 0,
i;
for (i = 0; i < M; i++) {
sum += a[i][i] + a[i][M - i - 1];
}
if (M % 2 == 1) { // 判断a是奇数矩阵还是偶数矩阵
sum -= a[M / 2][M / 2]; // a是奇数矩阵时, 将重复累加的中心元素值扣除
}
printf("Sum = %d\n", sum);
杨辉三角
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
首尾都是1
从第2行开始每一行的1位到倒数第二位的规律: **当前行当前列 = 上一行上一列 **+ 上一行当前列
arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j]
#define N 6
int arr[N][N],
i,
j;
for (i = 0; i < N; i++) {
arr[i][0] = 1;
arr[i][i] = 1;
}
for (i = 2; i < N; i++) {
for (j = 1; j < i; j++) {
arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];
}
}
数组反转
void swap(int* p1, int* p2) {
int t = *p1;
*p1 = *p2;
*p2 = t;
}
void reverse(int arr[], int len) {
int i,
middle = len / 2;
for (i = 0; i < middle; i++) {
swap(arr + i, arr + (len - i - 1));
}
}
将电文转译成密码
将一个字符串中的
"abcdefghijklmnopqrstuvwxyz "
转译为
"0123456789abcdefghi@#$%&!*j"
其他字符不变
// 查找字符串中的字符, 成功返回索引, 失败返回-1
int search(char str[], char c) {
int i;
for (i = 0; str[i] != '\0'; i++) {
if (str[i] == c) {
return i;
}
}
return -1;
}
void main() {
char code1[] = "abcdefghijklmnopqrstuvwxyz ", // 明文表
code2[] = "0123456789abcdefghi@#$%&!*j", // 密文表
str1[] = "This is a example.", // 要转译的明文
str2[50]; // 转译后的密文
int i,
index;
for (i = 0; str1[i] != '\0'; i++) { // 遍历明文表
if ((index = search(code1, str1[i])) != -1) { // 在明文表中逐个查找明文中的每一个字符
str2[i] = code2[index]; // 查找成功则向str2中与str1对应的位置赋值为对应的密文字符
continue; // 然后跳过此轮循环, 准备处理下一个字符
}
str2[i] = str1[i]; // 查找失败则直接向str2中对应的位置赋值为明文字符
}
str2[i] = '\0'; // 最后结束字符串
puts(str2);
}
汉诺塔问题
有ABC三个柱子, n个大小不相同的盘子, 所有盘子以塔状叠放在A柱上, 按照一定规则将A柱的所有盘子移动到B柱上, C柱为中转柱, 移动规则如下:
- 一次只能移动一个盘子
- 始终保持小盘在上, 大盘在下
步骤:
若有n个盘子
- 把A上面的n - 1个盘子移到C
- 将A仅有的一个盘子(也是最大的一只)直接移到B上
- 将C上的n - 1个盘子移到B上, 如此反复(递归)
void hanoi(int n, char A, char B, char C) {
if (n == 1) {
printf("%c-->%c", A, B); // 在递归过程中, 每当只剩1个盘子时,直接移动到目标盘
return;
} else {
hanoi(n - 1, A, C, B); // 第一步: 将上面的n-1个盘子由A经过B, 移到C
printf("\t%c-->%c\t", A, B); // 第二步: 将A上仅有的1个盘子直接移到B
hanoi(n - 1, C, B, A); // 第三步: 将C上的n-1个盘子由C经过A, 移到B
}
}
void main() {
hanoi(3, 'A', 'B', 'C');
}
最大公约数和最小公倍数
最大公约数:
辗转相除法: 将除数和余数反复做除法运算, 当余数为0时, 取算式中的除数为最大公约数
eg : 28和21
28 % 21 = 1 ... 7
21 % 7 = 3 ... 0
最大公约数为7
最小公倍数:
∵两个自然数的乘积 = 最大公约数 * 最小公倍数
∴最小公倍数 = 两个自然数的乘积 / 最大公约数
= 28 * 21 / 7
= 84
最小公倍数为84
int getGcd(int m, int n) { // 被除数m, 除数n
int r; // 余数
while ((r = m % n) != 0) {
m = n; // 下一轮的被除数为这一轮的除数
n = r; // 下一轮的除数为这一轮的余数
}
return n; // 当余数为0时, 此时的除数为最大公约数
}
int getLcm(int m, int n, int gcd) {
return m * n / gcd; // 最小公倍数 = 两数乘积 / 最大公约数
}
void main() {
int m, n;
scanf("%d %d", &m, &n);
int gcd = getGcd(m, n),
lcm = getLcm(m, n, gcd);
printf("%d %d\n", gcd, lcm);
}
判断传入的数是否是素数()
int isPrime(int n) {
int flag = 1, i, t = sqrt(n);
for (i = 2; i <= t; i++) {
if (n % i == 0) {
flag = 0;
break;
}
}
return flag;
}
字符串排序
通过交换地址的方式排序字符串数组
#include <string.h>
void sort(char* strArr[], int len) {
char* temp; // 指向字符串
int i,
current,
next;
for (i = 1; i < len; i++) {
for (current = 0; current < len - i; current++) {
next = current + 1;
// 如果这一位字符串大于下一位, 则交换指向字符串的指针的地址
if (strcmp(strArr[current], strArr[next]) > 0) {
temp = strArr[current];
strArr[current] = strArr[next];
strArr[next] = temp;
}
}
}
}
三色球问题
有红、黄、蓝、白、黑五种颜色的球若干个, 每次取出三个球 求出所有三种不同颜色的球的可能取法
int i,
j,
k,
n = 1;
char* colors[5] = { "red", "yellow", "blue", "white", "black" };
for (i = 0; i < 5; i++) {
for (j = 0; j < 5; j++) {
for (k = 0; k < 5; k++) {
if (i != j && j != k && i != k) {
printf("%d\t%s\t%s\t%s\n", n++, colors[i], colors[j], colors[k]);
}
}
}
}
从指针数组中查找第一个包含子串的字符串()
#include <string.h>
char* findFirstStrIncludesubStrFromStrArr(char* strArr[], char* subStr, int len) {
int i;
char* str;
for (i = 0; i < len; i++) {
str = strArr[i];
if (strstr(str, subStr) != 0) {
return str;
}
}
return '\0';
}
文本文件的复制
#include <stdio.h>
void main(int argc, char* argv[]) {
char* source = argv[1], * target = argv[2], c;
FILE* sourceP, * targetP;
if ((sourceP = fopen(source, "r")) == NULL) {
printf("cannot open source file");
exit(0);
}
if ((targetP = fopen(target, "w")) == NULL) {
printf("cannot open target file");
exit(0);
}
while (!feof(sourceP) && (c = fgetc(sourceP)) != EOF) {
fputc(c, targetP);
}
fclose(sourceP);
fclose(targetP);
}
用位运算使一个整型数据(4字节)清零
#include <stdio.h>
void main() {
int i = 1234;
i = i & 0x00000000;
}
用位运算输出整型数据(4字节)的高字节和低字节
#include <stdio.h>
void main() {
int i = 1234, high, low;
low = i & 0000ffff; // 取低字节
high = (i >> 16) & 0000ffff; // 取高字节
}
函数, 测定整数i(4字节)的最高位, 为0则输出"正数", 为1则输出"负数"
void test(int i) {
if (i & 0x80000000) {
printf("负数");
} else {
printf("正数");
}
}
函数, 使一个整数i的二进制形式中的低4位改为1, 并将得到的数返回
int f(int i) {
int t = i | 0x0000000f;
return t;
}
函数, 将一个整数i(4字节)循环左移4位
int f(int i) {
int a = (i >> (32 - 4)) & 0x0000000f; // a的值是i最左边的4位
int b = i << 4; // b的值是i左移4位后的结果
int c = (a | b) & 0xffffffff; // 与运算拼接
return c;
}
函数, 取一个整数最高端的5个二进制位
int f(int i) {
int c = i >> (32 - 5);
c = c & 0x0000001f;
return c;
}
所有的文件函数
FILE* fopen(char* filename, char* mode)
fclose(FILE* fp)
int fgetc(FILE* fp)
fputc(int c, FILE* fp)
fread(void* buffer, int size, int count, FILE* fp)
fwrite(void* buffer, int size, int count, FILE* fp)
int feof(FILE* fp)
long ftell(FILE* fp)
fseek(FILE* fp, int offset, int origin)
rewind(FILE* fp)
fscanf(FILE* fp, char* format, ...)
fprintf(FILE* fp, char* format, ...)
动态单向链表
#include <stdio.h>
#include <malloc.h>
#define LEN sizeof(struct Student)
struct Student {
long num;
float score;
struct Student* next;
};
int n;
struct Student* create() {
struct Student* head;
struct Student* p1, * p2;
n = 0;
p1 = p2 = (struct Student*)malloc(LEN);
scanf("%ld,%f", &p1->num, &p1->score);
head = NULL;
while (p1->num != 0) {
n++;
if (n == 1) head = p1;
else p2->next = p1;
p2 = p1;
p1 = (struct Student*)malloc(LEN);
scanf("%ld,%f", &p1->num, &p1->score);
}
p2->next = NULL;
return head;
}
void print(struct Student* head) {
struct Student* p;
printf("\nNow, These %d records are:\n", n);
p = head;
if (head != NULL) {
do {
printf("%ld\t%5.1f\n", p->num, p->score);
p = p->next;
} while (p != NULL);
}
}
int main() {
struct Student* head;
head = create();
print(head);
return 0;
}