From f2b8d1fe4cac396b5fd3b7bed1a67403a60b5ffe Mon Sep 17 00:00:00 2001 From: LHY0125 <3364451258@qq.com> Date: Sun, 14 Dec 2025 14:06:31 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=B7=BB=E5=8A=A0=E4=BB=93=E5=BA=93?= =?UTF-8?q?=E5=9C=B0=E5=9D=80=E5=88=B0README=EF=BC=9Bchore:=20=E6=95=B4?= =?UTF-8?q?=E7=90=86=E5=AE=9E=E9=AA=8C=E5=88=86=E6=9E=90=EF=BC=9Bfeat:=20K?= =?UTF-8?q?ruskal=E6=9C=80=E5=B0=8F=E7=94=9F=E6=88=90=E6=A0=91=E4=B8=8E?= =?UTF-8?q?=E5=9B=BE=E5=AD=98=E5=82=A8=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 4 +- .vscode/settings.json | 2 +- README.md | 3 + exercise/1.c | 177 +++++++++++ exercise/10.c | 158 +++++++++ exercise/11.c | 163 ++++++++++ exercise/12.c | 388 +++++++++++++++++++++++ exercise/13.c | 136 ++++++++ exercise/14.c | 42 +++ exercise/15.c | 43 +++ exercise/16.c | 49 +++ exercise/17.c | 41 +++ exercise/18.c | 43 +++ exercise/19.c | 52 +++ exercise/2.c | 50 +++ exercise/20.c | 44 +++ exercise/21.c | 88 +++++ exercise/22.c | 91 ++++++ exercise/23.c | 98 ++++++ exercise/24.c | 209 ++++++++++++ exercise/25.c | 86 +++++ exercise/26.c | 108 +++++++ exercise/27.c | 116 +++++++ exercise/28.c | 84 +++++ exercise/29.c | 66 ++++ exercise/3.c | 53 ++++ exercise/30.c | 65 ++++ exercise/31.c | 119 +++++++ exercise/32.c | 87 +++++ exercise/33.c | 170 ++++++++++ exercise/34.c | 133 ++++++++ exercise/35.c | 111 +++++++ exercise/36.c | 87 +++++ exercise/37.c | 152 +++++++++ exercise/38.c | 79 +++++ exercise/39.c | 30 ++ exercise/4.c | 34 ++ exercise/40.c | 156 +++++++++ exercise/41.c | 312 ++++++++++++++++++ exercise/42.c | 211 ++++++++++++ exercise/43.c | 119 +++++++ exercise/5.c | 46 +++ exercise/6.c | 32 ++ exercise/7.c | 36 +++ exercise/8.c | 124 ++++++++ exercise/9.c | 73 +++++ 数据结构/1.c | 35 -- 数据结构/未命名.c | 244 -------------- 数据结构/课上代码练习/README.md | 3 + 数据结构/课上代码练习/双栈.c | 15 +- 数据结构/课上代码练习/顺序表的基本操作.c | 23 ++ 数据结构/陈越数据结构/clock.c | 1 - 52 files changed, 4600 insertions(+), 291 deletions(-) create mode 100644 exercise/1.c create mode 100644 exercise/10.c create mode 100644 exercise/11.c create mode 100644 exercise/12.c create mode 100644 exercise/13.c create mode 100644 exercise/14.c create mode 100644 exercise/15.c create mode 100644 exercise/16.c create mode 100644 exercise/17.c create mode 100644 exercise/18.c create mode 100644 exercise/19.c create mode 100644 exercise/2.c create mode 100644 exercise/20.c create mode 100644 exercise/21.c create mode 100644 exercise/22.c create mode 100644 exercise/23.c create mode 100644 exercise/24.c create mode 100644 exercise/25.c create mode 100644 exercise/26.c create mode 100644 exercise/27.c create mode 100644 exercise/28.c create mode 100644 exercise/29.c create mode 100644 exercise/3.c create mode 100644 exercise/30.c create mode 100644 exercise/31.c create mode 100644 exercise/32.c create mode 100644 exercise/33.c create mode 100644 exercise/34.c create mode 100644 exercise/35.c create mode 100644 exercise/36.c create mode 100644 exercise/37.c create mode 100644 exercise/38.c create mode 100644 exercise/39.c create mode 100644 exercise/4.c create mode 100644 exercise/40.c create mode 100644 exercise/41.c create mode 100644 exercise/42.c create mode 100644 exercise/43.c create mode 100644 exercise/5.c create mode 100644 exercise/6.c create mode 100644 exercise/7.c create mode 100644 exercise/8.c create mode 100644 exercise/9.c delete mode 100644 数据结构/1.c delete mode 100644 数据结构/未命名.c create mode 100644 数据结构/课上代码练习/顺序表的基本操作.c diff --git a/.vscode/launch.json b/.vscode/launch.json index d46503e..3e4937f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,8 +8,8 @@ "args": [], "stopAtEntry": false, "externalConsole": true, - "cwd": "d:/Code/C_code/数据结构/陈越数据结构", - "program": "d:/Code/C_code/数据结构/陈越数据结构/build/Debug/outDebug", + "cwd": "d:/Code/C_code/exercise", + "program": "d:/Code/C_code/exercise/build/Debug/outDebug", "MIMode": "gdb", "miDebuggerPath": "gdb", "setupCommands": [ diff --git a/.vscode/settings.json b/.vscode/settings.json index 7b08d16..c10c8c7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,7 +4,7 @@ "C_Cpp_Runner.debuggerPath": "gdb", "C_Cpp_Runner.cStandard": "c17", "C_Cpp_Runner.cppStandard": "c++17", - "C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/VR_NR/Community/VC/Auxiliary/Build/vcvarsall.bat", + "C_Cpp_Runner.msvcBatchPath": "", "C_Cpp_Runner.useMsvc": false, "C_Cpp_Runner.warnings": [ "-Wall", diff --git a/README.md b/README.md index b3244ef..b4addf3 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,9 @@ ## 项目简介 这是一个完整的C语言学习代码库,包含了从基础语法到高级项目的全面学习内容。代码库涵盖了翁凯老师C语言课程的所有章节练习、课堂代码实践以及完整的项目实战。 +### 仓库地址 +- GitHub仓库为:https://github.com/LHY0125/Learn_C.git + ## 项目结构 ### 📚 翁凯C语言/ - 系统化学习路径 diff --git a/exercise/1.c b/exercise/1.c new file mode 100644 index 0000000..1ff3f13 --- /dev/null +++ b/exercise/1.c @@ -0,0 +1,177 @@ +#include +#include +#include +#include +#ifdef _WIN32 +#include +#include +#endif + +#define MAX_SIZE 1000 + +// 栈结构用于存储数字 +typedef struct +{ + int data[MAX_SIZE]; + int top; +} Stack; + +// 初始化栈 +void initStack(Stack *s) +{ + s->top = -1; +} + +// 判断栈是否为空 +int isEmpty(Stack *s) +{ + return s->top == -1; +} + +// 入栈 +void push(Stack *s, int value) +{ + if (s->top < MAX_SIZE - 1) + { + s->data[++s->top] = value; + } +} + +// 出栈 +int pop(Stack *s) +{ + if (!isEmpty(s)) + { + return s->data[s->top--]; + } + return 0; +} + +// 获取栈顶元素 +int peek(Stack *s) +{ + if (!isEmpty(s)) + { + return s->data[s->top]; + } + return 0; +} + +// 判断运算符优先级 +int precedence(char op) +{ + if (op == '+' || op == '-') + return 1; + if (op == '*' || op == '/') + return 2; + return 0; +} + +// 执行运算 +int calculate(int a, int b, char op) +{ + switch (op) + { + case '+': + return a + b; + case '-': + return a - b; + case '*': + return a * b; + case '/': + return a / b; + default: + return 0; + } +} + +// 计算表达式 +int evaluateExpression(char *expression) +{ + Stack numbers; + Stack operators; + initStack(&numbers); + initStack(&operators); + + int len = strlen(expression); + + for (int i = 0; i < len; i++) + { + // 跳过空格 + if (expression[i] == ' ') + { + continue; + } + + // 如果是数字 + if (isdigit(expression[i])) + { + int num = 0; + // 读取完整的数字 + while (i < len && isdigit(expression[i])) + { + num = num * 10 + (expression[i] - '0'); + i++; + } + i--; // 回退一位,因为for循环会自动增加 + push(&numbers, num); + } + // 如果是运算符 + else if (expression[i] == '+' || expression[i] == '-' || + expression[i] == '*' || expression[i] == '/') + { + + // 处理运算符优先级 + while (!isEmpty(&operators) && + precedence((char)peek(&operators)) >= precedence(expression[i])) + { + int b = pop(&numbers); + int a = pop(&numbers); + char op = (char)pop(&operators); + push(&numbers, calculate(a, b, op)); + } + push(&operators, expression[i]); + } + } + + // 处理剩余的运算符 + while (!isEmpty(&operators)) + { + int b = pop(&numbers); + int a = pop(&numbers); + char op = (char)pop(&operators); + push(&numbers, calculate(a, b, op)); + } + + return pop(&numbers); +} + +int main() +{ + // 设置控制台编码为UTF-8,防止中文乱码 +#ifdef _WIN32 + system("chcp 65001 > nul"); // 设置控制台编码为UTF-8 + SetConsoleOutputCP(65001); // 设置控制台输出编码 + SetConsoleCP(65001); // 设置控制台输入编码 + _mkdir("records"); +#endif + + char expression[MAX_SIZE]; + + // 读取表达式 + if (fgets(expression, sizeof(expression), stdin) != NULL) + { + // 去除换行符 + int len = strlen(expression); + if (len > 0 && expression[len - 1] == '\n') + { + expression[len - 1] = '\0'; + } + + // 计算并输出结果 + int result = evaluateExpression(expression); + printf("%d\n", result); + } + + return 0; +} \ No newline at end of file diff --git a/exercise/10.c b/exercise/10.c new file mode 100644 index 0000000..3e3cf52 --- /dev/null +++ b/exercise/10.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include + +#define MAX_SIZE 10002 + +// 栈结构 +typedef struct +{ + char data[MAX_SIZE]; + int top; +} Stack; + +// 初始化栈 +void initStack(Stack *s) +{ + s->top = -1; +} + +// 判断栈是否为空 +bool isEmpty(Stack *s) +{ + return s->top == -1; +} + +// 判断栈是否已满 +bool isFull(Stack *s) +{ + return s->top == MAX_SIZE - 1; +} + +// 入栈 +bool push(Stack *s, char item) +{ + if (isFull(s)) + { + return false; + } + s->data[++s->top] = item; + return true; +} + +// 出栈 +bool pop(Stack *s, char *item) +{ + if (isEmpty(s)) + { + return false; + } + *item = s->data[s->top--]; + return true; +} + +// 判断字符是否为左括号 +bool isLeftBracket(char c) +{ + return c == '(' || c == '[' || c == '{'; +} + +// 判断字符是否为右括号 +bool isRightBracket(char c) +{ + return c == ')' || c == ']' || c == '}'; +} + +// 判断左右括号是否匹配 +bool isMatching(char left, char right) +{ + return (left == '(' && right == ')') || + (left == '[' && right == ']') || + (left == '{' && right == '}'); +} + +// 括号匹配验证函数 +bool isValidBrackets(char *s) +{ + Stack stack; + initStack(&stack); + + int len = strlen(s); + + // 空字符串返回true + if (len == 0) + { + return true; + } + + for (int i = 0; i < len; i++) + { + char current = s[i]; + + // 如果是左括号,入栈 + if (isLeftBracket(current)) + { + if (!push(&stack, current)) + { + // 栈满,返回false + return false; + } + } + // 如果是右括号,检查匹配 + else if (isRightBracket(current)) + { + // 栈为空,说明没有对应的左括号 + if (isEmpty(&stack)) + { + return false; + } + + char top; + pop(&stack, &top); + + // 检查是否匹配 + if (!isMatching(top, current)) + { + return false; + } + } + // 根据题目描述,输入只包含括号字符,不应该有其他字符 + } + + // 最后栈应该为空,表示所有括号都已匹配 + return isEmpty(&stack); +} + +int main() +{ + char s[MAX_SIZE]; + + // 读取输入字符串 + if (fgets(s, sizeof(s), stdin) != NULL) + { + // 去除换行符 + int len = strlen(s); + if (len > 0 && s[len - 1] == '\n') + { + s[len - 1] = '\0'; + } + + // 验证括号匹配并输出结果 + if (isValidBrackets(s)) + { + printf("true\n"); + } + else + { + printf("false\n"); + } + } + else + { + // 如果读取失败,输出false + printf("false\n"); + } + + return 0; +} \ No newline at end of file diff --git a/exercise/11.c b/exercise/11.c new file mode 100644 index 0000000..ed555d4 --- /dev/null +++ b/exercise/11.c @@ -0,0 +1,163 @@ +#include +#include +#include +#ifdef _WIN32 +#include +#include +#endif + +#define NUM_COUNT 10000 +#define INPUT_FILE "random_numbers.txt" +#define OUTPUT_FILE "sorted_numbers.txt" + +/* 选择排序函数 */ +void SelectSort(int arr[], int n) +{ + int i, j, minIndex, temp; + for (i = 0; i < n - 1; i++) + { + // 假设当前索引i的元素为最小值 + minIndex = i; + for (j = i + 1; j < n; j++) + { + // 在未排序部分查找更小元素 + if (arr[j] < arr[minIndex]) + { + // 更新最小值的索引 + minIndex = j; + } + } + + // 将找到的最小值与当前位置交换 + if (minIndex != i) + { + temp = arr[i]; + arr[i] = arr[minIndex]; + arr[minIndex] = temp; + } + } +} + +/* 生成随机数并写入文件 */ +void MakeRandomNumber(const char *filename) +{ + FILE *file = fopen(filename, "w"); + if (file == NULL) + { + printf("错误:无法创建文件 %s\n", filename); + exit(1); + } + + // 初始化随机数种子 + srand((unsigned int)time(NULL)); + for (int i = 0; i < NUM_COUNT; i++) + { + // 生成0-99999范围内的随机数 + fprintf(file, "%d\n", rand() % 100000); + } + + fclose(file); + printf("已生成 %d 个随机数到文件 %s\n", NUM_COUNT, filename); +} + +/* 从文件读取数字到数组 */ +int ReadNumbers(const char *filename, int arr[]) +{ + FILE *file = fopen(filename, "r"); + if (file == NULL) + { + printf("错误:无法打开文件 %s\n", filename); + exit(1); + } + + int count = 0; + while (fscanf(file, "%d", &arr[count]) != EOF && count < NUM_COUNT) + { + count++; + } + + fclose(file); + printf("已从文件 %s 读取 %d 个数字\n", filename, count); + return count; +} + +/* 将数组中的数字写入文件 */ +void writeNumbersToFile(const char *filename, int arr[], int n) +{ + FILE *file = fopen(filename, "w"); + if (file == NULL) + { + printf("错误:无法创建文件 %s\n", filename); + exit(1); + } + + for (int i = 0; i < n; i++) + { + fprintf(file, "%d\n", arr[i]); + } + + fclose(file); + printf("已将 %d 个排序后的数字写入文件 %s\n", n, filename); +} + +int main() +{ + // 设置控制台编码为UTF-8,防止中文乱码 +#ifdef _WIN32 + system("chcp 65001 > nul"); // 设置控制台编码为UTF-8 + SetConsoleOutputCP(65001); // 设置控制台输出编码 + SetConsoleCP(65001); // 设置控制台输入编码 + _mkdir("records"); +#endif + + int numbers[NUM_COUNT]; + int actual_count; + clock_t start, end; + double time_used; + + printf("=== 选择排序执行时间测量程序 ===\n"); + + // 生成随机数并写入文件 + printf("\n1. 生成随机数...\n"); + MakeRandomNumber(INPUT_FILE); + + // 从文件读取数字到数组 + printf("\n2. 读取文件...\n"); + actual_count = ReadNumbers(INPUT_FILE, numbers); + + // 显示部分未排序数据 + printf("\n3. 未排序数据(前10个): "); + for (int i = 0; i < 10 && i < actual_count; i++) + { + printf("%d ", numbers[i]); + } + printf("\n"); + + // 测量选择排序执行时间 + printf("\n4. 开始选择排序...\n"); + // 记录开始时间 + start = clock(); + SelectSort(numbers, actual_count); + // 记录结束时间 + end = clock(); + + // 计算并显示执行时间 + time_used = ((double)(end - start)) / CLOCKS_PER_SEC; + printf("选择排序完成!\n"); + printf("执行时间: %.6f 秒\n", time_used); + + // 显示部分已排序数据 + printf("\n6. 已排序数据(前10个): "); + for (int i = 0; i < 10 && i < actual_count; i++) + { + printf("%d ", numbers[i]); + } + printf("\n"); + + // 将排序后的数据写入新文件 + printf("\n7. 写入排序结果...\n"); + writeNumbersToFile(OUTPUT_FILE, numbers, actual_count); + + printf("\n=== 程序执行完成 ===\n"); + return 0; +} \ No newline at end of file diff --git a/exercise/12.c b/exercise/12.c new file mode 100644 index 0000000..e2d6da9 --- /dev/null +++ b/exercise/12.c @@ -0,0 +1,388 @@ +#include +#include +#include +#ifdef _WIN32 +#include +#include +#endif + +// 定义双向链表节点结构体 +struct Node +{ + int data; + struct Node *prev; + struct Node *next; +}; + +// 定义双向链表结构体 +struct DoubleList +{ + struct Node *head; + struct Node *tail; +}; + +// 初始化双向链表 +void initDoubleList(struct DoubleList *list) +{ + list->head = NULL; + list->tail = NULL; +} + +// 获取双向链表长度 +int getListLength(struct DoubleList *list) +{ + int length = 0; + struct Node *current = list->head; + while (current != NULL) + { + length++; + current = current->next; + } + return length; +} + +// 向双向链表头部添加节点 +void addNodeToHead(struct DoubleList *list, int data) +{ + // 分配新节点内存 + struct Node *newNode = (struct Node *)malloc(sizeof(struct Node)); + newNode->data = data; + newNode->prev = NULL; + newNode->next = list->head; + + // 如果链表为空,则新节点同时是头节点和尾节点 + if (list->head == NULL) + { + list->tail = newNode; + } + else + { + list->head->prev = newNode; + } + + // 更新头节点为新节点 + list->head = newNode; +} + +// 向双向链表尾部添加节点 +void addNodeToTail(struct DoubleList *list, int data) +{ + // 分配新节点内存 + struct Node *newNode = (struct Node *)malloc(sizeof(struct Node)); + newNode->data = data; + newNode->prev = list->tail; + newNode->next = NULL; + + // 如果链表为空,则新节点同时是头节点和尾节点 + if (list->tail == NULL) + { + list->head = newNode; + } + else + { + list->tail->next = newNode; + } + + // 更新尾节点为新节点 + list->tail = newNode; +} + +// 在指定位置插入节点 +void insertNode(struct DoubleList *list, int data, int position) +{ + // 分配新节点内存 + struct Node *newNode = (struct Node *)malloc(sizeof(struct Node)); + newNode->data = data; + + // 如果插入位置为0,则在头部插入 + if (position == 0) + { + addNodeToHead(list, data); + } + // 如果插入位置大于等于链表长度,则在尾部插入 + else if (position >= getListLength(list)) + { + addNodeToTail(list, data); + } + + // 否则,在指定位置插入 + else + { + // 首先遍历到指定位置 + struct Node *current = list->head; + for (int i = 0; i < position; i++) + { + current = current->next; + } + + // 然后插入到指定位置 + newNode->prev = current->prev; + newNode->next = current; + + // 更新当前节点的前一个节点的next指针 + current->prev->next = newNode; + + // 更新当前节点的前指针为新节点 + current->prev = newNode; + } +} + +// 删除指定位置的节点 +int delectNode(struct DoubleList *list, int position) +{ + // 如果删除位置为0,则删除头节点 + if (position == 0) + { + // 如果链表只有一个节点,则删除后链表为空 + if (list->head == list->tail) + { + free(list->head); + list->head = NULL; + list->tail = NULL; + } + else + { + // 更新头节点为下一个节点 + list->head = list->head->next; + // 释放旧头节点内存,更新新头节点的prev指针为NULL + free(list->head->prev); + list->head->prev = NULL; + } + return 1; + } + // 如果删除位置大于等于链表长度,则删除尾节点 + else if (position >= getListLength(list)) + { + // 更新尾节点为前一个节点 + list->tail = list->tail->prev; + // 释放旧尾节点内存,更新新尾节点的next指针为NULL + free(list->tail->next); + list->tail->next = NULL; + return 1; + } + // 如果删除位置在中间,则删除指定位置节点 + else + { + // 首先遍历到指定位置 + struct Node *current = list->head; + for (int i = 0; i < position; i++) + { + current = current->next; + } + // 更新前一个节点的next指针为后一个节点 + current->prev->next = current->next; + + // 更新后一个节点的prev指针为前一个节点,更新当前节点的next指针为NULL + current->next->prev = current->prev; + + free(current); + + return 1; + } +} + +// 修改指定位置节点的数据 +int modifyNode(struct DoubleList *list, int data, int position) +{ + // 首先遍历到指定位置 + struct Node *current = list->head; + for (int i = 0; i < position; i++) + { + current = current->next; + } + // 修改节点数据 + current->data = data; + return 1; +} + +// 查找指定数据的节点位置 +int findNodePosition(struct DoubleList *list, int data) +{ + // 从头节点开始遍历 + struct Node *current = list->head; + int position = 0; + while (current != NULL) + { + // 如果找到匹配数据,则返回当前位置 + if (current->data == data) + { + return position; + } + // 否则,继续遍历下一个节点 + current = current->next; + position++; + } + // 如果遍历完链表仍未找到匹配数据,则返回-1 + return -1; +} + +// 查找指定位置的节点数据 +int findNodeData(struct DoubleList *list, int position) +{ + // 首先遍历到指定位置 + struct Node *current = list->head; + for (int i = 0; i < position; i++) + { + current = current->next; + } + // 返回当前节点数据 + return current->data; +} + +// 打印链表所有节点数据 +void printList(struct DoubleList *list) +{ + // 从头节点开始遍历 + struct Node *current = list->head; + while (current != NULL) + { + // 打印当前节点数据 + printf("%d ", current->data); + // 继续遍历下一个节点 + current = current->next; + } + // 打印换行符 + printf("\n"); +} + +int main() +{ + // 设置控制台编码为UTF-8,防止中文乱码 +#ifdef _WIN32 + system("chcp 65001 > nul"); // 设置控制台编码为UTF-8 + SetConsoleOutputCP(65001); // 设置控制台输出编码 + SetConsoleCP(65001); // 设置控制台输入编码 +#endif + + // 初始化双端链表 + struct DoubleList list; + initDoubleList(&list); + + // 输入节点数据 + printf("请输入初始节点数据的数量(默认在链表尾端插入):"); + int count; + scanf("%d", &count); + for (int i = 0; i < count; i++) + { + printf("请输入第 %d 个节点数据:", i + 1); + int data; + scanf("%d", &data); + addNodeToTail(&list, data); + } + + while (1) + { + // 打印菜单 + printf("1. 插入节点\n"); + printf("2. 删除节点\n"); + printf("3. 修改节点\n"); + printf("4. 查找节点\n"); + printf("5. 打印链表\n"); + printf("0. 退出程序\n"); + printf("请输入操作选择:"); + int choice; + scanf("%d", &choice); + + // 根据选择执行相应操作 + switch (choice) + { + case 1: + printf("1. 在链表头插入节点\n"); + printf("2. 在链表尾插入节点\n"); + printf("3. 在指定位置插入节点\n"); + printf("请输入插入方式选择:"); + int addchoice; + scanf("%d", &addchoice); + + printf("请输入要插入的数据:"); + int insertData; + scanf("%d", &insertData); + switch (addchoice) + { + case 1: + addNodeToHead(&list, insertData); + break; + case 2: + addNodeToTail(&list, insertData); + break; + case 3: + printf("请输入要插入的位置:"); + int insertPosition; + scanf("%d", &insertPosition); + insertNode(&list, insertData, insertPosition); + break; + default: + printf("无效选择,请重新输入\n"); + break; + } + break; + case 2: + printf("请输入要删除的位置:"); + int deletePosition; + scanf("%d", &deletePosition); + delectNode(&list, deletePosition); + break; + case 3: + printf("请输入要修改的数据:"); + int modifyData; + scanf("%d", &modifyData); + printf("请输入要修改的位置:"); + int modifyPosition; + scanf("%d", &modifyPosition); + modifyNode(&list, modifyData, modifyPosition); + break; + case 4: + printf("1. 查找指定数据的节点位置\n"); + printf("2. 查找指定位置的节点数据\n"); + printf("请输入查找方式选择:"); + int findchoice; + scanf("%d", &findchoice); + switch (findchoice) + { + case 1: + printf("请输入要查找的数据:"); + int findData; + scanf("%d", &findData); + int position = findNodePosition(&list, findData); + if (position != -1) + { + printf("数据 %d 位于链表第 %d 个节点\n", findData, position); + } + else + { + printf("链表中不存在数据 %d\n", findData); + } + break; + case 2: + printf("请输入要查找的位置:"); + int findPosition; + scanf("%d", &findPosition); + int data = findNodeData(&list, findPosition); + if (data != -1) + { + printf("链表第 %d 个节点的数据为 %d\n", findPosition, data); + } + else + { + printf("链表中不存在第 %d 个节点\n", findPosition); + } + break; + default: + printf("无效选择,请重新输入\n"); + break; + } + break; + case 5: + printList(&list); + break; + case 0: + printf("程序退出\n"); + return 0; + default: + printf("无效选择,请重新输入\n"); + break; + } + } + + return 0; +} \ No newline at end of file diff --git a/exercise/13.c b/exercise/13.c new file mode 100644 index 0000000..9e50069 --- /dev/null +++ b/exercise/13.c @@ -0,0 +1,136 @@ +#ifdef _WIN32 +#include +#include +#endif +#include +#include + +// 二叉树节点定义 +typedef struct BiTNode { + char data; + struct BiTNode *lchild; + struct BiTNode *rchild; +} BiTNode, *BiTree; + +static void CreateBiTree(BiTree *T) { + char ch; + if (scanf(" %c", &ch) != 1) { + *T = NULL; + return; + } + if (ch == '#') { + *T = NULL; + } else { + *T = (BiTNode *)malloc(sizeof(BiTNode)); + if (!*T) { + fprintf(stderr, "内存分配失败\n"); + exit(EXIT_FAILURE); + } + (*T)->data = ch; + CreateBiTree(&(*T)->lchild); + CreateBiTree(&(*T)->rchild); + } +} + +static void PreOrderTraverse(BiTree T) { + if (T) { + putchar(T->data); + putchar(' '); + PreOrderTraverse(T->lchild); + PreOrderTraverse(T->rchild); + } +} + +static void InOrderTraverse(BiTree T) { + if (T) { + InOrderTraverse(T->lchild); + putchar(T->data); + putchar(' '); + InOrderTraverse(T->rchild); + } +} + +static void PostOrderTraverse(BiTree T) { + if (T) { + PostOrderTraverse(T->lchild); + PostOrderTraverse(T->rchild); + putchar(T->data); + putchar(' '); + } +} + +static void DestroyTree(BiTree T) { + if (!T) return; + DestroyTree(T->lchild); + DestroyTree(T->rchild); + free(T); +} + +static void PrintMenu(void) { + printf("\n--- 选择遍历方式 ---\n"); + printf("1. 先序遍历\n"); + printf("2. 中序遍历\n"); + printf("3. 后序遍历\n"); + printf("4. 退出\n"); + printf("请输入选择 (1-4): "); +} + +int main() { + // 设置控制台编码为UTF-8,防止中文乱码 +#ifdef _WIN32 + system("chcp 65001 > nul"); // 设置控制台编码为UTF-8 + SetConsoleOutputCP(65001); // 设置控制台输出编码 + SetConsoleCP(65001); // 设置控制台输入编码 +#endif + + // 初始化二叉树 + BiTree T = NULL; + int choice = 0; + + printf("=== 链式二叉树遍历系统 ===\n"); + printf("请输入先序扩展序列构建二叉树(# 表示空节点,例如 AB#C##D##):\n"); + // 构建二叉树 + CreateBiTree(&T); + + // 主循环处理用户选择 + while (choice != 4) + { + PrintMenu(); + if (scanf("%d", &choice) != 1) + { + fprintf(stderr, "输入错误,程序结束。\n"); + break; + } + switch (choice) + { + case 1: + // 先序遍历 + printf("先序遍历结果: "); + PreOrderTraverse(T); + putchar('\n'); + break; + case 2: + // 中序遍历 + printf("中序遍历结果: "); + InOrderTraverse(T); + putchar('\n'); + break; + case 3: + // 后序遍历 + printf("后序遍历结果: "); + PostOrderTraverse(T); + putchar('\n'); + break; + case 4: + printf("程序已退出。\n"); + break; + default: + printf("无效输入,请输入 1~4 之间的数字!\n"); + } + } + + // 销毁二叉树 + DestroyTree(T); + + return 0; +} \ No newline at end of file diff --git a/exercise/14.c b/exercise/14.c new file mode 100644 index 0000000..2efd7de --- /dev/null +++ b/exercise/14.c @@ -0,0 +1,42 @@ +// 二叉树先序遍历(给出每个结点的左右孩子编号) +// 输入:n,随后 n 行,每行两个整数 l、r 表示结点 i 的左右孩子编号(0 表示空) +// 根节点固定为 1。输出:先序遍历序列(每个数字后均有一个空格)。 + +#include +#include + +int main(void) { + int n; + if (scanf("%d", &n) != 1) return 0; + + int *L = (int *)malloc((n + 1) * sizeof(int)); + int *R = (int *)malloc((n + 1) * sizeof(int)); + if (!L || !R) return 0; + + for (int i = 1; i <= n; ++i) { + int l, r; + if (scanf("%d %d", &l, &r) != 2) { + free(L); free(R); + return 0; + } + L[i] = l; R[i] = r; + } + + // 迭代版先序遍历,避免最坏情况下递归栈溢出(n 可达 1e5) + int *stack = (int *)malloc((n + 1) * sizeof(int)); + int top = 0; + stack[top++] = 1; // 根节点编号为 1 + + while (top) { + int u = stack[--top]; + if (u == 0) continue; + printf("%d ", u); + // 先压右再压左,保证左子树先被访问 + if (R[u]) stack[top++] = R[u]; + if (L[u]) stack[top++] = L[u]; + } + + free(stack); + free(L); free(R); + return 0; +} \ No newline at end of file diff --git a/exercise/15.c b/exercise/15.c new file mode 100644 index 0000000..72f4300 --- /dev/null +++ b/exercise/15.c @@ -0,0 +1,43 @@ +// 二叉树中序遍历(给出每个结点的左右孩子编号,根为1) +// 输入:n,随后 n 行,每行两个整数 l、r(0 表示空)。 +// 输出:中序遍历序列,每个数字后均输出一个空格。 + +#include +#include + +int main(void) { + int n; + if (scanf("%d", &n) != 1) return 0; + + int *L = (int *)malloc((n + 1) * sizeof(int)); + int *R = (int *)malloc((n + 1) * sizeof(int)); + if (!L || !R) return 0; + + for (int i = 1; i <= n; ++i) { + int l, r; + if (scanf("%d %d", &l, &r) != 2) { + free(L); free(R); + return 0; + } + L[i] = l; R[i] = r; + } + + // 迭代式中序遍历:一路向左压栈,弹栈访问,再转向右子树 + int *stack = (int *)malloc((n + 1) * sizeof(int)); + int top = 0; + int cur = 1; // 根节点编号为 1 + + while (cur || top) { + while (cur) { // 沿左链入栈 + stack[top++] = cur; + cur = L[cur]; + } + int u = stack[--top]; + printf("%d ", u); + cur = R[u]; + } + + free(stack); + free(L); free(R); + return 0; +} \ No newline at end of file diff --git a/exercise/16.c b/exercise/16.c new file mode 100644 index 0000000..a8d1f55 --- /dev/null +++ b/exercise/16.c @@ -0,0 +1,49 @@ +// 二叉树后序遍历(给出每个结点的左右孩子编号,根为1) +// 输入:n,随后 n 行,每行两个整数 l、r(0 表示空)。 +// 输出:后序遍历序列,每个数字后均输出一个空格。 + +#include +#include + +int main(void) { + int n; + if (scanf("%d", &n) != 1) return 0; + + int *L = (int *)malloc((n + 1) * sizeof(int)); + int *R = (int *)malloc((n + 1) * sizeof(int)); + if (!L || !R) return 0; + + for (int i = 1; i <= n; ++i) { + int l, r; + if (scanf("%d %d", &l, &r) != 2) { + free(L); free(R); + return 0; + } + L[i] = l; R[i] = r; + } + + // 迭代式后序遍历:使用两个栈 + // 栈1:根右左;栈2:左右根(输出时弹出栈2) + int *s1 = (int *)malloc((n + 1) * sizeof(int)); + int *s2 = (int *)malloc((n + 1) * sizeof(int)); + int t1 = 0, t2 = 0; + + s1[t1++] = 1; // 根节点为 1 + while (t1) { + int u = s1[--t1]; + if (u == 0) continue; + s2[t2++] = u; + // 先压左,再压右,使栈2形成 左右根 的逆序 + if (L[u]) s1[t1++] = L[u]; + if (R[u]) s1[t1++] = R[u]; + } + + while (t2) { + int u = s2[--t2]; + printf("%d ", u); + } + + free(s1); free(s2); + free(L); free(R); + return 0; +} \ No newline at end of file diff --git a/exercise/17.c b/exercise/17.c new file mode 100644 index 0000000..5c5250d --- /dev/null +++ b/exercise/17.c @@ -0,0 +1,41 @@ +// 非递归先序遍历(给出每个结点的左右孩子编号,根为1) +// 输入:n,随后 n 行,每行两个整数 l、r(0 表示无孩子)。 +// 输出:先序遍历序列,每个数字后均输出一个空格。 + +#include +#include + +int main(void) { + int n; + if (scanf("%d", &n) != 1) return 0; + + int *L = (int *)malloc((n + 1) * sizeof(int)); + int *R = (int *)malloc((n + 1) * sizeof(int)); + if (!L || !R) return 0; + + for (int i = 1; i <= n; ++i) { + int l, r; + if (scanf("%d %d", &l, &r) != 2) { + free(L); free(R); + return 0; + } + L[i] = l; R[i] = r; + } + + // 迭代版先序遍历:使用一个栈,根开始;弹出访问当前结点,先压右再压左 + int *stack = (int *)malloc((n + 1) * sizeof(int)); + int top = 0; + stack[top++] = 1; // 根节点为 1 + + while (top) { + int u = stack[--top]; + if (u == 0) continue; + printf("%d ", u); + if (R[u]) stack[top++] = R[u]; + if (L[u]) stack[top++] = L[u]; + } + + free(stack); + free(L); free(R); + return 0; +} \ No newline at end of file diff --git a/exercise/18.c b/exercise/18.c new file mode 100644 index 0000000..141edef --- /dev/null +++ b/exercise/18.c @@ -0,0 +1,43 @@ +// 非递归中序遍历。给出每个结点的左右孩子编号,根为 1。 +// 输入:n,随后 n 行,每行两个整数 l、r(0 表示无孩子)。 +// 输出:中序遍历序列,每个数字后均输出一个空格。 + +#include +#include + +int main(void) { + int n; + if (scanf("%d", &n) != 1) return 0; + + int *L = (int *)malloc((n + 1) * sizeof(int)); + int *R = (int *)malloc((n + 1) * sizeof(int)); + if (!L || !R) return 0; + + for (int i = 1; i <= n; ++i) { + int l, r; + if (scanf("%d %d", &l, &r) != 2) { + free(L); free(R); + return 0; + } + L[i] = l; R[i] = r; + } + + // 非递归中序遍历(栈) + int *stack = (int *)malloc((n + 1) * sizeof(int)); + int top = 0; + int cur = 1; // 根结点为 1 + + while (cur || top) { + while (cur) { // 沿左链压栈 + stack[top++] = cur; + cur = L[cur]; + } + int u = stack[--top]; // 访问栈顶 + printf("%d ", u); + cur = R[u]; // 转向右子树 + } + + free(stack); + free(L); free(R); + return 0; +} \ No newline at end of file diff --git a/exercise/19.c b/exercise/19.c new file mode 100644 index 0000000..0be4a47 --- /dev/null +++ b/exercise/19.c @@ -0,0 +1,52 @@ +// 非递归后序遍历(给出每个结点的左右孩子编号,根为1) +// 输入:n,随后 n 行,每行两个整数 l、r(0 表示无孩子)。 +// 输出:后序遍历序列,每个数字后均输出一个空格。 + +#include +#include + +int main(void) { + int n; + if (scanf("%d", &n) != 1) return 0; + + int *L = (int *)malloc((n + 1) * sizeof(int)); + int *R = (int *)malloc((n + 1) * sizeof(int)); + if (!L || !R) return 0; + + for (int i = 1; i <= n; ++i) { + int l, r; + if (scanf("%d %d", &l, &r) != 2) { + free(L); free(R); + return 0; + } + L[i] = l; R[i] = r; + } + + // 单栈 + 最近访问标记 实现后序遍历 + int *stack = (int *)malloc((n + 1) * sizeof(int)); + int top = 0; + int cur = 1; // 根结点编号为 1 + int prev = 0; // 最近一次输出的结点编号 + + while (cur || top) { + if (cur) { + stack[top++] = cur; + cur = L[cur]; // 沿左链压栈 + } else { + int u = stack[top - 1]; + // 若右子树存在且未被处理,则转向右子树 + if (R[u] && prev != R[u]) { + cur = R[u]; + } else { + // 右子树为空或已处理,弹栈并输出该结点 + --top; + printf("%d ", u); + prev = u; + } + } + } + + free(stack); + free(L); free(R); + return 0; +} \ No newline at end of file diff --git a/exercise/2.c b/exercise/2.c new file mode 100644 index 0000000..18d5aed --- /dev/null +++ b/exercise/2.c @@ -0,0 +1,50 @@ +// 题目描述 +// 给定一个只包括(,) +// ,{,} ,[,] 的字符串 +// s +// s ,判断字符串是否有效。 +// 有效字符串需满足: + +// 左括号必须用相同类型的右括号闭合。 +// 左括号必须以正确的顺序闭合。 +// 每个右括号都有一个对应的相同类型的左括号。 +// 输入 +// 输入一个字符串 +// s + +// ( +// 1 +// ≤ s +// ≤ 10 4) +// s(1≤s≤10 4)。 + +// 输出 +// 有效字符串输出 true,否则输出 false。 + +// 样例 +// 输入 #1 复制代码() +// 输出 #1 复制代码 +// true 输入 #2 复制代码()[] +// { +// } +// 输出 #2 +// 复制代码 +// true +// 输入 #3 +// 复制代码 +// (] +// 输出 #3 +// 复制代码 +// false +// 输入 #4 +// 复制代码 +// ([]) +// 输出 #4 +// 复制代码 +// true +// 输入 #5 +// 复制代码 +// ()[{]} +// 输出 #5 +// 复制代码 +// diff --git a/exercise/20.c b/exercise/20.c new file mode 100644 index 0000000..6ab0a9a --- /dev/null +++ b/exercise/20.c @@ -0,0 +1,44 @@ +// 非递归层序遍历(BFS)(给出每个结点的左右孩子编号,根为1) +// 输入:n,随后 n 行,每行两个整数 l、r(0 表示无孩子)。 +// 输出:层序遍历序列,每个数字后均输出一个空格。 + +#include +#include + +int main(void) { + int n; + if (scanf("%d", &n) != 1) return 0; + + if (n <= 0) return 0; + + int *L = (int *)malloc((n + 1) * sizeof(int)); + int *R = (int *)malloc((n + 1) * sizeof(int)); + if (!L || !R) return 0; + + for (int i = 1; i <= n; ++i) { + int l, r; + if (scanf("%d %d", &l, &r) != 2) { + free(L); free(R); + return 0; + } + L[i] = l; R[i] = r; + } + + // 队列 BFS,从根 1 开始,左到右按层输出 + int *q = (int *)malloc((n + 1) * sizeof(int)); + if (!q) { free(L); free(R); return 0; } + int head = 0, tail = 0; + + q[tail++] = 1; // 根节点为 1 + while (head < tail) { + int u = q[head++]; + if (u == 0) continue; + printf("%d ", u); + if (L[u]) q[tail++] = L[u]; + if (R[u]) q[tail++] = R[u]; + } + + free(q); + free(L); free(R); + return 0; +} \ No newline at end of file diff --git a/exercise/21.c b/exercise/21.c new file mode 100644 index 0000000..77fdd2c --- /dev/null +++ b/exercise/21.c @@ -0,0 +1,88 @@ +// 前序线索二叉树构建(根为1) +// 输入:n,随后 n 行,每行两个整数 l、r(0 表示无孩子)。 +// 输出:n 行,每行四个整数:lchild(i) ltag(i) rchild(i) rtag(i) +// 规则: +// - 若有左儿子:ltag(i)=0,lchild(i) 为左儿子编号;否则 ltag(i)=1,lchild(i) 为前序前驱,无前驱为 -2。 +// - 若有右儿子:rtag(i)=0,rchild(i) 为右儿子编号;否则 rtag(i)=1,rchild(i) 为前序后继,无后继为 -1。 + +#include +#include + +int main(void) { + int n; + if (scanf("%d", &n) != 1) return 0; + if (n <= 0) return 0; + + int *L = (int *)malloc((n + 1) * sizeof(int)); + int *R = (int *)malloc((n + 1) * sizeof(int)); + if (!L || !R) return 0; + + for (int i = 1; i <= n; ++i) { + int l, r; + if (scanf("%d %d", &l, &r) != 2) { + free(L); free(R); + return 0; + } + L[i] = l; R[i] = r; + } + + // 迭代前序遍历,生成访问序列 order + int *stack = (int *)malloc((n + 1) * sizeof(int)); + int *order = (int *)malloc(n * sizeof(int)); + if (!stack || !order) { free(L); free(R); return 0; } + int top = 0, k = 0; + + stack[top++] = 1; // 根为 1 + while (top) { + int u = stack[--top]; + if (u == 0) continue; + order[k++] = u; + if (R[u]) stack[top++] = R[u]; + if (L[u]) stack[top++] = L[u]; + } + + // 位置映射:pos[node] = 在前序序列中的索引 + int *pos = (int *)malloc((n + 1) * sizeof(int)); + if (!pos) { free(stack); free(order); free(L); free(R); return 0; } + for (int i = 1; i <= n; ++i) pos[i] = -1; + for (int i = 0; i < k; ++i) pos[order[i]] = i; + + // 输出域与标记域 + int *outL = (int *)malloc((n + 1) * sizeof(int)); + int *ltag = (int *)malloc((n + 1) * sizeof(int)); + int *outR = (int *)malloc((n + 1) * sizeof(int)); + int *rtag = (int *)malloc((n + 1) * sizeof(int)); + if (!outL || !ltag || !outR || !rtag) { + free(pos); free(stack); free(order); free(L); free(R); + return 0; + } + + for (int i = 1; i <= n; ++i) { + if (L[i]) { // 有左儿子 + ltag[i] = 0; + outL[i] = L[i]; + } else { // 无左儿子,线索到前序前驱 + ltag[i] = 1; + if (pos[i] > 0) outL[i] = order[pos[i] - 1]; + else outL[i] = -2; // 无前驱 + } + + if (R[i]) { // 有右儿子 + rtag[i] = 0; + outR[i] = R[i]; + } else { // 无右儿子,线索到前序后继 + rtag[i] = 1; + if (pos[i] >= 0 && pos[i] < k - 1) outR[i] = order[pos[i] + 1]; + else outR[i] = -1; // 无后继 + } + } + + for (int i = 1; i <= n; ++i) { + printf("%d %d %d %d\n", outL[i], ltag[i], outR[i], rtag[i]); + } + + free(outL); free(ltag); free(outR); free(rtag); + free(pos); free(stack); free(order); + free(L); free(R); + return 0; +} \ No newline at end of file diff --git a/exercise/22.c b/exercise/22.c new file mode 100644 index 0000000..a38b276 --- /dev/null +++ b/exercise/22.c @@ -0,0 +1,91 @@ +// 中序线索二叉树构建(根为1) +// 输入:n,随后 n 行,每行两个整数 l、r(0 表示无孩子)。 +// 输出:n 行,每行四个整数:lchild(i) ltag(i) rchild(i) rtag(i) +// 规则: +// - 若有左儿子:ltag(i)=0,lchild(i) 为左儿子编号;否则 ltag(i)=1,lchild(i) 为中序前驱,无前驱为 -2。 +// - 若有右儿子:rtag(i)=0,rchild(i) 为右儿子编号;否则 rtag(i)=1,rchild(i) 为中序后继,无后继为 -1。 + +#include +#include + +int main(void) { + int n; + if (scanf("%d", &n) != 1) return 0; + if (n <= 0) return 0; + + int *L = (int *)malloc((n + 1) * sizeof(int)); + int *R = (int *)malloc((n + 1) * sizeof(int)); + if (!L || !R) return 0; + + for (int i = 1; i <= n; ++i) { + int l, r; + if (scanf("%d %d", &l, &r) != 2) { + free(L); free(R); + return 0; + } + L[i] = l; R[i] = r; + } + + // 迭代中序遍历,生成访问序列 order + int *stack = (int *)malloc((n + 1) * sizeof(int)); + int *order = (int *)malloc(n * sizeof(int)); + if (!stack || !order) { free(L); free(R); return 0; } + int top = 0, k = 0; + + int cur = 1; // 根为 1 + while (cur || top) { + if (cur) { + stack[top++] = cur; + cur = L[cur]; + } else { + int u = stack[--top]; + order[k++] = u; + cur = R[u]; + } + } + + // 位置映射:pos[node] = 在中序序列中的索引 + int *pos = (int *)malloc((n + 1) * sizeof(int)); + if (!pos) { free(stack); free(order); free(L); free(R); return 0; } + for (int i = 1; i <= n; ++i) pos[i] = -1; + for (int i = 0; i < k; ++i) pos[order[i]] = i; + + // 输出域与标记域 + int *outL = (int *)malloc((n + 1) * sizeof(int)); + int *ltag = (int *)malloc((n + 1) * sizeof(int)); + int *outR = (int *)malloc((n + 1) * sizeof(int)); + int *rtag = (int *)malloc((n + 1) * sizeof(int)); + if (!outL || !ltag || !outR || !rtag) { + free(pos); free(stack); free(order); free(L); free(R); + return 0; + } + + for (int i = 1; i <= n; ++i) { + if (L[i]) { // 有左儿子 + ltag[i] = 0; + outL[i] = L[i]; + } else { // 无左儿子,线索到中序前驱 + ltag[i] = 1; + if (pos[i] > 0) outL[i] = order[pos[i] - 1]; + else outL[i] = -2; // 无前驱 + } + + if (R[i]) { // 有右儿子 + rtag[i] = 0; + outR[i] = R[i]; + } else { // 无右儿子,线索到中序后继 + rtag[i] = 1; + if (pos[i] >= 0 && pos[i] < k - 1) outR[i] = order[pos[i] + 1]; + else outR[i] = -1; // 无后继 + } + } + + for (int i = 1; i <= n; ++i) { + printf("%d %d %d %d\n", outL[i], ltag[i], outR[i], rtag[i]); + } + + free(outL); free(ltag); free(outR); free(rtag); + free(pos); free(stack); free(order); + free(L); free(R); + return 0; +} \ No newline at end of file diff --git a/exercise/23.c b/exercise/23.c new file mode 100644 index 0000000..7e421de --- /dev/null +++ b/exercise/23.c @@ -0,0 +1,98 @@ +// 后序线索二叉树构建(根为1) +// 输入:n,随后 n 行,每行两个整数 l、r(0 表示无孩子)。 +// 输出:n 行,每行四个整数:lchild(i) ltag(i) rchild(i) rtag(i) +// 规则: +// - 若有左儿子:ltag(i)=0,lchild(i) 为左儿子编号;否则 ltag(i)=1,lchild(i) 为后序前驱,无前驱为 -2。 +// - 若有右儿子:rtag(i)=0,rchild(i) 为右儿子编号;否则 rtag(i)=1,rchild(i) 为后序后继,无后继为 -1。 + +#include +#include + +int main(void) { + int n; + if (scanf("%d", &n) != 1) return 0; + if (n <= 0) return 0; + + int *L = (int *)malloc((n + 1) * sizeof(int)); + int *R = (int *)malloc((n + 1) * sizeof(int)); + if (!L || !R) return 0; + + for (int i = 1; i <= n; ++i) { + int l, r; + if (scanf("%d %d", &l, &r) != 2) { + free(L); free(R); + return 0; + } + L[i] = l; R[i] = r; + } + + // 迭代后序遍历,生成访问序列 order + int *stack = (int *)malloc((n + 1) * sizeof(int)); + int *order = (int *)malloc(n * sizeof(int)); + if (!stack || !order) { free(L); free(R); return 0; } + int top = 0, k = 0; + + int cur = 1; // 根为 1 + int prev = 0; // 最近已输出的结点 + while (cur || top) { + if (cur) { + stack[top++] = cur; + cur = L[cur]; // 沿左链压栈 + } else { + int u = stack[top - 1]; + if (R[u] && prev != R[u]) { + cur = R[u]; // 右子树存在且未处理,转向右子树 + } else { + // 右子树为空或已处理,弹栈并记录该结点 + --top; + order[k++] = u; + prev = u; + } + } + } + + // 位置映射:pos[node] = 在后序序列中的索引 + int *pos = (int *)malloc((n + 1) * sizeof(int)); + if (!pos) { free(stack); free(order); free(L); free(R); return 0; } + for (int i = 1; i <= n; ++i) pos[i] = -1; + for (int i = 0; i < k; ++i) pos[order[i]] = i; + + // 输出域与标记域 + int *outL = (int *)malloc((n + 1) * sizeof(int)); + int *ltag = (int *)malloc((n + 1) * sizeof(int)); + int *outR = (int *)malloc((n + 1) * sizeof(int)); + int *rtag = (int *)malloc((n + 1) * sizeof(int)); + if (!outL || !ltag || !outR || !rtag) { + free(pos); free(stack); free(order); free(L); free(R); + return 0; + } + + for (int i = 1; i <= n; ++i) { + if (L[i]) { // 有左儿子 + ltag[i] = 0; + outL[i] = L[i]; + } else { // 无左儿子,线索到后序前驱 + ltag[i] = 1; + if (pos[i] > 0) outL[i] = order[pos[i] - 1]; + else outL[i] = -2; // 无前驱 + } + + if (R[i]) { // 有右儿子 + rtag[i] = 0; + outR[i] = R[i]; + } else { // 无右儿子,线索到后序后继 + rtag[i] = 1; + if (pos[i] >= 0 && pos[i] < k - 1) outR[i] = order[pos[i] + 1]; + else outR[i] = -1; // 无后继 + } + } + + for (int i = 1; i <= n; ++i) { + printf("%d %d %d %d\n", outL[i], ltag[i], outR[i], rtag[i]); + } + + free(outL); free(ltag); free(outR); free(rtag); + free(pos); free(stack); free(order); + free(L); free(R); + return 0; +} \ No newline at end of file diff --git a/exercise/24.c b/exercise/24.c new file mode 100644 index 0000000..2b221d8 --- /dev/null +++ b/exercise/24.c @@ -0,0 +1,209 @@ +#include +#include +#include +#ifdef _WIN32 +#include +#include +#endif + +// 栈结构定义 +typedef struct +{ + long long *data; + int top; + int capacity; +} Stack; + +// 栈初始化 +void stack_init(Stack *st, int initial_capacity) +{ + int cap = initial_capacity > 0 ? initial_capacity : 2; + + st->data = (long long *)malloc(sizeof(long long) * cap); + st->top = 0; + st->capacity = cap; +} + +// 栈释放 +void stack_free(Stack *st) +{ + free(st->data); + st->data = NULL; + st->top = 0; + st->capacity = 0; +} + +// 栈是否为空 +int stack_empty(const Stack *st) +{ + return st->top == 0; +} + +// 栈压栈 +void stack_push(Stack *st, long long v) +{ + if (st->top >= st->capacity) + { + int new_cap = st->capacity ? st->capacity * 2 : 2; + long long *nd = (long long *)realloc(st->data, sizeof(long long) * new_cap); + if (!nd) + { + free(st->data); + exit(0); + } + st->data = nd; + st->capacity = new_cap; + } + st->data[st->top++] = v; +} + +// 栈弹栈 +long long stack_pop(Stack *st) +{ + if (st->top == 0) + { + return 0; + } + return st->data[--st->top]; +} + +// 栈顶元素 +long long stack_top(const Stack *st) +{ + if (st->top == 0) + { + return 0; + } + return st->data[st->top - 1]; +} + +int main(void) +{ + // 设置控制台编码为UTF-8,防止中文乱码 +#ifdef _WIN32 + system("chcp 65001 > nul"); // 设置控制台编码为UTF-8 + SetConsoleOutputCP(65001); // 设置控制台输出编码 + SetConsoleCP(65001); // 设置控制台输入编码 +#endif + + // 动态读取一行表达式 + size_t cap = 1024, len = 0; + char *s = (char *)malloc(cap); + if (!s) + return 0; + int ch; + // 读取表达式 + while ((ch = getchar()) != EOF && ch != '\n') + { + if (len + 1 >= cap) + { + // 容量不足时,倍增扩容 + cap <<= 1; + char *ns = (char *)realloc(s, cap); + if (!ns) + { + free(s); + return 0; + } + s = ns; + } + // 逐字符写入 + s[len++] = (char)ch; + } + s[len] = '\0'; + if (len == 0) + { + free(s); + return 0; + } + + Stack st; + stack_init(&st, (int)len + 1); + + long long num = 0; + // 记录最近的运算符,初始为加号 + char op = '+'; + + for (size_t i = 0; i < len; ++i) + { + char c = s[i]; + // 跳过空格字符 + if (isspace((unsigned char)c)) + continue; + + if (isdigit((unsigned char)c)) + { + // 累积多位数字 + num = num * 10 + (c - '0'); + } + else + { + // 根据“前一个”运算符 op 处理当前数字 num; + // 乘除即时计算以确保高于加减的优先级 + switch (op) + { + case '+': + stack_push(&st, num); + break; + case '-': + stack_push(&st, -num); + break; + case '*': + { + long long a = stack_pop(&st); + stack_push(&st, a * num); + break; + } + case '/': + { + long long a = stack_pop(&st); + stack_push(&st, a / num); + break; + } + default: + break; + } + // 更新待应用的运算符为当前位置字符 + op = c; + // 重置当前数字,继续解析 + num = 0; + } + } + + // 处理末尾累积数字(循环结束后最后一个数尚未被处理) + switch (op) + { + case '+': + stack_push(&st, num); + break; + case '-': + stack_push(&st, -num); + break; + case '*': + { + long long a = stack_pop(&st); + stack_push(&st, a * num); + break; + } + case '/': + { + long long a = stack_pop(&st); + // C 的整数除法向零截断 + stack_push(&st, a / num); + break; + } + default: + break; + } + + long long ans = 0; + // 栈中为已应用乘除的加减项,累加得到结果 + while (!stack_empty(&st)) + ans += stack_pop(&st); + + printf("%lld\n", ans); + + stack_free(&st); + free(s); + return 0; +} \ No newline at end of file diff --git a/exercise/25.c b/exercise/25.c new file mode 100644 index 0000000..49bbd1b --- /dev/null +++ b/exercise/25.c @@ -0,0 +1,86 @@ +#include +#include +#include +#ifdef _WIN32 +#include +#include +#endif + +// 简单环形队列 +typedef struct +{ + int *buf; + int cap; + int head; + int tail; + int len; +} Queue; + +static void q_init(Queue *q, int cap) +{ + q->buf = (int *)malloc(sizeof(int) * cap); + q->cap = cap; + q->head = 0; + q->tail = 0; + q->len = 0; +} + +static int q_empty(const Queue *q) { return q->len == 0; } + +static void q_push(Queue *q, int x) +{ + q->buf[q->tail] = x; + q->tail = (q->tail + 1) % q->cap; + q->len++; +} + +static int q_pop(Queue *q) +{ + int x = q->buf[q->head]; + q->head = (q->head + 1) % q->cap; + q->len--; + return x; +} + +static void q_free(Queue *q) +{ + free(q->buf); + q->buf = NULL; + q->cap = q->head = q->tail = q->len = 0; +} + +int main(void) +{ + // 设置控制台编码为UTF-8,防止中文乱码 +#ifdef _WIN32 + system("chcp 65001 > nul"); // 设置控制台编码为UTF-8 + SetConsoleOutputCP(65001); // 设置控制台输出编码 + SetConsoleCP(65001); // 设置控制台输入编码 +#endif + + int n, m; + if (scanf("%d %d", &n, &m) != 2) + return 0; + if (n <= 0 || m <= 0) + return 0; + + Queue q; + q_init(&q, n); + for (int i = 1; i <= n; ++i) + q_push(&q, i); + + while (!q_empty(&q)) + { + // 旋转 m-1 次:把队头移动到队尾(取模优化减少旋转次数) + int k = (m - 1) % q.len; + for (int t = 0; t < k; ++t) + { + q_push(&q, q_pop(&q)); + } + int out = q_pop(&q); + printf("%d\n", out); + } + + q_free(&q); + return 0; +} \ No newline at end of file diff --git a/exercise/26.c b/exercise/26.c new file mode 100644 index 0000000..5405ae6 --- /dev/null +++ b/exercise/26.c @@ -0,0 +1,108 @@ +#include +#include +#include +#ifdef _WIN32 +#include +#include +#endif + +// 简单环形队列 +typedef struct +{ + int *buf; // 队列缓冲区 + int cap; // 队列容量 + int head; // 队头指针 + int tail; // 队尾指针 + int len; // 当前队列长度 +} Queue; + +// 初始化队列 +static void Queue_init(Queue *q, int cap) +{ + q->buf = (int *)malloc(sizeof(int) * cap); + q->cap = cap; + q->head = 0; + q->tail = 0; + q->len = 0; +} + +// 检查队列是否为空 +static int Queue_empty(const Queue *q) +{ + return q->len == 0; +} + +// 入队操作 +static void Queue_push(Queue *q, int x) +{ + q->buf[q->tail] = x; + q->tail = (q->tail + 1) % q->cap; + q->len++; +} + +// 弹出队列元素 +static int Queue_pop(Queue *q) +{ + int x = q->buf[q->head]; + q->head = (q->head + 1) % q->cap; + q->len--; + return x; +} + +// 释放队列内存(避免与标准库 free 冲突) +static void Queue_free(Queue *q) +{ + free(q->buf); + q->buf = NULL; + q->cap = 0; + q->head = 0; + q->tail = 0; + q->len = 0; +} + +int main(void) +{ + // 设置控制台编码为UTF-8,防止中文乱码 +#ifdef _WIN32 + system("chcp 65001 > nul"); // 设置控制台编码为UTF-8 + SetConsoleOutputCP(65001); // 设置控制台输出编码 + SetConsoleCP(65001); // 设置控制台输入编码 +#endif + + int n, m; + printf("请输入约瑟夫环的人数n和报数m: "); + scanf("%d %d", &n, &m); + if (n < 8 || n > 15 || m < 5 || m > 32767) + { + printf("输入错误,请重新输入!\n"); + printf("请重输入约瑟夫环的人数n和报数m: "); + scanf("%d %d", &n, &m); + } + + // 初始化队列 + Queue q; + Queue_init(&q, n); + + // 入队操作 + for (int i = 0; i < n; i++) + { + Queue_push(&q, i + 1); + } + + // 出队操作:模拟报数过程 + while (!Queue_empty(&q)) + { + // 旋转 m-1 次:把队头移动到队尾(取模优化减少旋转次数) + int k = (m - 1) % q.len; + for (int t = 0; t < k; ++t) + { + Queue_push(&q, Queue_pop(&q)); + } + int out = Queue_pop(&q); + printf("%d ", out); + } + + // 释放队列内存 + Queue_free(&q); + return 0; +} \ No newline at end of file diff --git a/exercise/27.c b/exercise/27.c new file mode 100644 index 0000000..453c401 --- /dev/null +++ b/exercise/27.c @@ -0,0 +1,116 @@ +#include +#include + +// 目标:在允许使用容量为 c 的栈缓冲的前提下, +// 将输入序列(商店从上到下)重排为字典序最小的最终堆叠(从下到上)。 +// 操作等价于:依次读取输入;每次要么将下一个元素压入栈(若未满),要么从栈顶弹出到输出; +// 栈容量不超过 c;输出顺序即为最终堆叠的自下而上的编号。 + +int main(void) +{ + int n, c; + if (scanf("%d %d", &n, &c) != 2) + return 0; + int *a = (int *)malloc(sizeof(int) * n); + for (int i = 0; i < n; ++i) + scanf("%d", &a[i]); + + // 栈缓冲(手上带着的箱子),存储值 + int *stk = (int *)malloc(sizeof(int) * n); + int len = 0; // 当前栈大小 + + // 单调队列(维护接下来可压入窗口中的最小值及其位置) + int *dq_val = (int *)malloc(sizeof(int) * n); + int *dq_idx = (int *)malloc(sizeof(int) * n); + int dq_head = 0, dq_tail = 0; // [head, tail) 有效 + + int i = 0; // 下一个待读取的输入位置 + int j = 0; // 已加入单调队列的输入位置(下一个待加入的位置) + int out_cnt = 0; + + while (out_cnt < n) + { + // 计算当前还能压入的最大数量 R(窗口大小) + int R = c - len; + if (R < 0) + R = 0; + + // 扩充单调队列,使其覆盖 [i, min(i+R-1, n-1)] + while (j < n && j < i + R) + { + int v = a[j]; + while (dq_tail > dq_head && dq_val[dq_tail - 1] > v) + --dq_tail; + dq_val[dq_tail] = v; + dq_idx[dq_tail] = j; + ++dq_tail; + ++j; + } + + // 若栈非空,比较栈顶与窗口内最小值,决定弹出还是继续压入到最小值位置 + if (len > 0) + { + int top = stk[len - 1]; + int hasUpcoming = (dq_tail > dq_head); + int minUpcoming = hasUpcoming ? dq_val[dq_head] : 2147483647; // INF + if (!hasUpcoming || top <= minUpcoming) + { + // 栈顶不大于可达窗口中的最小值(或无可压入项),弹出栈顶到输出 + printf("%d", top); + ++out_cnt; + if (out_cnt < n) + putchar(' '); + --len; + continue; + } + } + + // 否则(栈为空或栈顶较大且尚有可压入项),把队列窗口的最小值所在位置的元素压入到栈顶,然后立即弹出 + if (dq_tail > dq_head) + { + int target_pos = dq_idx[dq_head]; + // 逐个压入直到到达 target_pos + while (i <= target_pos) + { + stk[len++] = a[i++]; + } + // 清理队列中过期项(索引 < i 的) + while (dq_tail > dq_head && dq_idx[dq_head] < i) + ++dq_head; + + // 弹出刚压入的最小值 + int val = stk[len - 1]; + printf("%d", val); + ++out_cnt; + if (out_cnt < n) + putchar(' '); + --len; + } + else + { + // 没有可压入项,但仍需输出 -> 只能弹出栈顶 + if (len > 0) + { + int val = stk[len - 1]; + printf("%d", val); + ++out_cnt; + if (out_cnt < n) + putchar(' '); + --len; + } + else + { + // 理论上不会到这里(既无可压入项又无栈元素),为安全直接中断 + break; + } + } + } + + putchar('\n'); + + free(a); + free(stk); + free(dq_val); + free(dq_idx); + return 0; +} \ No newline at end of file diff --git a/exercise/28.c b/exercise/28.c new file mode 100644 index 0000000..14be9be --- /dev/null +++ b/exercise/28.c @@ -0,0 +1,84 @@ +#include +#include + +typedef struct { + int *data; + int *mins; + int top; // index of next insertion in data + int mtop; // index of next insertion in mins + int cap; // capacity +} MinStack; + +static void ms_init(MinStack *s, int cap) { + s->data = (int *)malloc(sizeof(int) * cap); + s->mins = (int *)malloc(sizeof(int) * cap); + s->top = 0; + s->mtop = 0; + s->cap = cap; +} + +static int ms_empty(const MinStack *s) { return s->top == 0; } + +static void ms_push(MinStack *s, int x) { + // Assume total pushes won't exceed cap per problem constraints + s->data[s->top++] = x; + if (s->mtop == 0 || x <= s->mins[s->mtop - 1]) { + s->mins[s->mtop++] = x; + } +} + +static void ms_pop(MinStack *s) { + if (s->top == 0) return; // ignore if empty + int v = s->data[s->top - 1]; + s->top--; + if (s->mtop > 0 && v == s->mins[s->mtop - 1]) { + s->mtop--; + } +} + +static int ms_top(const MinStack *s) { + return s->data[s->top - 1]; +} + +static int ms_get_min(const MinStack *s) { + return s->mins[s->mtop - 1]; +} + +static void ms_free(MinStack *s) { + free(s->data); + free(s->mins); + s->data = s->mins = NULL; + s->top = s->mtop = s->cap = 0; +} + +int main(void) { + int n; + if (scanf("%d", &n) != 1) return 0; + MinStack st; + ms_init(&st, n > 0 ? n : 1); + + for (int i = 0; i < n; ++i) { + int t; + if (scanf("%d", &t) != 1) t = 0; + if (t == 1) { + int x; + scanf("%d", &x); + ms_push(&st, x); + } else if (t == 2) { + ms_pop(&st); + } else if (t == 3) { + if (!ms_empty(&st)) { + printf("%d\n", ms_top(&st)); + } + } else if (t == 4) { + if (!ms_empty(&st)) { + printf("%d\n", ms_get_min(&st)); + } + } else { + // ignore unknown command + } + } + + ms_free(&st); + return 0; +} \ No newline at end of file diff --git a/exercise/29.c b/exercise/29.c new file mode 100644 index 0000000..6247174 --- /dev/null +++ b/exercise/29.c @@ -0,0 +1,66 @@ +#include +#include +#include + +// 计算最长合法括号子串长度及数量(数量指达到该最长长度的子串个数) +// 使用经典 DP:dp[i] 表示以 i 结尾的最长合法括号长度。 +// 当 maxLen 为 0 时,按题意输出 "0 1"。 + +int main(void) +{ + const int MAXN = 1000005; // 题面最大长度约 1e6 + char *s = (char *)malloc(MAXN); + if (!s) return 0; + if (scanf("%1000000s", s) != 1) { + free(s); + return 0; + } + + int n = (int)strlen(s); + if (n == 0) { + printf("0 1\n"); + free(s); + return 0; + } + + int *dp = (int *)calloc(n, sizeof(int)); + if (!dp) { + free(s); + return 0; + } + + int maxLen = 0; + int count = 1; // 若最终 maxLen 为 0,答案应为 0 1 + + for (int i = 1; i < n; ++i) { + if (s[i] == ')') { + if (s[i - 1] == '(') { + dp[i] = 2 + (i >= 2 ? dp[i - 2] : 0); + } else { + int prev = i - dp[i - 1] - 1; + if (prev >= 0 && s[prev] == '(') { + dp[i] = dp[i - 1] + 2 + (prev >= 1 ? dp[prev - 1] : 0); + } + } + + if (dp[i] > 0) { + if (dp[i] > maxLen) { + maxLen = dp[i]; + count = 1; + } else if (dp[i] == maxLen) { + count++; + } + } + } + } + + if (maxLen == 0) { + printf("0 1\n"); + } else { + printf("%d %d\n", maxLen, count); + } + + free(dp); + free(s); + return 0; +} \ No newline at end of file diff --git a/exercise/3.c b/exercise/3.c new file mode 100644 index 0000000..1a4a9b4 --- /dev/null +++ b/exercise/3.c @@ -0,0 +1,53 @@ +#include + +int main() +{ + int T; + scanf("%d", &T); + + while (T--) + { + int N; + scanf("%d", &N); + + int a[10000]; + + // 读取序列 + for (int i = 0; i < N; i++) + { + scanf("%d", &a[i]); + } + + // 找最大值和最小值的位置 + int max_pos = 0, min_pos = 0; + for (int i = 0; i < N; i++) + { + if (a[i] > a[max_pos]) + { + max_pos = i; + } + if (a[i] < a[min_pos]) + { + min_pos = i; + } + } + + // 交换最大值和最小值 + int temp = a[max_pos]; + a[max_pos] = a[min_pos]; + a[min_pos] = temp; + + // 输出结果 + for (int i = 0; i < N; i++) + { + printf("%d", a[i]); + if (i < N - 1) + { + printf(" "); + } + } + printf("\n"); + } + + return 0; +} \ No newline at end of file diff --git a/exercise/30.c b/exercise/30.c new file mode 100644 index 0000000..8fb5cce --- /dev/null +++ b/exercise/30.c @@ -0,0 +1,65 @@ +#include +#include +#include + +// 语法: +// E := T ('|' T)* // 选择,取较长长度 +// T := F+ // 连接,长度相加 +// F := 'a' | '(' E ')' // 原子:一个 a 或括号组 +// 输出化简后(全为 a)的长度 + +static const char *s; +static int n, pos; + +static int parse_E(void); +static int parse_T(void); +static int parse_F(void); + +static int parse_E(void) +{ + int best = parse_T(); + while (pos < n && s[pos] == '|') { + ++pos; // consume '|' + int t = parse_T(); + if (t > best) best = t; + } + return best; +} + +static int parse_T(void) +{ + int sum = 0; + while (pos < n && s[pos] != ')' && s[pos] != '|') { + sum += parse_F(); + } + return sum; +} + +static int parse_F(void) +{ + if (pos < n && s[pos] == 'a') { + ++pos; + return 1; + } + if (pos < n && s[pos] == '(') { + ++pos; // consume '(' + int v = parse_E(); + if (pos < n && s[pos] == ')') ++pos; // consume ')' + return v; + } + // 理论上不会到达(保证输入合法且不含空串),安全返回 0 + return 0; +} + +int main(void) +{ + // 读取一行字符串(仅包含 a | ( )),长度不超过 1e5 + static char buf[1000005]; + if (scanf("%1000000s", buf) != 1) return 0; + s = buf; + n = (int)strlen(s); + pos = 0; + int ans = parse_E(); + printf("%d\n", ans); + return 0; +} \ No newline at end of file diff --git a/exercise/31.c b/exercise/31.c new file mode 100644 index 0000000..cdbd8a0 --- /dev/null +++ b/exercise/31.c @@ -0,0 +1,119 @@ +// 可随机访问的“栈”,支持按下标 O(1) 访问与快 I/O +// 操作: +// 1 x:压入整数 x +// 2:输出栈顶元素 +// 3 i:输出第 i 个元素(从 0 开始) +// 4:弹出栈顶元素 +// 约束:操作数最多 5,000,000;执行 3 时保证 i 有效 + +#include +#include +#include + +// 快读整数 +static inline int read_int(void) { + int c = getchar(); + while (c != EOF && (c == ' ' || c == '\n' || c == '\t' || c == '\r')) c = getchar(); + int sign = 1; + if (c == '-') { sign = -1; c = getchar(); } + int x = 0; + while (c >= '0' && c <= '9') { x = x * 10 + (c - '0'); c = getchar(); } + return sign * x; +} + +// 快速输出整数并换行 +static inline void write_int_ln(int x) { + char buf[32]; + char *p = buf + sizeof(buf); + *(--p) = '\n'; + unsigned int ux; + if (x < 0) { + ux = (unsigned int)(-(long long)x); + } else { + ux = (unsigned int)x; + } + do { + *(--p) = (char)('0' + (ux % 10)); + ux /= 10; + } while (ux); + if (x < 0) *(--p) = '-'; + fwrite(p, 1, (size_t)(buf + sizeof(buf) - p), stdout); +} + +typedef struct { + int *a; + size_t len; + size_t cap; +} RAStack; + +static inline void ras_init(RAStack *s) { + s->len = 0; + s->cap = 1024; // 初始容量 + s->a = (int*)malloc(s->cap * sizeof(int)); + if (!s->a) { + // 若内存紧张,回退到较小容量以继续运行 + s->cap = 16; + s->a = (int*)malloc(s->cap * sizeof(int)); + if (!s->a) exit(1); + } +} + +static inline void ras_reserve(RAStack *s, size_t need) { + if (need <= s->cap) return; + size_t new_cap = s->cap; + while (new_cap < need) { + // 约 1.5 倍扩容,以便在超大输入时节省内存 + new_cap = new_cap + (new_cap >> 1); + if (new_cap < s->cap + 1) new_cap = s->cap + 1; // 避免停滞 + } + int *na = (int*)realloc(s->a, new_cap * sizeof(int)); + if (!na) { + // 若 1.5 倍失败则尝试翻倍 + new_cap = s->cap * 2; + na = (int*)realloc(s->a, new_cap * sizeof(int)); + if (!na) exit(1); + } + s->a = na; + s->cap = new_cap; +} + +static inline void ras_push(RAStack *s, int x) { + if (s->len == s->cap) ras_reserve(s, s->len + 1); + s->a[s->len++] = x; +} + +static inline int ras_top(const RAStack *s) { + return s->a[s->len - 1]; +} + +static inline int ras_get(const RAStack *s, size_t i) { + return s->a[i]; // 从底部 0 开始计数 +} + +static inline void ras_pop(RAStack *s) { + --s->len; +} + +int main(void) { + RAStack st; + ras_init(&st); + + int n = read_int(); + for (int k = 0; k < n; ++k) { + int op = read_int(); + if (op == 1) { + int x = read_int(); + ras_push(&st, x); + } else if (op == 2) { + write_int_ln(ras_top(&st)); + } else if (op == 3) { + int i = read_int(); + write_int_ln(ras_get(&st, (size_t)i)); + } else if (op == 4) { + ras_pop(&st); + } + } + + free(st.a); + return 0; +} \ No newline at end of file diff --git a/exercise/32.c b/exercise/32.c new file mode 100644 index 0000000..b94c33e --- /dev/null +++ b/exercise/32.c @@ -0,0 +1,87 @@ +// 计算含运算符 '&'(取两数较小值)与 '|'(取两数较大值)的表达式 +// 两者同优先级,按从左到右结合;遇到括号优先计算括号内表达式。 +// 输入:一行字符串,仅由数字、&、|、(、) 组成 +// 输出:一个整数,表示表达式的值 + +#include +#include +#include +#include + +static inline int min_i(int a, int b) { return a < b ? a : b; } +static inline int max_i(int a, int b) { return a > b ? a : b; } + +static inline void apply_top(int *vals, int *vtop, char *ops, int *otop) { + char op = ops[--(*otop)]; + int b = vals[--(*vtop)]; + int a = vals[--(*vtop)]; + int r = (op == '&') ? min_i(a, b) : max_i(a, b); + vals[(*vtop)++] = r; +} + +int main(void) { + // 读取整行输入 + char *line = NULL; + size_t cap = 0; + { + // getline 若不可用则用 fgets 简易读取 + // Windows 平台无 getline,这里使用 fgets + size_t bufcap = 16384; // 大于题目约束的 10000 + line = (char*)malloc(bufcap); + if (!line) return 1; + if (!fgets(line, (int)bufcap, stdin)) return 0; + size_t len = strlen(line); + // 去掉行尾 CR/LF + while (len && (line[len-1] == '\n' || line[len-1] == '\r')) line[--len] = '\0'; + cap = len + 1; + } + + size_t L = strlen(line); + int *vals = (int*)malloc((L + 1) * sizeof(int)); + char *ops = (char*)malloc(L + 1); + if (!vals || !ops) return 1; + int vtop = 0, otop = 0; + + for (size_t i = 0; i < L;) { + char c = line[i]; + if (isspace((unsigned char)c)) { ++i; continue; } // 忽略空白 + if (c >= '0' && c <= '9') { + int x = 0; + while (i < L && line[i] >= '0' && line[i] <= '9') { + x = x * 10 + (line[i] - '0'); + ++i; + } + vals[vtop++] = x; + } else if (c == '&' || c == '|') { + // 同优先级:在遇到 '(' 之前,应用所有已入栈的运算符 + while (otop > 0 && ops[otop - 1] != '(') { + apply_top(vals, &vtop, ops, &otop); + } + ops[otop++] = c; + ++i; + } else if (c == '(') { + ops[otop++] = c; + ++i; + } else if (c == ')') { + while (otop > 0 && ops[otop - 1] != '(') { + apply_top(vals, &vtop, ops, &otop); + } + if (otop > 0 && ops[otop - 1] == '(') --otop; // 弹出左括号 + ++i; + } else { + // 非法字符:跳过以增强鲁棒性 + ++i; + } + } + + while (otop > 0) { + apply_top(vals, &vtop, ops, &otop); + } + + if (vtop > 0) printf("%d\n", vals[vtop - 1]); + + free(vals); + free(ops); + free(line); + return 0; +} \ No newline at end of file diff --git a/exercise/33.c b/exercise/33.c new file mode 100644 index 0000000..8c0c7b4 --- /dev/null +++ b/exercise/33.c @@ -0,0 +1,170 @@ +// 算术表达式求值:支持 + - * / ^ 和小括号 +// 规则: +// - 运算符优先级:括号 > 一元± > ^(右结合)> * /(左结合)> + -(左结合) +// - 输入为一行表达式,可能包含多余括号与空格 +// - 输出为结果,按四舍五入取整 + +#include +#include +#include +#include +#include + +// 手写整数乘方(支持负指数):右结合的 ^ 使用该实现 +static inline long double powi_ld(long double base, long long exp) { + if (exp == 0) return 1.0L; + int neg = 0; + if (exp < 0) { neg = 1; exp = -exp; } + long double res = 1.0L, a = base; + while (exp) { + if (exp & 1LL) res *= a; + a *= a; + exp >>= 1LL; + } + if (neg) { + // 避免 1/0 产生异常(表达式一般不会出现该情况) + if (res == 0.0L) return 0.0L; // 约定返回 0,防止 RE + return 1.0L / res; + } + return res; +} + +// 手写四舍五入为 long long,避免依赖 llround +static inline long long roundll(long double x) { + return (x >= 0.0L) ? (long long)(x + 0.5L) : (long long)(x - 0.5L); +} + +// 操作符优先级 +static inline int prec(char op) { + switch (op) { + case '~': return 4; // 一元负号 + case '^': return 3; // 乘方,右结合 + case '*': case '/': return 2; // 乘除 + case '+': case '-': return 1; // 加减 + default: return 0; + } +} + +// 应用一个操作符到栈顶操作数 +static inline void apply_top(long double *vals, int *vtop, char *ops, int *otop) { + char op = ops[--(*otop)]; + if (op == '~') { + long double a = vals[--(*vtop)]; + vals[(*vtop)++] = -a; + return; + } + long double b = vals[--(*vtop)]; + long double a = vals[--(*vtop)]; + long double r; + switch (op) { + case '+': r = a + b; break; + case '-': r = a - b; break; + case '*': r = a * b; break; + case '/': + // 防御除零导致的 RE:约定返回 0(题目数据通常不会出现此情况) + if (b == 0.0L) r = 0.0L; else r = a / b; + break; + case '^': { + long long be = roundll(b); // 指数按近似整数处理 + r = powi_ld(a, be); + break; + } + default: r = 0.0; break; + } + vals[(*vtop)++] = r; +} + +int main(void) { + // 读取整行表达式 + char *line = NULL; + size_t cap = 0; + { + size_t bufcap = 1024; // 表达式长度 ≤ 30,这里足够 + line = (char*)malloc(bufcap); + if (!line) return 1; + if (!fgets(line, (int)bufcap, stdin)) return 0; + size_t len = strlen(line); + while (len && (line[len-1] == '\n' || line[len-1] == '\r')) line[--len] = '\0'; + cap = len + 1; + } + + size_t L = strlen(line); + // 栈容量按输入长度分配 + long double *vals = (long double*)malloc((L + 1) * sizeof(long double)); + char *ops = (char*)malloc(L + 1); + if (!vals || !ops) return 1; + int vtop = 0, otop = 0; + + int expect_unary = 1; // 是否期待一元运算符(开头或在'('或二元运算符之后) + + for (size_t i = 0; i < L;) { + char c = line[i]; + if (isspace((unsigned char)c)) { ++i; continue; } + if (c >= '0' && c <= '9') { + // 解析数字(整数) + long long x = 0; + while (i < L && line[i] >= '0' && line[i] <= '9') { + x = x * 10 + (line[i] - '0'); + ++i; + } + vals[vtop++] = (long double)x; + expect_unary = 0; + } else if (c == '(') { + ops[otop++] = c; + ++i; + expect_unary = 1; + } else if (c == ')') { + while (otop > 0 && ops[otop - 1] != '(') { + apply_top(vals, &vtop, ops, &otop); + } + if (otop > 0 && ops[otop - 1] == '(') --otop; // 弹出左括号 + ++i; + expect_unary = 0; + } else if (c == '+' || c == '-' || c == '*' || c == '/' || c == '^') { + // 处理一元 ± + if (expect_unary && (c == '+' || c == '-')) { + if (c == '-') { + // 一元负号入栈(最高优先级) + ops[otop++] = '~'; + } + // 一元 '+' 不产生效果,直接跳过 + ++i; + expect_unary = 1; // 仍可能继续接 '(' 或 数字 + continue; + } + + // 处理二元运算符的结合与优先级 + int p = prec(c); + int right_assoc = (c == '^'); + while (otop > 0 && ops[otop - 1] != '(') { + int pt = prec(ops[otop - 1]); + if ((right_assoc && pt > p) || (!right_assoc && pt >= p)) { + apply_top(vals, &vtop, ops, &otop); + } else break; + } + ops[otop++] = c; + ++i; + expect_unary = 1; + } else { + // 其他字符(若存在):跳过 + ++i; + } + } + + // 清空剩余操作符 + while (otop > 0) { + apply_top(vals, &vtop, ops, &otop); + } + + // 四舍五入输出整数 + if (vtop > 0) { + long double res = vals[vtop - 1]; + long long rounded = roundll(res); + printf("%lld\n", rounded); + } + + free(vals); + free(ops); + free(line); + return 0; +} \ No newline at end of file diff --git a/exercise/34.c b/exercise/34.c new file mode 100644 index 0000000..e849fdc --- /dev/null +++ b/exercise/34.c @@ -0,0 +1,133 @@ +// 逆波兰式逐步规约打印 +// 输入:仅含 0-9、+ - * / 和小括号 () 的中缀表达式,数字均为一位 +// 要求: +// - 先将中缀转为后缀(RPN) +// - 按从左到右每次规约一个“两个数字 + 一个运算符”的三元组,得到新的后缀表达式 +// - 逐行输出:首行是完整后缀表达式;之后每行比上一行少 1 个运算符和 1 个数字;最后一行只有一个数字(最终结果) +// - 令 / 为整除(向零截断),允许中间结果为负数 +// - 输出格式:各符号之间以单个空格分隔;只有首行和最后一行行末保留一个空格,其他行末无空格 + +#include +#include +#include +#include + +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; +} \ No newline at end of file diff --git a/exercise/35.c b/exercise/35.c new file mode 100644 index 0000000..65b43b7 --- /dev/null +++ b/exercise/35.c @@ -0,0 +1,111 @@ +// 简单逻辑表达式求值:支持 true/false 与 not/and/or,带错误检测 +// 规则: +// - 仅包含单词 true, false, not, and, or 与空格;全部小写 +// - 优先级:not > and > or;同级从左到右(左结合) +// - 输入为一行,输出为 true / false;如果语法或词法错误,输出 error + +#include +#include +#include + +typedef enum { TK_TRUE, TK_FALSE, TK_AND, TK_OR, TK_NOT } Tok; + +// 读取一行到缓冲区,并去除尾部换行符 +static int read_line(char *buf, size_t sz) { + if (!fgets(buf, (int)sz, stdin)) return 0; + size_t n = strlen(buf); + while (n && (buf[n-1] == '\n' || buf[n-1] == '\r')) buf[--n] = '\0'; + return 1; +} + +// 词法:按字母分组,提取单词,映射到令牌;出错返回 -1 +static int tokenize(const char *s, Tok *out, int maxn) { + int nt = 0; + size_t i = 0, n = strlen(s); + while (i < n) { + while (i < n && isspace((unsigned char)s[i])) ++i; + if (i >= n) break; + if (!isalpha((unsigned char)s[i])) return -1; // 非法字符 + size_t j = i; + while (j < n && isalpha((unsigned char)s[j])) ++j; + size_t wlen = j - i; + if (wlen == 4 && strncmp(s + i, "true", 4) == 0) { + if (nt >= maxn) return -1; + out[nt++] = TK_TRUE; + } else if (wlen == 5 && strncmp(s + i, "false", 5) == 0) { + if (nt >= maxn) return -1; + out[nt++] = TK_FALSE; + } else if (wlen == 3 && strncmp(s + i, "and", 3) == 0) { + if (nt >= maxn) return -1; + out[nt++] = TK_AND; + } else if (wlen == 2 && strncmp(s + i, "or", 2) == 0) { + if (nt >= maxn) return -1; + out[nt++] = TK_OR; + } else if (wlen == 3 && strncmp(s + i, "not", 3) == 0) { + if (nt >= maxn) return -1; + out[nt++] = TK_NOT; + } else { + return -1; // 未知单词 + } + i = j; + } + return nt; +} + +// 递归下降(迭代实现)语法: +// unary := { not }* ( true | false ) +// and := unary { and unary }* +// or := and { or and }* + +static int parse_unary(const Tok *toks, int nt, int *idx, int *ok) { + int neg = 0; + while (*idx < nt && toks[*idx] == TK_NOT) { ++neg; ++*idx; } + if (*idx >= nt) { *ok = 0; return 0; } + int val; + if (toks[*idx] == TK_TRUE) { val = 1; } + else if (toks[*idx] == TK_FALSE) { val = 0; } + else { *ok = 0; return 0; } + ++*idx; + if (neg & 1) val = !val; + return val; +} + +static int parse_and(const Tok *toks, int nt, int *idx, int *ok) { + int lhs = parse_unary(toks, nt, idx, ok); + if (!*ok) return 0; + while (*idx < nt && toks[*idx] == TK_AND) { + ++*idx; + int rhs = parse_unary(toks, nt, idx, ok); + if (!*ok) return 0; + lhs = (lhs && rhs); + } + return lhs; +} + +static int parse_or(const Tok *toks, int nt, int *idx, int *ok) { + int lhs = parse_and(toks, nt, idx, ok); + if (!*ok) return 0; + while (*idx < nt && toks[*idx] == TK_OR) { + ++*idx; + int rhs = parse_and(toks, nt, idx, ok); + if (!*ok) return 0; + lhs = (lhs || rhs); + } + return lhs; +} + +int main(void) { + char line[512]; + if (!read_line(line, sizeof(line))) return 0; + + Tok toks[300]; + int nt = tokenize(line, toks, 300); + if (nt <= 0) { printf("error\n"); return 0; } + + int idx = 0, ok = 1; + int result = parse_or(toks, nt, &idx, &ok); + if (!ok || idx != nt) { printf("error\n"); return 0; } + + printf(result ? "true\n" : "false\n"); + return 0; +} \ No newline at end of file diff --git a/exercise/36.c b/exercise/36.c new file mode 100644 index 0000000..0e5257e --- /dev/null +++ b/exercise/36.c @@ -0,0 +1,87 @@ +// 地道连通查询(线性房屋 1..n):支持操作 +// D x: 摧毁房屋 x;R: 修复上一次摧毁的房屋;Q x: 询问士兵在 x 能到达的房屋数 +// 思路:维护“被摧毁房屋”的有序集合,查询时找离 x 最近的左右两个摧毁位置。 +// 为了在 C 中高效实现前驱/后继,使用树状数组(Fenwick)存放摧毁标记(1 表示摧毁), +// 并用“按前缀和查找第 k 个 1”的技巧 O(log n) 求出前驱/后继位置。 + +#include +#include + +static int N; // 房屋总数 +static int *bit; // 树状数组,1..N +static int *dead; // 摧毁标记 +static int *stackD; // 摧毁栈,支持 R +static int topD = 0; + +static inline int lowbit(int x) { return x & -x; } + +static void bit_add(int i, int delta) { + for (; i <= N; i += lowbit(i)) bit[i] += delta; +} + +static int bit_sum(int i) { + int s = 0; + for (; i > 0; i -= lowbit(i)) s += bit[i]; + return s; +} + +// 返回使得前缀和等于 k 的最小下标(1..N)。要求 k>=1 且 k<=sum(N) +static int bit_find_kth(int k) { + int idx = 0; + // 最大 2 的幂覆盖到 N + int p = 1; + while ((p << 1) <= N) p <<= 1; + for (; p; p >>= 1) { + int next = idx + p; + if (next <= N && bit[next] < k) { + idx = next; + k -= bit[next]; + } + } + return idx + 1; // 1..N +} + +int main(void) { + int n, m; + if (scanf("%d %d", &n, &m) != 2) return 0; + N = n; + bit = (int *)calloc((size_t)N + 1u, sizeof(int)); + dead = (int *)calloc((size_t)N + 2u, sizeof(int)); + stackD = (int *)malloc(((size_t)m + 5u) * sizeof(int)); + if (!bit || !dead || !stackD) return 0; + + for (int i = 0; i < m; ++i) { + char cmd[8]; + if (scanf("%7s", cmd) != 1) break; + if (cmd[0] == 'D') { + int x; scanf("%d", &x); + if (x >= 1 && x <= n && !dead[x]) { + dead[x] = 1; + bit_add(x, +1); + stackD[topD++] = x; + } + } else if (cmd[0] == 'R') { + if (topD > 0) { + int x = stackD[--topD]; + if (dead[x]) { dead[x] = 0; bit_add(x, -1); } + } + } else if (cmd[0] == 'Q') { + int x; scanf("%d", &x); + if (x < 1 || x > n) { printf("0\n"); continue; } + if (dead[x]) { + printf("0\n"); + } else { + int left_cnt = bit_sum(x - 1); + int total_cnt = bit_sum(n); + int upto_x_cnt = bit_sum(x); + int left_break = (left_cnt == 0) ? 0 : bit_find_kth(left_cnt); + int right_break = (upto_x_cnt == total_cnt) ? (n + 1) : bit_find_kth(upto_x_cnt + 1); + int reachable = right_break - left_break - 1; + printf("%d\n", reachable); + } + } + } + + free(bit); free(dead); free(stackD); + return 0; +} \ No newline at end of file diff --git a/exercise/37.c b/exercise/37.c new file mode 100644 index 0000000..db5a2c6 --- /dev/null +++ b/exercise/37.c @@ -0,0 +1,152 @@ +// 随机连续子序列的最小值期望满意度: +// 选取所有子数组(连续子序列)均匀随机;score 为该子数组的最小值;满意度为 max(0, score - expect) +// 目标:对每个 expect 求 E[max(0, min - expect)],用最简分数输出。 +// 做法: +// - 用单调栈统计每个位置作为“子数组最小值的代表”的子数组个数 c_i,采用去重规则: +// prev 为前一个 < 当前值的位置,next 为后一个 <= 当前值的位置;贡献个数为 (i-prev)*(next-i) +// - 将相同值的贡献累加,得到“最小值为 v 的子数组个数” count[v] +// - 总子数组数 T = n*(n+1)/2;对 expect=e,有 +// E = (1/T) * sum_{v>e} (v-e) * count[v] +// = (1/T) * ( sum_{v>e} v*count[v] - e * sum_{v>e} count[v] ) +// - 预先按 v 排序并做前缀和,查询时二分找 v>e 的起点,O(log n) 得到分子;化简为最简分数输出。 + +#include +#include + +typedef long long ll; +typedef unsigned long long ull; +typedef __int128 i128; +typedef unsigned __int128 u128; + +typedef struct { ll v; ull c; } Pair; + +static int cmp_pair(const void *a, const void *b) { + const Pair *x = (const Pair *)a, *y = (const Pair *)b; + if (x->v < y->v) return -1; + if (x->v > y->v) return 1; + return 0; +} + +static void print_u128(u128 x) { + if (x == 0) { putchar('0'); return; } + char buf[64]; + int p = 0; + while (x) { + unsigned int d = (unsigned int)(x % 10); + buf[p++] = (char)('0' + d); + x /= 10; + } + while (p--) putchar(buf[p]); +} + +static ull gcd_ull(ull a, ull b) { + while (b) { ull t = a % b; a = b; b = t; } + return a; +} + +int main(void) { + int T; + if (scanf("%d", &T) != 1) return 0; + for (int tc = 1; tc <= T; ++tc) { + int n; if (scanf("%d", &n) != 1) return 0; + ll *a = (ll *)malloc(((size_t)n + 5u) * sizeof(ll)); + for (int i = 1; i <= n; ++i) scanf("%lld", &a[i]); + + // 单调栈:prev(<) 与 next(<=) + int *prev = (int *)malloc(((size_t)n + 5u) * sizeof(int)); + int *next = (int *)malloc(((size_t)n + 5u) * sizeof(int)); + int *st = (int *)malloc(((size_t)n + 5u) * sizeof(int)); + int top = 0; + for (int i = 1; i <= n; ++i) { + while (top > 0 && a[st[top - 1]] >= a[i]) --top; + prev[i] = (top == 0 ? 0 : st[top - 1]); + st[top++] = i; + } + top = 0; + for (int i = n; i >= 1; --i) { + while (top > 0 && a[st[top - 1]] > a[i]) --top; + next[i] = (top == 0 ? (n + 1) : st[top - 1]); + st[top++] = i; + } + + // 生成 (value, count) 对 + Pair *pairs = (Pair *)malloc(((size_t)n + 5u) * sizeof(Pair)); + for (int i = 1; i <= n; ++i) { + ull L = (ull)(i - prev[i]); + ull R = (ull)(next[i] - i); + pairs[i - 1].v = a[i]; + pairs[i - 1].c = L * R; + } + + qsort(pairs, (size_t)n, sizeof(Pair), cmp_pair); + + // 压缩相同值 + int k = 0; + Pair *uniq = (Pair *)malloc(((size_t)n + 5u) * sizeof(Pair)); + for (int i = 0; i < n; ) { + ll v = pairs[i].v; u128 csum = 0; + while (i < n && pairs[i].v == v) { csum += (u128)pairs[i].c; ++i; } + uniq[k].v = v; // csum 可能 >2^64,但总子数组数 <= 5e10,仍可放进 64bit + // 但为了稳妥,仍按 64 位存储(安全范围内) + unsigned long long cc = (unsigned long long)csum; // csum <= n*(n+1)/2 <= 5e10 + uniq[k].c = cc; + ++k; + } + + // 前缀和(用于后缀查询) + unsigned long long *prefC = (unsigned long long *)malloc(((size_t)k + 5u) * sizeof(unsigned long long)); + u128 *prefVC = (u128 *)malloc(((size_t)k + 5u) * sizeof(u128)); + u128 sVC = 0; unsigned long long sC = 0; + for (int i = 0; i < k; ++i) { + sC += uniq[i].c; + sVC += (u128)((i128)uniq[i].v) * (u128)uniq[i].c; + prefC[i] = sC; + prefVC[i] = sVC; + } + + // 总子数组数 + unsigned long long Total = (unsigned long long)n * (unsigned long long)(n + 1) / 2ull; + + int m; scanf("%d", &m); + printf("Case %d:\n", tc); + for (int qi = 0; qi < m; ++qi) { + long long e; scanf("%lld", &e); + // 二分找第一个 v>e 的位置 + int lo = 0, hi = k; + while (lo < hi) { + int mid = (lo + hi) >> 1; + if (uniq[mid].v <= e) lo = mid + 1; else hi = mid; + } + if (lo == k) { puts("0"); continue; } + // 后缀和 + unsigned long long S2 = prefC[k - 1] - (lo ? prefC[lo - 1] : 0ull); + u128 S1 = prefVC[k - 1] - (lo ? prefVC[lo - 1] : (u128)0); + // 分子:S1 - e*S2 + u128 Numer = S1 - (u128)((i128)e) * (u128)S2; + if (Numer == 0) { puts("0"); continue; } + // 若可整除,输出整数 + u128 mod = Numer % (u128)Total; + if (mod == 0) { + u128 A = Numer / (u128)Total; + print_u128(A); putchar('\n'); + } else { + unsigned long long r = (unsigned long long)mod; // mod < Total + unsigned long long g = gcd_ull(Total, r); + u128 A = Numer / (u128)g; + unsigned long long B = Total / g; + print_u128(A); putchar('/'); + // 打印 B(64 位) + char buf[32]; int p = 0; unsigned long long Bb = B; + if (Bb == 0) { putchar('0'); } + else { + while (Bb) { buf[p++] = (char)('0' + (Bb % 10)); Bb /= 10; } + while (p--) putchar(buf[p]); + } + putchar('\n'); + } + } + + free(a); free(prev); free(next); free(st); free(pairs); free(uniq); free(prefC); free(prefVC); + } + return 0; +} \ No newline at end of file diff --git a/exercise/38.c b/exercise/38.c new file mode 100644 index 0000000..9d9a742 --- /dev/null +++ b/exercise/38.c @@ -0,0 +1,79 @@ +// 优化版:每个区间长度 k(1..n) 的最大区间价值 max(subarray_max * subarray_min) +// 算法:最大值笛卡尔树 + 跨越合并(单调两指针),整体显著优于 O(n^2) +// 说明:对每个树节点 i 及其覆盖段 [l,r],所有包含 i 的子数组最大值均为 a[i]; +// 设从 i 向左取 x 个、向右取 y 个,长度 k=x+y+1,区间最小值为 min(Lmin[x], Rmin[y]); +// 其中 Lmin/Rmin 为以 i 为中心的左/右最小值前后缀。对固定 s=x+y, +// 利用两指针在可行范围内最大化 min(Lmin[s-y], Rmin[y]),O(lenL+lenR) 完成一次合并。 + +#include +#include + +typedef long long ll; + +static inline ll minll(ll a, ll b) { return a < b ? a : b; } + +// 构建“以最大值为堆”的笛卡尔树。相等值用 <= 弹出以保证唯一性(倾向右侧作为父)。 +// 输出:left child lc,right child rc,parent;返回根下标。 +static int build_cartesian_tree(const ll *a, int n, int *lc, int *rc, int *parent) { + int *st = (int*)malloc((n + 1) * sizeof(int)); + int top = 0; + int root = 0; + for (int i = 1; i <= n; ++i) { + int last = 0; + while (top > 0 && a[st[top - 1]] <= a[i]) { + last = st[--top]; + } + if (top > 0) { + rc[st[top - 1]] = i; + parent[i] = st[top - 1]; + } else { + root = i; + parent[i] = 0; + } + lc[i] = last; + if (last) parent[last] = i; + st[top++] = i; + } + free(st); + return root; +} + +int main(void) { + int n; + if (scanf("%d", &n) != 1) return 0; + int cap = n + 5; + int *dq = (int*)malloc((size_t)cap * sizeof(int)); + int head = 0, tail = 0, size = 0; + char *out = (char*)malloc((size_t)(n * 14 + 1)); + int pos = 0; + for (int i = 0; i < n; ++i) { + int op; + scanf("%d", &op); + if (op == 1) { + int x; scanf("%d", &x); + head = (head - 1 + cap) % cap; + dq[head] = x; + ++size; + } else if (op == 2) { + int x; scanf("%d", &x); + dq[tail] = x; + tail = (tail + 1) % cap; + ++size; + } else if (op == 3) { + pos += sprintf(out + pos, "%d\n", dq[head]); + } else if (op == 4) { + int idx = (tail - 1 + cap) % cap; + pos += sprintf(out + pos, "%d\n", dq[idx]); + } else if (op == 5) { + head = (head + 1) % cap; + --size; + } else if (op == 6) { + tail = (tail - 1 + cap) % cap; + --size; + } + } + fwrite(out, 1, (size_t)pos, stdout); + free(out); + free(dq); + return 0; +} \ No newline at end of file diff --git a/exercise/39.c b/exercise/39.c new file mode 100644 index 0000000..8a62985 --- /dev/null +++ b/exercise/39.c @@ -0,0 +1,30 @@ +#include +#include + +int main(void) { + int n, m; + if (scanf("%d %d", &n, &m) != 2) return 0; + int *a = (int*)malloc((size_t)(n + 1) * sizeof(int)); + for (int i = 1; i <= n; ++i) scanf("%d", &a[i]); + int *cnt = (int*)calloc((size_t)(m + 1), sizeof(int)); + int covered = 0; + int l = 1; + int best_l = 1, best_r = n; + int best_len = n; + for (int r = 1; r <= n; ++r) { + int c = a[r]; + if (cnt[c] == 0) ++covered; + ++cnt[c]; + if (covered == m) { + while (cnt[a[l]] > 1) { --cnt[a[l]]; ++l; } + int len = r - l + 1; + if (len < best_len || (len == best_len && l < best_l)) { + best_len = len; best_l = l; best_r = r; + } + } + } + printf("%d %d\n", best_l, best_r); + free(cnt); + free(a); + return 0; +} \ No newline at end of file diff --git a/exercise/4.c b/exercise/4.c new file mode 100644 index 0000000..16315fa --- /dev/null +++ b/exercise/4.c @@ -0,0 +1,34 @@ +#include + +// 递归实现 +long long f_recursive(int n) +{ + if (n == 1) + { + return 1; + } + return n + f_recursive(n - 1); +} + +// 数学公式实现(更高效) +long long f_formula(long long n) +{ + return n * (n + 1) / 2; +} + +int main() +{ + int T; + scanf("%d", &T); + + while (T--) + { + long long n; + scanf("%lld", &n); + + // 由于n可能很大(<10^9),使用数学公式更安全 + printf("%lld\n", f_formula(n)); + } + + return 0; +} \ No newline at end of file diff --git a/exercise/40.c b/exercise/40.c new file mode 100644 index 0000000..5f0df36 --- /dev/null +++ b/exercise/40.c @@ -0,0 +1,156 @@ +#include +#include +#ifdef _WIN32 +#include +#include +#endif + +// 二叉树节点定义 +struct BiTNode +{ + char data; // 节点数据 + struct BiTNode *lchild; // 左子节点 + struct BiTNode *rchild; // 右子节点 +}; + +typedef struct BiTNode *BiTree; + +// 函数声明 +void CreateBiTree(BiTree *T); // 创建二叉树 +void PreOrderTraverse(BiTree T); // 先序遍历 +void InOrderTraverse(BiTree T); // 中序遍历 +void PostOrderTraverse(BiTree T); // 后序遍历 +void PrintMenu(); // 打印菜单 +void FreeTree(BiTree T); + +int main() +{ + // 设置控制台编码为UTF-8,防止中文乱码 +#ifdef _WIN32 + system("chcp 65001 > nul"); // 设置控制台编码为UTF-8 + SetConsoleOutputCP(65001); // 设置控制台输出编码 + SetConsoleCP(65001); // 设置控制台输入编码 +#endif + + BiTree T = NULL; + int choice; + + printf("=== 链式二叉树遍历系统 (C语言版本) ===\n"); + printf("请输入先序扩展序列构建二叉树(# 表示空节点,例如 AB#C##D##):\n"); + CreateBiTree(&T); + + do + { + PrintMenu(); + if (scanf("%d", &choice) != 1) + { + return 0; + } + + switch (choice) + { + case 1: + printf("先序遍历结果: "); + PreOrderTraverse(T); + printf("\n"); + break; + case 2: + printf("中序遍历结果: "); + InOrderTraverse(T); + printf("\n"); + break; + case 3: + printf("后序遍历结果: "); + PostOrderTraverse(T); + printf("\n"); + break; + case 4: + printf("程序已退出。\n"); + break; + default: + printf("无效输入,请输入 1~4 之间的数字!\n"); + } + } while (choice != 4); + + FreeTree(T); + return 0; +} + +// 创建二叉树(先序扩展输入) +void CreateBiTree(BiTree *T) +{ + char ch; + if (scanf(" %c", &ch) != 1) + { + *T = NULL; + return; + } + + if (ch == '#') + { + *T = NULL; + } + else + { + *T = (struct BiTNode *)malloc(sizeof(struct BiTNode)); + (*T)->data = ch; + (*T)->lchild = NULL; + (*T)->rchild = NULL; + CreateBiTree(&(*T)->lchild); + CreateBiTree(&(*T)->rchild); + } +} + +// 先序遍历:根 -> 左 -> 右 +void PreOrderTraverse(BiTree T) +{ + if (T != NULL) + { + printf("%c ", T->data); + PreOrderTraverse(T->lchild); + PreOrderTraverse(T->rchild); + } +} + +// 中序遍历:左 -> 根 -> 右 +void InOrderTraverse(BiTree T) +{ + if (T != NULL) + { + InOrderTraverse(T->lchild); + printf("%c ", T->data); + InOrderTraverse(T->rchild); + } +} + +// 后序遍历:左 -> 右 -> 根 +void PostOrderTraverse(BiTree T) +{ + if (T != NULL) + { + PostOrderTraverse(T->lchild); + PostOrderTraverse(T->rchild); + printf("%c ", T->data); + } +} + +// 打印菜单 +void PrintMenu() +{ + printf("\n--- 选择遍历方式 ---\n"); + printf("1. 先序遍历\n"); + printf("2. 中序遍历\n"); + printf("3. 后序遍历\n"); + printf("4. 退出\n"); + printf("请输入选择 (1-4): "); +} + +void FreeTree(BiTree T) +{ + if (T) + { + FreeTree(T->lchild); + FreeTree(T->rchild); + free(T); + } +} \ No newline at end of file diff --git a/exercise/41.c b/exercise/41.c new file mode 100644 index 0000000..6acc0f2 --- /dev/null +++ b/exercise/41.c @@ -0,0 +1,312 @@ +#include +#include +#ifdef _WIN32 +#include +#include +#endif + +// 链式二叉树节点结构 +struct BiTNode +{ + char data; + struct BiTNode *lchild; + struct BiTNode *rchild; +}; + +// 二叉树指针类型定义 +typedef struct BiTNode *BiTree; + +// 函数声明 +void CreateBiTree(BiTree *T); // 创建二叉树 +void PreOrderTraverse(BiTree T); // 先序遍历 +void InOrderTraverse(BiTree T); // 中序遍历 +void PostOrderTraverse(BiTree T); // 后序遍历 +void LevelOrderTraverse(BiTree T); // 层次遍历 +int MaxWidth(BiTree T); // 计算最大宽度 +void PrintMenu(); // 打印菜单 +void FreeTree(BiTree T); // 释放二叉树内存 + +int main(void) +{ + // 设置控制台编码为UTF-8,防止中文乱码 +#ifdef _WIN32 + system("chcp 65001 > nul"); // 设置控制台编码为UTF-8 + SetConsoleOutputCP(65001); // 设置控制台输出编码 + SetConsoleCP(65001); // 设置控制台输入编码 +#endif + + BiTree T = NULL; + int choice; + + printf("=== 链式二叉树遍历系统 (C语言非递归) ===\n"); + printf("请输入先序扩展序列构建二叉树(# 表示空节点,例如 AB#C##D##):\n"); + CreateBiTree(&T); + + do + { + PrintMenu(); + if (scanf("%d", &choice) != 1) + { + printf("无效输入,请输入1~6之间的数字!\n"); + continue; + } + + switch (choice) + { + case 1: + printf("先序遍历结果: "); + PreOrderTraverse(T); + printf("\n"); + break; + case 2: + printf("中序遍历结果: "); + InOrderTraverse(T); + printf("\n"); + break; + case 3: + printf("后序遍历结果: "); + PostOrderTraverse(T); + printf("\n"); + break; + case 4: + printf("层次遍历结果: "); + LevelOrderTraverse(T); + printf("\n"); + break; + case 5: + printf("程序已退出。\n"); + break; + case 6: + printf("最大宽度: %d\n", MaxWidth(T)); + break; + default: + printf("无效输入,请输入 1~6 之间的数字!\n"); + } + } while (choice != 5); + + FreeTree(T); + return 0; +} + +// 创建二叉树(先序扩展输入) +void CreateBiTree(BiTree *T) +{ + char ch; + if (scanf(" %c", &ch) != 1) + { + *T = NULL; + return; + } + + if (ch == '#') + { + *T = NULL; + return; + } + else + { + *T = (struct BiTNode *)malloc(sizeof(struct BiTNode)); + (*T)->data = ch; + (*T)->lchild = NULL; + (*T)->rchild = NULL; + CreateBiTree(&(*T)->lchild); + CreateBiTree(&(*T)->rchild); + } +} + +// 先序遍历:根 -> 左 -> 右 +void PreOrderTraverse(BiTree T) +{ + if (!T) + { + return; + } + // 栈初始化,用栈来显性表示递归时的函数调用 + int cap = 128, top = 0; + BiTree *st = (BiTree *)malloc(sizeof(BiTree) * cap); + st[top++] = T; + + while (top) + { + BiTree p = st[--top]; + printf("%c ", p->data); + if (p->rchild) + { + if (top >= cap) + { + cap *= 2; + st = (BiTree *)realloc(st, sizeof(BiTree) * cap); + } + st[top++] = p->rchild; + } + if (p->lchild) + { + if (top >= cap) + { + cap *= 2; + st = (BiTree *)realloc(st, sizeof(BiTree) * cap); + } + st[top++] = p->lchild; + } + } + free(st); +} + +// 中序遍历:左 -> 根 -> 右 +void InOrderTraverse(BiTree T) +{ + int cap = 128, top = 0; + BiTree *st = (BiTree *)malloc(sizeof(BiTree) * cap); + BiTree cur = T; + while (cur || top) + { + while (cur) + { + if (top >= cap) + { + cap *= 2; + st = (BiTree *)realloc(st, sizeof(BiTree) * cap); + } + st[top++] = cur; + cur = cur->lchild; + } + BiTree p = st[--top]; + printf("%c ", p->data); + cur = p->rchild; + } + free(st); +} + +// 后序遍历:左 -> 右 -> 根 +void PostOrderTraverse(BiTree T) +{ + int cap = 128, top = 0; + BiTree *st = (BiTree *)malloc(sizeof(BiTree) * cap); + BiTree cur = T, last = NULL; + while (cur || top) + { + while (cur) + { + if (top >= cap) + { + cap *= 2; + st = (BiTree *)realloc(st, sizeof(BiTree) * cap); + } + st[top++] = cur; + cur = cur->lchild; + } + BiTree p = st[top - 1]; + if (p->rchild && last != p->rchild) + { + cur = p->rchild; + } + else + { + printf("%c ", p->data); + last = p; + --top; + } + } + free(st); +} + +// 层次遍历:按层从左到右遍历 +void LevelOrderTraverse(BiTree T) +{ + if (!T) + { + return; + } + int cap = 128; + BiTree *q = (BiTree *)malloc(sizeof(BiTree) * cap); + int head = 0, tail = 0; + q[tail++] = T; + while (head < tail) + { + BiTree p = q[head++]; + printf("%c ", p->data); + if (p->lchild) + { + if (tail >= cap) + { + cap *= 2; + q = (BiTree *)realloc(q, sizeof(BiTree) * cap); + } + q[tail++] = p->lchild; + } + if (p->rchild) + { + if (tail >= cap) + { + cap *= 2; + q = (BiTree *)realloc(q, sizeof(BiTree) * cap); + } + q[tail++] = p->rchild; + } + } + free(q); +} + +// 计算二叉树的最大宽度 +int MaxWidth(BiTree T) +{ + if (!T) return 0; + int cap = 128; + BiTree *q = (BiTree *)malloc(sizeof(BiTree) * cap); + int head = 0, tail = 0; + int maxw = 0; + q[tail++] = T; + while (head < tail) + { + int level_size = tail - head; + if (level_size > maxw) maxw = level_size; + for (int i = 0; i < level_size; ++i) + { + BiTree p = q[head++]; + if (p->lchild) + { + if (tail >= cap) + { + cap *= 2; + q = (BiTree *)realloc(q, sizeof(BiTree) * cap); + } + q[tail++] = p->lchild; + } + if (p->rchild) + { + if (tail >= cap) + { + cap *= 2; + q = (BiTree *)realloc(q, sizeof(BiTree) * cap); + } + q[tail++] = p->rchild; + } + } + } + free(q); + return maxw; +} + +// 打印菜单 +void PrintMenu(void) +{ + printf("\n--- 选择遍历方式(非递归) ---\n"); + printf("1. 先序遍历\n"); + printf("2. 中序遍历\n"); + printf("3. 后序遍历\n"); + printf("4. 层次遍历\n"); + printf("5. 退出\n"); + printf("6. 最大宽度\n"); + printf("请输入选择 (1-6): "); +} + +// 释放二叉树内存 +void FreeTree(BiTree T) +{ + if (T) + { + FreeTree(T->lchild); + FreeTree(T->rchild); + free(T); + } +} \ No newline at end of file diff --git a/exercise/42.c b/exercise/42.c new file mode 100644 index 0000000..d6b3256 --- /dev/null +++ b/exercise/42.c @@ -0,0 +1,211 @@ +#include +#include +#ifdef _WIN32 +#include +#endif + +// 图的邻接矩阵表示 +typedef struct +{ + int n; + int directed; + int **mat; +} GraphMat; + +// 图的邻接表边的表示 +typedef struct Edge +{ + int to; + struct Edge *next; +} Edge; + +// 图的邻接表表示 +typedef struct +{ + int n; + int directed; + Edge **head; +} GraphList; + +// 创建邻接矩阵表示的图 +GraphMat GraphMatCreate(int n, int directed) +{ + GraphMat g; + g.n = n; + g.directed = directed; + g.mat = (int **)malloc((size_t)n * sizeof(int *)); + for (int i = 0; i < n; ++i) + { + g.mat[i] = (int *)calloc((size_t)n, sizeof(int)); + } + return g; +} + +// 添加邻接矩阵表示的图的边 +void GraphMatAddEdge(GraphMat *g, int u, int v) +{ + int n = g->n; + if (u >= 1 && u <= n && v >= 1 && v <= n) + { + g->mat[u - 1][v - 1] = 1; + if (!g->directed) + { + g->mat[v - 1][u - 1] = 1; + } + } +} + +// 释放邻接矩阵表示的图 +void GraphMatFree(GraphMat *g) +{ + if (g->mat) + { + for (int i = 0; i < g->n; ++i) + free(g->mat[i]); + free(g->mat); + g->mat = NULL; + } +} + +// 创建邻接表表示的图 +GraphList GraphListCreate(int n, int directed) +{ + GraphList g; + g.n = n; + g.directed = directed; + g.head = (Edge **)calloc((size_t)n + 1, sizeof(Edge *)); + return g; +} + +// 添加邻接表表示的图的边 +void GraphListAddEdge(GraphList *g, int u, int v) +{ + int n = g->n; + if (u >= 1 && u <= n && v >= 1 && v <= n) + { + Edge *e = (Edge *)malloc(sizeof(Edge)); + e->to = v; + e->next = g->head[u]; + g->head[u] = e; + if (!g->directed) + { + Edge *e2 = (Edge *)malloc(sizeof(Edge)); + e2->to = u; + e2->next = g->head[v]; + g->head[v] = e2; + } + } +} + +// 释放邻接表表示的图 +void GraphListFree(GraphList *g) +{ + for (int i = 1; i <= g->n; ++i) + { + Edge *p = g->head[i]; + while (p) + { + Edge *nxt = p->next; + free(p); + p = nxt; + } + } + free(g->head); + g->head = NULL; +} + +// 打印邻接矩阵表示的图 +void PrintMatrix(const GraphMat *g) +{ + int n = g->n; + printf("邻接矩阵:\n"); + for (int i = 0; i < n; ++i) + { + for (int j = 0; j < n; ++j) + { + if (j) + { + printf(" "); + } + printf("%d", g->mat[i][j]); + } + printf("\n"); + } +} + +// 打印邻接表表示的图 +void PrintList(const GraphList *g) +{ + printf("邻接表:\n"); + for (int i = 1; i <= g->n; ++i) + { + printf("%d:", i); + Edge *p = g->head[i]; + if (p) + { + printf(" "); + } + int first = 1; + while (p) + { + if (!first) + { + printf(" "); + } + printf("%d", p->to); + first = 0; + p = p->next; + } + printf("\n"); + } +} + +int main(void) +{ +#ifdef _WIN32 + system("chcp 65001 > nul"); + SetConsoleOutputCP(65001); + SetConsoleCP(65001); +#endif + + // 图的顶点数、边数和是否有向 + int n, m, dir; + printf("请输入图的顶点数、边数和是否有向(0:无向, 1:有向): "); + if (scanf("%d %d %d", &n, &m, &dir) != 3) + { + printf("输入错误\n"); + return 0; + } + if (n <= 0 || m < 0 || (dir != 0 && dir != 1)) + { + printf("输入错误\n"); + return 0; + } + + // 创建邻接矩阵表示的图和邻接表表示的图 + GraphMat gm = GraphMatCreate(n, dir); + GraphList gl = GraphListCreate(n, dir); + for (int i = 0; i < m; ++i) + { + int u, v; + if (scanf("%d %d", &u, &v) != 2) + { + printf("输入错误\n"); + break; + } + + // 添加邻接矩阵表示的图的边和邻接表表示的图的边 + GraphMatAddEdge(&gm, u, v); + GraphListAddEdge(&gl, u, v); + } + + // 打印邻接矩阵表示的图和邻接表表示的图 + PrintMatrix(&gm); + PrintList(&gl); + + // 释放邻接矩阵表示的图和邻接表表示的图 + GraphMatFree(&gm); + GraphListFree(&gl); + + return 0; +} \ No newline at end of file diff --git a/exercise/43.c b/exercise/43.c new file mode 100644 index 0000000..ffc2e59 --- /dev/null +++ b/exercise/43.c @@ -0,0 +1,119 @@ +#include +#include +#ifdef _WIN32 +#include +#endif + +// 图的边的表示 +typedef struct +{ + int u, v; + int w; +} Edge; + +// 边的比较函数,用于排序 +static int cmp_edge(const void *a, const void *b) +{ + int wa = ((const Edge *)a)->w; + int wb = ((const Edge *)b)->w; + return (wa > wb) - (wa < wb); +} + +// 并查集的查找函数 +static int find(int *parent, int x) +{ + if (parent[x] == x) + { + return x; + } + return parent[x] = find(parent, parent[x]); +} + +// 并查集的合并函数 +static void unite(int *parent, int *sz, int a, int b) +{ + if (sz[a] < sz[b]) + { + int t = a; + a = b; + b = t; + } + parent[b] = a; + sz[a] += sz[b]; +} + +int main(void) +{ +#ifdef _WIN32 + system("chcp 65001 > nul"); + SetConsoleOutputCP(65001); + SetConsoleCP(65001); +#endif + + // 读取图的边数和节点数 + int n, m; + if (scanf("%d %d", &n, &m) != 2) + { + printf("输入错误\n"); + return 0; + } + + // 读取图的边 + Edge *e = (Edge *)malloc((size_t)m * sizeof(Edge)); + for (int i = 0; i < m; ++i) + { + int u, v, w; + scanf("%d %d %d", &u, &v, &w); + e[i].u = u; + e[i].v = v; + e[i].w = w; + } + + // 初始化并查集 + int *parent = (int *)malloc((size_t)(n + 1) * sizeof(int)); + int *sz = (int *)malloc((size_t)(n + 1) * sizeof(int)); + for (int i = 1; i <= n; ++i) + { + parent[i] = i; + sz[i] = 1; + } + + // 对边按权重排序 + qsort(e, (size_t)m, sizeof(Edge), cmp_edge); + + // 最小生成树的计算 + long long ans = 0; + int cnt = 0; + for (int i = 0; i < m && cnt < n - 1; ++i) + { + // 跳过无效的边 + int u = e[i].u, v = e[i].v; + if (u < 1 || u > n || v < 1 || v > n) + { + continue; + } + // 检查是否形成环 + int ru = find(parent, u), rv = find(parent, v); + if (ru != rv) + { + ans += e[i].w; + unite(parent, sz, ru, rv); + ++cnt; + } + } + + // 检查是否所有节点都在最小生成树中 + if (cnt == n - 1) + { + printf("%lld\n", ans); + } + else + { + printf("impossible\n"); + } + + free(sz); + free(parent); + free(e); + return 0; +} \ No newline at end of file diff --git a/exercise/5.c b/exercise/5.c new file mode 100644 index 0000000..5522edd --- /dev/null +++ b/exercise/5.c @@ -0,0 +1,46 @@ +#include +#include + +int main() +{ + int T; + scanf("%d", &T); + + while (T--) + { + char str[10001]; + scanf("%s", str); + + // 统计每个小写字母的出现次数 + int count[26] = {0}; // a-z对应0-25 + + int len = strlen(str); + for (int i = 0; i < len; i++) + { + char c = str[i]; + // 只统计小写字母 + if (c >= 'a' && c <= 'z') + { + count[c - 'a']++; + } + } + + // 找出出现次数最多的字母,如果次数相同则选择字典序最小的 + int max_count = 0; + char result = 'a'; + + // 从a到z遍历,保证字典序最小 + for (int i = 0; i < 26; i++) + { + if (count[i] > max_count) + { + max_count = count[i]; + result = 'a' + i; + } + } + + printf("%c\n", result); + } + + return 0; +} \ No newline at end of file diff --git a/exercise/6.c b/exercise/6.c new file mode 100644 index 0000000..ed4d084 --- /dev/null +++ b/exercise/6.c @@ -0,0 +1,32 @@ +#include +#include + +int main() +{ + int T; + scanf("%d", &T); + + while (T--) + { + char str[10001]; + scanf("%s", str); + + int count = 0; + int len = strlen(str); + + // 遍历字符串,统计小写字母个数 + for (int i = 0; i < len; i++) + { + char c = str[i]; + // 判断是否为小写字母 + if (c >= 'a' && c <= 'z') + { + count++; + } + } + + printf("%d\n", count); + } + + return 0; +} \ No newline at end of file diff --git a/exercise/7.c b/exercise/7.c new file mode 100644 index 0000000..2997dd6 --- /dev/null +++ b/exercise/7.c @@ -0,0 +1,36 @@ +#include + +int main() +{ + int N; + scanf("%d", &N); + + while (N--) + { + int AH, AM, AS, BH, BM, BS; + scanf("%d %d %d %d %d %d", &AH, &AM, &AS, &BH, &BM, &BS); + + // 直接相加 + int total_hours = AH + BH; + int total_minutes = AM + BM; + int total_seconds = AS + BS; + + // 处理秒的进位 + if (total_seconds >= 60) + { + total_minutes += total_seconds / 60; + total_seconds = total_seconds % 60; + } + + // 处理分钟的进位 + if (total_minutes >= 60) + { + total_hours += total_minutes / 60; + total_minutes = total_minutes % 60; + } + + printf("%d %d %d\n", total_hours, total_minutes, total_seconds); + } + + return 0; +} \ No newline at end of file diff --git a/exercise/8.c b/exercise/8.c new file mode 100644 index 0000000..17dff9d --- /dev/null +++ b/exercise/8.c @@ -0,0 +1,124 @@ +#include +#include +#include +#ifdef _WIN32 +#include +#include +#endif + +#define MAX_SIZE 10 + +typedef struct +{ + int data[MAX_SIZE]; // 存储数据的数组 + int length; // 当前顺序表长度 +} List; + +// 初始化顺序表 +void InitList(List *L) +{ + L->length = 0; + memset(L->data, 0, sizeof(L->data)); +} + +// 判断顺序表是否已满 +int IsFull(List *L) +{ + return L->length == MAX_SIZE; +} + +// 在指定位置插入元素 +int InsertLoc(List *L, int loc, int value) +{ + if (IsFull(L)) + { + return 0; + } + if (loc < 1 || loc > L->length + 1) + { + return 0; + } + + // 将插入位置后的元素后移 + for (int i = L->length; i >= loc; i--) + { + L->data[i] = L->data[i - 1]; + } + + // 插入新元素和更新长度 + L->data[loc - 1] = value; + L->length++; + + return 1; +} + +// 显示顺序表内容 +void DisplayList(List *L) +{ + for (int i = 0; i < L->length; i++) + { + printf("%d\n", L->data[i]); + } +} + +int main() +{ + // 设置控制台编码为UTF-8,防止中文乱码 +#ifdef _WIN32 + system("chcp 65001 > nul"); // 设置控制台编码为UTF-8 + SetConsoleOutputCP(65001); // 设置控制台输出编码 + SetConsoleCP(65001); // 设置控制台输入编码 + _mkdir("records"); +#endif + + List L; + InitList(&L); + + // 插入一些元素以测试 + for (int i = 0; i < 9; i++) + { + scanf("%d", &L.data[i]); + L.length++; + } + + // 验证输入数组是否有序 + for (int i = 1; i < L.length; i++) + { + if (L.data[i] < L.data[i - 1]) + { + printf("输入数组未按升序排列\n"); + return 1; + } + } + + // 找到value插入的位置 + int value, loc; + scanf("%d", &value); + // 默认插入到最后 + loc = L.length + 1; + for (int i = 0; i < L.length; i++) + { + if (value <= L.data[i]) + { + loc = i + 1; + break; + } + } + + // 插入元素 + if (L.length >= MAX_SIZE) + { + printf("插入失败:顺序表已满\n"); + return 1; + } + if (!InsertLoc(&L, loc, value)) + { + printf("插入失败\n"); + return 1; + } + + // 显示顺序表内容 + DisplayList(&L); + + return 0; +} \ No newline at end of file diff --git a/exercise/9.c b/exercise/9.c new file mode 100644 index 0000000..13c4ff4 --- /dev/null +++ b/exercise/9.c @@ -0,0 +1,73 @@ +#include +#ifdef _WIN32 +#include +#include +#endif + +// 删除数组中下标为 i 的元素 +void del(int a[], int n, int i) +{ + if (i < 0 || i >= n) + { + printf("下标超出范围\n"); + return; + } + for (int j = i; j < n - 1; j++) + { + a[j] = a[j + 1]; + } +} + +// 输出数组的前 n 个元素 +void PrintArr(int a[], int n) +{ + for (int j = 0; j < n; j++) + { + printf("%d", a[j]); + if (j < n - 1) + { + printf(" "); + } + } + printf("\n"); +} + +int main() +{ + // 设置控制台编码为UTF-8,防止中文乱码 +#ifdef _WIN32 + system("chcp 65001 > nul"); // 设置控制台编码为UTF-8 + SetConsoleOutputCP(65001); // 设置控制台输出编码 + SetConsoleCP(65001); // 设置控制台输入编码 + _mkdir("records"); +#endif + + int n; + scanf("%d", &n); + + if (n <= 0 || n >= 10) + { + printf("数组长度不合法\n"); + return 1; + } + + int a[10]; + for (int i = 0; i < n; i++) + { + scanf("%d", &a[i]); + } + + int index; + scanf("%d", &index); + + if (index < 0 || index >= n) + { + printf("下标超出范围\n"); + return 1; + } + + del(a, n, index); + PrintArr(a, n - 1); + + return 0; +} \ No newline at end of file diff --git a/数据结构/1.c b/数据结构/1.c deleted file mode 100644 index 3f97af3..0000000 --- a/数据结构/1.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include -#include -#ifdef _WIN32 -#include -#include -#endif - -// 计算斐波那契第n项(公式法) -long long fib_binet(int n) -{ - const double phi = (1 + sqrt(5)) / 2; // 黄金分割比 - const double sqrt5 = sqrt(5); // 根号5 - double value = pow(phi, n) / sqrt5; // 核心计算项 - return llround(value); // 四舍五入取整(避免小数误差) -} - -int main() -{ - // 设置控制台编码为UTF-8,防止中文乱码 -#ifdef _WIN32 - system("chcp 65001 > nul"); // 设置控制台编码为UTF-8 - SetConsoleOutputCP(65001); // 设置控制台输出编码 - SetConsoleCP(65001); // 设置控制台输入编码 - _mkdir("records"); -#endif - - // 计算第47项及后续3项(47~50项) - for (int n = 47; n <= 50; n++) - { - long long result = fib_binet(n); - printf("第%d项: %lld\n", n, result); - } - return 0; -} \ No newline at end of file diff --git a/数据结构/未命名.c b/数据结构/未命名.c deleted file mode 100644 index 7161cd6..0000000 --- a/数据结构/未命名.c +++ /dev/null @@ -1,244 +0,0 @@ -#include -#include - -// 宏定义:状态码与元素类型 -typedef int Status; // 函数返回状态 -typedef int SElemType; // 栈元素类型(可根据需求修改,如char、float等) - -// 双栈数据结构定义(题目给定) -typedef struct -{ - int top[2], bot[2]; // 栈顶、栈底指针(top[0]对应0号栈,top[1]对应1号栈) - SElemType *V; // 共享的数组空间 - int m; // 数组最大容量(双栈总容量) -} DblStack; - -/** - * 初始化双栈 - * @param s 双栈指针 - * @param m 数组最大容量 - * @return 初始化成功返回OK,内存分配失败返回OVERFLOW - */ -Status InitDblStack(DblStack *s, int m) -{ - if (m <= 0) - return 0; // 容量无效 - s->V = (SElemType *)malloc(m * sizeof(SElemType)); - if (!s->V) - return -1; // 内存分配失败 - - s->m = m; - // 初始化0号栈:栈底在数组起始位置(索引0),空栈时top[0] = -1 - s->top[0] = -1; - s->bot[0] = 0; - // 初始化1号栈:栈底在数组末尾(索引m-1),空栈时top[1] = m - s->top[1] = m; - s->bot[1] = m - 1; - - return 1; -} - -/** - * 销毁双栈(释放内存) - * @param s 双栈指针 - */ -void DestroyDblStack(DblStack *s) -{ - if (s->V) - { - free(s->V); // 释放数组空间 - s->V = NULL; - } - s->m = 0; - s->top[0] = -1; - s->top[1] = 0; - s->bot[0] = s->bot[1] = 0; -} - -/** - * 判断指定栈是否为空 - * @param s 双栈 - * @param stackNum 栈号(0或1) - * @return 空返回OK,非空返回ERROR,栈号无效返回ERROR - */ -Status IsEmpty(DblStack s, int stackNum) -{ - if (stackNum != 0 && stackNum != 1) - return 0; // 栈号无效 - if (stackNum == 0) - { - return (s.top[0] == -1) ? 1 : 0; // 0号栈空:top[0] = -1 - } - else - { - return (s.top[1] == s.m) ? 1 : 0; // 1号栈空:top[1] = m - } -} - -/** - * 判断双栈是否已满(两栈顶相遇) - * @param s 双栈 - * @return 满返回OK,未满返回ERROR - */ -Status IsFull(DblStack s) -{ - // 0号栈顶的下一个位置等于1号栈顶时,无剩余空间 - return (s.top[0] + 1 == s.top[1]) ? 1 : 0; -} - -/** - * 进栈操作 - * @param s 双栈指针 - * @param stackNum 栈号(0或1) - * @param e 待入栈元素 - * @return 成功返回OK,栈满/栈号无效返回ERROR - */ -Status Push(DblStack *s, int stackNum, SElemType e) -{ - if (stackNum != 0 && stackNum != 1) - return 0; // 栈号无效 - if (IsFull(*s) == 1) - { - printf("双栈已满,无法进栈!\n"); - return 0; - } - - if (stackNum == 0) - { - // 0号栈:栈顶指针上移(+1),元素存入新栈顶 - s->top[0]++; - s->V[s->top[0]] = e; - } - else - { - // 1号栈:栈顶指针下移(-1),元素存入新栈顶 - s->top[1]--; - s->V[s->top[1]] = e; - } - return 1; -} - -/** - * 出栈操作 - * @param s 双栈指针 - * @param stackNum 栈号(0或1) - * @param e 用于接收出栈元素的指针 - * @return 成功返回OK,栈空/栈号无效返回ERROR - */ -Status Pop(DblStack *s, int stackNum, SElemType *e) -{ - if (stackNum != 0 && stackNum != 1) - return 0; // 栈号无效 - if (IsEmpty(*s, stackNum) == 1) - { - printf("栈%d为空,无法出栈!\n", stackNum); - return 0; - } - - if (stackNum == 0) - { - // 0号栈:取出当前栈顶元素,栈顶指针下移(-1) - *e = s->V[s->top[0]]; - s->top[0]--; - } - else - { - // 1号栈:取出当前栈顶元素,栈顶指针上移(+1) - *e = s->V[s->top[1]]; - s->top[1]++; - } - return 1; -} - -/** - * 获取栈顶元素(不弹出) - * @param s 双栈 - * @param stackNum 栈号(0或1) - * @param e 用于接收栈顶元素的指针 - * @return 成功返回OK,栈空/栈号无效返回ERROR - */ -Status GetTop(DblStack s, int stackNum, SElemType *e) -{ - if (stackNum != 0 && stackNum != 1) - return 0; // 栈号无效 - if (IsEmpty(s, stackNum) == 1) - { - printf("栈%d为空,无栈顶元素!\n", stackNum); - return 0; - } - - if (stackNum == 0) - { - *e = s.V[s.top[0]]; // 0号栈顶元素 - } - else - { - *e = s.V[s.top[1]]; // 1号栈顶元素 - } - return 1; -} - -/** - * 测试函数:演示双栈基本操作 - */ -void TestDblStack() -{ - DblStack s; - int m = 5; // 双栈总容量为5 - SElemType e; - - // 初始化双栈 - if (InitDblStack(&s, m) != 1) - { - printf("双栈初始化失败!\n"); - return; - } - printf("初始化双栈成功(容量:%d)\n", m); - - // 测试栈空 - printf("栈0是否为空?%s\n", IsEmpty(s, 0) == 1 ? "是" : "否"); // 是 - printf("栈1是否为空?%s\n", IsEmpty(s, 1) == 1 ? "是" : "否"); // 是 - - // 0号栈进栈 - Push(&s, 0, 10); - Push(&s, 0, 20); - Push(&s, 0, 30); - printf("0号栈进栈元素:10, 20, 30\n"); - GetTop(s, 0, &e); - printf("0号栈顶元素:%d\n", e); // 30 - - // 1号栈进栈 - Push(&s, 1, 100); - Push(&s, 1, 200); - printf("1号栈进栈元素:100, 200\n"); - GetTop(s, 1, &e); - printf("1号栈顶元素:%d\n", e); // 200 - - // 测试栈满(此时0号栈顶=2,1号栈顶=3,2+1=3 → 满) - printf("双栈是否已满?%s\n", IsFull(s) == 1 ? "是" : "否"); // 是 - - // 尝试继续进栈(应失败) - Push(&s, 0, 40); // 提示"双栈已满" - - // 出栈操作 - Pop(&s, 0, &e); - printf("0号栈出栈元素:%d\n", e); // 30 - Pop(&s, 1, &e); - printf("1号栈出栈元素:%d\n", e); // 200 - - // 出栈后栈顶 - GetTop(s, 0, &e); - printf("0号栈顶元素(出栈后):%d\n", e); // 20 - GetTop(s, 1, &e); - printf("1号栈顶元素(出栈后):%d\n", e); // 100 - - // 销毁双栈 - DestroyDblStack(&s); - printf("双栈销毁完成\n"); -} - -int main() -{ - TestDblStack(); - return 0; -} diff --git a/数据结构/课上代码练习/README.md b/数据结构/课上代码练习/README.md index f78df47..d9fa566 100644 --- a/数据结构/课上代码练习/README.md +++ b/数据结构/课上代码练习/README.md @@ -2,6 +2,9 @@ 本目录包含数据结构相关的C语言实现代码,专注于基础数据结构的学习和实践。 +## 仓库地址 +- GitHub仓库为:https://github.com/LHY0125/Learn_C.git + ## 📁 文件列表 ### 核心实现 diff --git a/数据结构/课上代码练习/双栈.c b/数据结构/课上代码练习/双栈.c index 0a70f8f..bb9c14e 100644 --- a/数据结构/课上代码练习/双栈.c +++ b/数据结构/课上代码练习/双栈.c @@ -6,8 +6,7 @@ #include #endif -typedef int Status; // 函数返回状态 -typedef int SElemType; // 栈元素类型 +typedef int SElemType; // 栈元素类型,方便自定义栈的数据类型 typedef struct { @@ -17,7 +16,7 @@ typedef struct } DblStack; // 双栈的初始化 -Status Init(DblStack *s, int m) +int Init(DblStack *s, int m) { // 容量无效 if (m <= 0) @@ -56,7 +55,7 @@ void Destroy(DblStack *s) } // 判断栈是否为空 -Status IsEmpty(DblStack s, int Num) +int IsEmpty(DblStack s, int Num) { // 栈号无效 if (Num != 0 && Num != 1) @@ -91,7 +90,7 @@ Status IsEmpty(DblStack s, int Num) } // 判断双栈是否已满 -Status IsFull(DblStack s) +int IsFull(DblStack s) { // 两栈顶相遇 if (s.top[0] + 1 == s.top[1]) @@ -105,7 +104,7 @@ Status IsFull(DblStack s) } // 进栈操作 -Status Push(DblStack *s, int Num, SElemType e) +int Push(DblStack *s, int Num, SElemType e) { // 栈号无效 if (Num != 0 && Num != 1) @@ -134,7 +133,7 @@ Status Push(DblStack *s, int Num, SElemType e) } // 出栈操作 -Status Pop(DblStack *s, int Num, SElemType *e) +int Pop(DblStack *s, int Num, SElemType *e) { // 栈号无效 if (Num != 0 && Num != 1) @@ -163,7 +162,7 @@ Status Pop(DblStack *s, int Num, SElemType *e) } // 获取栈顶元素 -Status GetTop(DblStack s, int Num, SElemType *e) +int GetTop(DblStack s, int Num, SElemType *e) { // 栈号无效 if (Num != 0 && Num != 1) diff --git a/数据结构/课上代码练习/顺序表的基本操作.c b/数据结构/课上代码练习/顺序表的基本操作.c new file mode 100644 index 0000000..c1b8cae --- /dev/null +++ b/数据结构/课上代码练习/顺序表的基本操作.c @@ -0,0 +1,23 @@ +#include +#include +#include +#ifdef _WIN32 +#include +#include +#endif + + +int main() +{ + // 设置控制台编码为UTF-8,防止中文乱码 +#ifdef _WIN32 + system("chcp 65001 > nul"); // 设置控制台编码为UTF-8 + SetConsoleOutputCP(65001); // 设置控制台输出编码 + SetConsoleCP(65001); // 设置控制台输入编码 + _mkdir("records"); +#endif + + + + return 0; +} \ No newline at end of file diff --git a/数据结构/陈越数据结构/clock.c b/数据结构/陈越数据结构/clock.c index 78e9ae4..3c54afd 100644 --- a/数据结构/陈越数据结构/clock.c +++ b/数据结构/陈越数据结构/clock.c @@ -8,7 +8,6 @@ #include #endif -// clock_t 是一个无符号整数类型,用于表示时钟 ticks 的数量。 clock_t start, stop; // 记录程序运行时间