docs: 添加仓库地址到README;chore: 整理实验分析;feat: Kruskal最小生成树与图存储结构

This commit is contained in:
2025-12-14 14:06:31 +08:00
parent be03307655
commit f2b8d1fe4c
52 changed files with 4600 additions and 291 deletions
+133
View File
@@ -0,0 +1,133 @@
// 逆波兰式逐步规约打印
// 输入:仅含 0-9、+ - * / 和小括号 () 的中缀表达式,数字均为一位
// 要求:
// - 先将中缀转为后缀(RPN
// - 按从左到右每次规约一个“两个数字 + 一个运算符”的三元组,得到新的后缀表达式
// - 逐行输出:首行是完整后缀表达式;之后每行比上一行少 1 个运算符和 1 个数字;最后一行只有一个数字(最终结果)
// - 令 / 为整除(向零截断),允许中间结果为负数
// - 输出格式:各符号之间以单个空格分隔;只有首行和最后一行行末保留一个空格,其他行末无空格
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef struct {
int is_num; // 1 表示数字,0 表示运算符
int val; // 数字值
char op; // 运算符字符
} Token;
// 运算符优先级:* / 高于 + -,全部左结合
static inline int prec(char c) {
if (c == '*' || c == '/') return 2;
if (c == '+' || c == '-') return 1;
return 0;
}
// 打印一行后缀表达式:tokens[0..n-1]
// 参数 trailing_space 控制是否在行末额外打印一个空格
static void print_tokens(const Token *t, int n, int trailing_space) {
for (int i = 0; i < n; ++i) {
if (t[i].is_num) {
printf("%d", t[i].val);
} else {
printf("%c", t[i].op);
}
if (i + 1 < n) putchar(' ');
}
if (trailing_space) putchar(' ');
putchar('\n');
}
// 计算 a (op) b,/ 为整除(向零),其余为常规整数算术
static inline int apply_int(int a, int b, char op) {
switch (op) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return (b == 0 ? 0 : a / b); // 题面保证不会越界;防御除零
default: return 0;
}
}
int main(void) {
// 读取整行
char line[256];
if (!fgets(line, sizeof(line), stdin)) return 0;
size_t len = strlen(line);
while (len && (line[len-1] == '\n' || line[len-1] == '\r')) line[--len] = '\0';
// 中缀转后缀(shunting-yard
Token out[256];
int on = 0;
char ops[256];
int ot = 0;
for (size_t i = 0; i < len; ++i) {
char c = line[i];
if (isspace((unsigned char)c)) continue;
if (c >= '0' && c <= '9') {
out[on].is_num = 1;
out[on].val = c - '0';
out[on].op = 0;
++on;
} else if (c == '+' || c == '-' || c == '*' || c == '/') {
int p = prec(c);
while (ot > 0 && ops[ot - 1] != '(' && prec(ops[ot - 1]) >= p) {
out[on].is_num = 0;
out[on].op = ops[--ot];
++on;
}
ops[ot++] = c;
} else if (c == '(') {
ops[ot++] = c;
} else if (c == ')') {
while (ot > 0 && ops[ot - 1] != '(') {
out[on].is_num = 0;
out[on].op = ops[--ot];
++on;
}
if (ot > 0 && ops[ot - 1] == '(') --ot; // 弹出左括号
} else {
// 题面保证无需判错
}
}
while (ot > 0) {
out[on].is_num = 0;
out[on].op = ops[--ot];
++on;
}
// 打印首行(保留行末空格)
print_tokens(out, on, 1);
// 逐步规约:每次找到第一个运算符(其前必有两个数字),规约为一个数字
Token cur[256];
memcpy(cur, out, on * sizeof(Token));
int n = on;
while (n > 1) {
int idx = -1;
for (int i = 0; i < n; ++i) {
if (!cur[i].is_num) { idx = i; break; }
}
// 规约 cur[idx-2], cur[idx-1], cur[idx]
int a = cur[idx - 2].val;
int b = cur[idx - 1].val;
int r = apply_int(a, b, cur[idx].op);
// 将结果写回到 idx-2,并左移覆盖 idx-1 与 idx
cur[idx - 2].is_num = 1;
cur[idx - 2].val = r;
// 左移 n-(idx+1) 个元素
for (int j = idx - 1; j + 2 < n; ++j) {
cur[j] = cur[j + 2];
}
n -= 2;
// 是否最后一行:n==1 时保留行末空格,否则不保留
print_tokens(cur, n, (n == 1));
}
return 0;
}