From f7c41b6bef9b3da96bac04d91c98706ca1371347 Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Fri, 17 Nov 2023 00:29:54 +0800 Subject: [PATCH] fix: Update C code for compatibility with the MSVC compiler (#949) * Replace VLA with malloc Replace VLA with malloc to make C code compatible with cl compiler on Windows. * Fix C code for CI compiler. * Fix C code compability to CI. * check the trigger --- codes/c/chapter_array_and_linkedlist/array.c | 2 +- .../preorder_traversal_i_compact.c | 3 +- .../preorder_traversal_ii_compact.c | 3 +- .../preorder_traversal_iii_compact.c | 3 +- .../preorder_traversal_iii_template.c | 3 +- .../climbing_stairs_constraint_dp.c | 14 ++++- .../chapter_dynamic_programming/coin_change.c | 28 ++++++--- .../coin_change_ii.c | 22 +++++-- .../edit_distance.c | 47 +++++++++----- .../c/chapter_dynamic_programming/knapsack.c | 45 +++++++++----- .../min_cost_climbing_stairs_dp.c | 23 +++---- .../min_path_sum.c | 62 ++++++++++++------- .../unbounded_knapsack.c | 27 +++++--- codes/c/chapter_greedy/CMakeLists.txt | 5 +- codes/c/chapter_greedy/max_capacity.c | 14 +++-- codes/c/chapter_heap/top_k.c | 2 +- codes/c/chapter_stack_and_queue/array_deque.c | 20 ++---- codes/c/chapter_stack_and_queue/array_queue.c | 16 +---- .../linkedlist_deque.c | 3 +- .../linkedlist_queue.c | 3 +- codes/c/utils/print_util.h | 60 +++++++----------- .../preorder_traversal_i_compact.cpp | 2 +- .../preorder_traversal_ii_compact.cpp | 2 +- 23 files changed, 235 insertions(+), 174 deletions(-) diff --git a/codes/c/chapter_array_and_linkedlist/array.c b/codes/c/chapter_array_and_linkedlist/array.c index 217d0cb0..9ab22ff5 100644 --- a/codes/c/chapter_array_and_linkedlist/array.c +++ b/codes/c/chapter_array_and_linkedlist/array.c @@ -76,7 +76,7 @@ int main() { printf("数组 arr = "); printArray(arr, size); - int nums[5] = {1, 3, 2, 5, 4}; + int nums[] = {1, 3, 2, 5, 4}; printf("数组 nums = "); printArray(nums, size); diff --git a/codes/c/chapter_backtracking/preorder_traversal_i_compact.c b/codes/c/chapter_backtracking/preorder_traversal_i_compact.c index 719d54c8..d6ef1f15 100644 --- a/codes/c/chapter_backtracking/preorder_traversal_i_compact.c +++ b/codes/c/chapter_backtracking/preorder_traversal_i_compact.c @@ -36,7 +36,7 @@ int main() { preOrder(root); printf("\n输出所有值为 7 的节点\n"); - int vals[resSize]; + int *vals = malloc(resSize * sizeof(int)); for (int i = 0; i < resSize; i++) { vals[i] = res[i]->val; } @@ -44,5 +44,6 @@ int main() { // 释放内存 freeMemoryTree(root); + free(vals); return 0; } diff --git a/codes/c/chapter_backtracking/preorder_traversal_ii_compact.c b/codes/c/chapter_backtracking/preorder_traversal_ii_compact.c index 2bd580ad..824911d6 100644 --- a/codes/c/chapter_backtracking/preorder_traversal_ii_compact.c +++ b/codes/c/chapter_backtracking/preorder_traversal_ii_compact.c @@ -46,12 +46,13 @@ int main() { printf("\n输出所有根节点到节点 7 的路径\n"); for (int i = 0; i < resSize; ++i) { - int vals[MAX_SIZE]; + int *vals = malloc(MAX_SIZE * sizeof(int)); int size = 0; for (int j = 0; res[i][j] != NULL; ++j) { vals[size++] = res[i][j]->val; } printArray(vals, size); + free(vals); } // 释放内存 diff --git a/codes/c/chapter_backtracking/preorder_traversal_iii_compact.c b/codes/c/chapter_backtracking/preorder_traversal_iii_compact.c index a09accb5..d5269ff2 100644 --- a/codes/c/chapter_backtracking/preorder_traversal_iii_compact.c +++ b/codes/c/chapter_backtracking/preorder_traversal_iii_compact.c @@ -47,12 +47,13 @@ int main() { printf("\n输出所有根节点到节点 7 的路径,要求路径中不包含值为 3 的节点\n"); for (int i = 0; i < resSize; ++i) { - int vals[MAX_SIZE]; + int *vals = malloc(MAX_SIZE * sizeof(int)); int size = 0; for (int j = 0; res[i][j] != NULL; ++j) { vals[size++] = res[i][j]->val; } printArray(vals, size); + free(vals); } // 释放内存 diff --git a/codes/c/chapter_backtracking/preorder_traversal_iii_template.c b/codes/c/chapter_backtracking/preorder_traversal_iii_template.c index db6ae4cb..b02930af 100644 --- a/codes/c/chapter_backtracking/preorder_traversal_iii_template.c +++ b/codes/c/chapter_backtracking/preorder_traversal_iii_template.c @@ -78,12 +78,13 @@ int main() { printf("\n输出所有根节点到节点 7 的路径,要求路径中不包含值为 3 的节点\n"); for (int i = 0; i < resSize; ++i) { - int vals[MAX_SIZE]; + int *vals = malloc(MAX_SIZE * sizeof(int)); int size = 0; for (int j = 0; res[i][j] != NULL; ++j) { vals[size++] = res[i][j]->val; } printArray(vals, size); + free(vals); } // 释放内存 diff --git a/codes/c/chapter_dynamic_programming/climbing_stairs_constraint_dp.c b/codes/c/chapter_dynamic_programming/climbing_stairs_constraint_dp.c index 4752994d..b5356933 100644 --- a/codes/c/chapter_dynamic_programming/climbing_stairs_constraint_dp.c +++ b/codes/c/chapter_dynamic_programming/climbing_stairs_constraint_dp.c @@ -12,8 +12,10 @@ int climbingStairsConstraintDP(int n) { return 1; } // 初始化 dp 表,用于存储子问题的解 - int dp[n + 1][3]; - memset(dp, 0, sizeof(dp)); + int **dp = malloc((n + 1) * sizeof(int *)); + for (int i = 0; i <= n; i++) { + dp[i] = calloc(3, sizeof(int)); + } // 初始状态:预设最小子问题的解 dp[1][1] = 1; dp[1][2] = 0; @@ -24,7 +26,13 @@ int climbingStairsConstraintDP(int n) { dp[i][1] = dp[i - 1][2]; dp[i][2] = dp[i - 2][1] + dp[i - 2][2]; } - return dp[n][1] + dp[n][2]; + int res = dp[n][1] + dp[n][2]; + // 释放内存 + for (int i = 0; i <= n; i++) { + free(dp[i]); + } + free(dp); + return res; } /* Driver Code */ diff --git a/codes/c/chapter_dynamic_programming/coin_change.c b/codes/c/chapter_dynamic_programming/coin_change.c index bc120bbe..f1127e74 100644 --- a/codes/c/chapter_dynamic_programming/coin_change.c +++ b/codes/c/chapter_dynamic_programming/coin_change.c @@ -7,7 +7,7 @@ #include "../utils/common.h" /* 求最小值 */ -int min(int a, int b) { +int myMin(int a, int b) { return a < b ? a : b; } @@ -16,8 +16,10 @@ int coinChangeDP(int coins[], int amt, int coinsSize) { int n = coinsSize; int MAX = amt + 1; // 初始化 dp 表 - int dp[n + 1][amt + 1]; - memset(dp, 0, sizeof(dp)); + int **dp = malloc((n + 1) * sizeof(int *)); + for (int i = 0; i <= n; i++) { + dp[i] = calloc(amt + 1, sizeof(int)); + } // 状态转移:首行首列 for (int a = 1; a <= amt; a++) { dp[0][a] = MAX; @@ -30,11 +32,17 @@ int coinChangeDP(int coins[], int amt, int coinsSize) { dp[i][a] = dp[i - 1][a]; } else { // 不选和选硬币 i 这两种方案的较小值 - dp[i][a] = min(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1); + dp[i][a] = myMin(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1); } } } - return dp[n][amt] != MAX ? dp[n][amt] : -1; + int res = dp[n][amt] != MAX ? dp[n][amt] : -1; + // 释放内存 + for (int i = 0; i <= n; i++) { + free(dp[i]); + } + free(dp); + return res; } /* 零钱兑换:空间优化后的动态规划 */ @@ -42,8 +50,7 @@ int coinChangeDPComp(int coins[], int amt, int coinsSize) { int n = coinsSize; int MAX = amt + 1; // 初始化 dp 表 - int dp[amt + 1]; - memset(dp, MAX, sizeof(dp)); + int *dp = calloc(amt + 1, sizeof(int)); dp[0] = 0; // 状态转移 for (int i = 1; i <= n; i++) { @@ -53,11 +60,14 @@ int coinChangeDPComp(int coins[], int amt, int coinsSize) { dp[a] = dp[a]; } else { // 不选和选硬币 i 这两种方案的较小值 - dp[a] = min(dp[a], dp[a - coins[i - 1]] + 1); + dp[a] = myMin(dp[a], dp[a - coins[i - 1]] + 1); } } } - return dp[amt] != MAX ? dp[amt] : -1; + int res = dp[amt] != MAX ? dp[amt] : -1; + // 释放内存 + free(dp); + return res; } /* Driver code */ diff --git a/codes/c/chapter_dynamic_programming/coin_change_ii.c b/codes/c/chapter_dynamic_programming/coin_change_ii.c index 6b43a2d0..17470285 100644 --- a/codes/c/chapter_dynamic_programming/coin_change_ii.c +++ b/codes/c/chapter_dynamic_programming/coin_change_ii.c @@ -10,8 +10,10 @@ int coinChangeIIDP(int coins[], int amt, int coinsSize) { int n = coinsSize; // 初始化 dp 表 - int dp[n + 1][amt + 1]; - memset(dp, 0, sizeof(dp)); + int **dp = malloc((n + 1) * sizeof(int *)); + for (int i = 0; i <= n; i++) { + dp[i] = calloc(amt + 1, sizeof(int)); + } // 初始化首列 for (int i = 0; i <= n; i++) { dp[i][0] = 1; @@ -28,15 +30,20 @@ int coinChangeIIDP(int coins[], int amt, int coinsSize) { } } } - return dp[n][amt]; + int res = dp[n][amt]; + // 释放内存 + for (int i = 0; i <= n; i++) { + free(dp[i]); + } + free(dp); + return res; } /* 零钱兑换 II:空间优化后的动态规划 */ int coinChangeIIDPComp(int coins[], int amt, int coinsSize) { int n = coinsSize; // 初始化 dp 表 - int dp[amt + 1]; - memset(dp, 0, sizeof(dp)); + int *dp = calloc(amt + 1, sizeof(int)); dp[0] = 1; // 状态转移 for (int i = 1; i <= n; i++) { @@ -50,7 +57,10 @@ int coinChangeIIDPComp(int coins[], int amt, int coinsSize) { } } } - return dp[amt]; + int res = dp[amt]; + // 释放内存 + free(dp); + return res; } /* Driver code */ diff --git a/codes/c/chapter_dynamic_programming/edit_distance.c b/codes/c/chapter_dynamic_programming/edit_distance.c index 5144e12d..229eabe2 100644 --- a/codes/c/chapter_dynamic_programming/edit_distance.c +++ b/codes/c/chapter_dynamic_programming/edit_distance.c @@ -7,12 +7,12 @@ #include "../utils/common.h" /* 求最小值 */ -int min(int a, int b) { +int myMin(int a, int b) { return a < b ? a : b; } /* 编辑距离:暴力搜索 */ -int editDistanceDFS(char *s, char *t, int i, int j) { +int editDistanceDFS(char *s, char *t, int i, int j) { // 若 s 和 t 都为空,则返回 0 if (i == 0 && j == 0) return 0; @@ -30,11 +30,11 @@ int editDistanceDFS(char *s, char *t, int i, int j) { int del = editDistanceDFS(s, t, i - 1, j); int replace = editDistanceDFS(s, t, i - 1, j - 1); // 返回最少编辑步数 - return min(min(insert, del), replace) + 1; + return myMin(myMin(insert, del), replace) + 1; } /* 编辑距离:记忆化搜索 */ -int editDistanceDFSMem(char *s, char *t, int memCols, int mem[][memCols], int i, int j) { +int editDistanceDFSMem(char *s, char *t, int memCols, int **mem, int i, int j) { // 若 s 和 t 都为空,则返回 0 if (i == 0 && j == 0) return 0; @@ -55,14 +55,16 @@ int editDistanceDFSMem(char *s, char *t, int memCols, int mem[][memCols], int i, int del = editDistanceDFSMem(s, t, memCols, mem, i - 1, j); int replace = editDistanceDFSMem(s, t, memCols, mem, i - 1, j - 1); // 记录并返回最少编辑步数 - mem[i][j] = min(min(insert, del), replace) + 1; + mem[i][j] = myMin(myMin(insert, del), replace) + 1; return mem[i][j]; } /* 编辑距离:动态规划 */ int editDistanceDP(char *s, char *t, int n, int m) { - int dp[n + 1][m + 1]; - memset(dp, 0, sizeof(dp)); + int **dp = malloc((n + 1) * sizeof(int *)); + for (int i = 0; i <= n; i++) { + dp[i] = calloc(m + 1, sizeof(int)); + } // 状态转移:首行首列 for (int i = 1; i <= n; i++) { dp[i][0] = i; @@ -78,17 +80,21 @@ int editDistanceDP(char *s, char *t, int n, int m) { dp[i][j] = dp[i - 1][j - 1]; } else { // 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1 - dp[i][j] = min(min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; + dp[i][j] = myMin(myMin(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; } } } - return dp[n][m]; + int res = dp[n][m]; + // 释放内存 + for (int i = 0; i <= n; i++) { + free(dp[i]); + } + return res; } /* 编辑距离:空间优化后的动态规划 */ int editDistanceDPComp(char *s, char *t, int n, int m) { - int dp[m + 1]; - memset(dp, 0, sizeof(dp)); + int *dp = calloc(m + 1, sizeof(int)); // 状态转移:首行 for (int j = 1; j <= m; j++) { dp[j] = j; @@ -106,12 +112,15 @@ int editDistanceDPComp(char *s, char *t, int n, int m) { dp[j] = leftup; } else { // 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1 - dp[j] = min(min(dp[j - 1], dp[j]), leftup) + 1; + dp[j] = myMin(myMin(dp[j - 1], dp[j]), leftup) + 1; } leftup = temp; // 更新为下一轮的 dp[i-1, j-1] } } - return dp[m]; + int res = dp[m]; + // 释放内存 + free(dp); + return res; } /* Driver Code */ @@ -125,10 +134,18 @@ int main() { printf("将 %s 更改为 %s 最少需要编辑 %d 步\n", s, t, res); // 记忆化搜索 - int mem[n + 1][m + 1]; - memset(mem, -1, sizeof(mem)); + int **mem = malloc((n + 1) * sizeof(int *)); + for (int i = 0; i <= n; i++) { + mem[i] = malloc((m + 1) * sizeof(int)); + memset(mem[i], -1, (m + 1) * sizeof(int)); + } res = editDistanceDFSMem(s, t, m + 1, mem, n, m); printf("将 %s 更改为 %s 最少需要编辑 %d 步\n", s, t, res); + // 释放内存 + for (int i = 0; i <= n; i++) { + free(mem[i]); + } + free(mem); // 动态规划 res = editDistanceDP(s, t, n, m); diff --git a/codes/c/chapter_dynamic_programming/knapsack.c b/codes/c/chapter_dynamic_programming/knapsack.c index 4b6239db..19b1f232 100644 --- a/codes/c/chapter_dynamic_programming/knapsack.c +++ b/codes/c/chapter_dynamic_programming/knapsack.c @@ -7,7 +7,7 @@ #include "../utils/common.h" /* 求最大值 */ -int max(int a, int b) { +int myMax(int a, int b) { return a > b ? a : b; } @@ -25,11 +25,11 @@ int knapsackDFS(int wgt[], int val[], int i, int c) { int no = knapsackDFS(wgt, val, i - 1, c); int yes = knapsackDFS(wgt, val, i - 1, c - wgt[i - 1]) + val[i - 1]; // 返回两种方案中价值更大的那一个 - return max(no, yes); + return myMax(no, yes); } /* 0-1 背包:记忆化搜索 */ -int knapsackDFSMem(int wgt[], int val[], int memCols, int mem[][memCols], int i, int c) { +int knapsackDFSMem(int wgt[], int val[], int memCols, int **mem, int i, int c) { // 若已选完所有物品或背包无容量,则返回价值 0 if (i == 0 || c == 0) { return 0; @@ -46,7 +46,7 @@ int knapsackDFSMem(int wgt[], int val[], int memCols, int mem[][memCols], int i, int no = knapsackDFSMem(wgt, val, memCols, mem, i - 1, c); int yes = knapsackDFSMem(wgt, val, memCols, mem, i - 1, c - wgt[i - 1]) + val[i - 1]; // 记录并返回两种方案中价值更大的那一个 - mem[i][c] = max(no, yes); + mem[i][c] = myMax(no, yes); return mem[i][c]; } @@ -54,8 +54,10 @@ int knapsackDFSMem(int wgt[], int val[], int memCols, int mem[][memCols], int i, int knapsackDP(int wgt[], int val[], int cap, int wgtSize) { int n = wgtSize; // 初始化 dp 表 - int dp[n + 1][cap + 1]; - memset(dp, 0, sizeof(dp)); + int **dp = malloc((n + 1) * sizeof(int *)); + for (int i = 0; i <= n; i++) { + dp[i] = calloc(cap + 1, sizeof(int)); + } // 状态转移 for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { @@ -64,30 +66,37 @@ int knapsackDP(int wgt[], int val[], int cap, int wgtSize) { dp[i][c] = dp[i - 1][c]; } else { // 不选和选物品 i 这两种方案的较大值 - dp[i][c] = max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1]); + dp[i][c] = myMax(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1]); } } } - return dp[n][cap]; + int res = dp[n][cap]; + // 释放内存 + for (int i = 0; i <= n; i++) { + free(dp[i]); + } + return res; } /* 0-1 背包:空间优化后的动态规划 */ int knapsackDPComp(int wgt[], int val[], int cap, int wgtSize) { int n = wgtSize; // 初始化 dp 表 - int dp[cap + 1]; - memset(dp, 0, sizeof(dp)); + int *dp = calloc(cap + 1, sizeof(int)); // 状态转移 for (int i = 1; i <= n; i++) { // 倒序遍历 for (int c = cap; c >= 1; c--) { if (wgt[i - 1] <= c) { // 不选和选物品 i 这两种方案的较大值 - dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]); + dp[c] = myMax(dp[c], dp[c - wgt[i - 1]] + val[i - 1]); } } } - return dp[cap]; + int res = dp[cap]; + // 释放内存 + free(dp); + return res; } /* Driver Code */ @@ -103,10 +112,18 @@ int main() { printf("不超过背包容量的最大物品价值为 %d\n", res); // 记忆化搜索 - int mem[n + 1][cap + 1]; - memset(mem, -1, sizeof(mem)); + int **mem = malloc((n + 1) * sizeof(int *)); + for (int i = 0; i <= n; i++) { + mem[i] = malloc((cap + 1) * sizeof(int)); + memset(mem[i], -1, (cap + 1) * sizeof(int)); + } res = knapsackDFSMem(wgt, val, cap + 1, mem, n, cap); printf("不超过背包容量的最大物品价值为 %d\n", res); + // 释放内存 + for (int i = 0; i <= n; i++) { + free(mem[i]); + } + free(mem); // 动态规划 res = knapsackDP(wgt, val, cap, wgtSize); diff --git a/codes/c/chapter_dynamic_programming/min_cost_climbing_stairs_dp.c b/codes/c/chapter_dynamic_programming/min_cost_climbing_stairs_dp.c index fad9a218..48ec8452 100644 --- a/codes/c/chapter_dynamic_programming/min_cost_climbing_stairs_dp.c +++ b/codes/c/chapter_dynamic_programming/min_cost_climbing_stairs_dp.c @@ -7,7 +7,7 @@ #include "../utils/common.h" /* 求最小值 */ -int min(int a, int b) { +int myMin(int a, int b) { return a < b ? a : b; } @@ -17,15 +17,18 @@ int minCostClimbingStairsDP(int cost[], int costSize) { if (n == 1 || n == 2) return cost[n]; // 初始化 dp 表,用于存储子问题的解 - int dp[n + 1]; + int *dp = calloc(n + 1, sizeof(int)); // 初始状态:预设最小子问题的解 dp[1] = cost[1]; dp[2] = cost[2]; // 状态转移:从较小子问题逐步求解较大子问题 for (int i = 3; i <= n; i++) { - dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i]; + dp[i] = myMin(dp[i - 1], dp[i - 2]) + cost[i]; } - return dp[n]; + int res = dp[n]; + // 释放内存 + free(dp); + return res; } /* 爬楼梯最小代价:空间优化后的动态规划 */ @@ -36,7 +39,7 @@ int minCostClimbingStairsDPComp(int cost[], int costSize) { int a = cost[1], b = cost[2]; for (int i = 3; i <= n; i++) { int tmp = b; - b = min(a, tmp) + cost[i]; + b = myMin(a, tmp) + cost[i]; a = tmp; } return b; @@ -46,14 +49,8 @@ int minCostClimbingStairsDPComp(int cost[], int costSize) { int main() { int cost[] = {0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1}; int costSize = sizeof(cost) / sizeof(cost[0]); - printf("输入楼梯的代价列表为 ["); - for (int i = 0; i < costSize; i++) { - if (i != costSize - 1) - printf("%d, ", cost[i]); - else - printf("%d", cost[i]); - } - printf("]\n"); + printf("输入楼梯的代价列表为:"); + printArray(cost, costSize); int res = minCostClimbingStairsDP(cost, costSize); printf("爬完楼梯的最低代价为 %d\n", res); diff --git a/codes/c/chapter_dynamic_programming/min_path_sum.c b/codes/c/chapter_dynamic_programming/min_path_sum.c index bbc604fc..e4a7b78c 100644 --- a/codes/c/chapter_dynamic_programming/min_path_sum.c +++ b/codes/c/chapter_dynamic_programming/min_path_sum.c @@ -6,13 +6,16 @@ #include "../utils/common.h" +// 假设矩阵最大行列数为 100 +#define MAX_SIZE 100 + /* 求最小值 */ -int min(int a, int b) { +int myMin(int a, int b) { return a < b ? a : b; } /* 最小路径和:暴力搜索 */ -int minPathSumDFS(int gridCols, int grid[][gridCols], int i, int j) { +int minPathSumDFS(int grid[MAX_SIZE][MAX_SIZE], int i, int j) { // 若为左上角单元格,则终止搜索 if (i == 0 && j == 0) { return grid[0][0]; @@ -22,14 +25,14 @@ int minPathSumDFS(int gridCols, int grid[][gridCols], int i, int j) { return INT_MAX; } // 计算从左上角到 (i-1, j) 和 (i, j-1) 的最小路径代价 - int up = minPathSumDFS(gridCols, grid, i - 1, j); - int left = minPathSumDFS(gridCols, grid, i, j - 1); + int up = minPathSumDFS(grid, i - 1, j); + int left = minPathSumDFS(grid, i, j - 1); // 返回从左上角到 (i, j) 的最小路径代价 - return min(left, up) != INT_MAX ? min(left, up) + grid[i][j] : INT_MAX; + return myMin(left, up) != INT_MAX ? myMin(left, up) + grid[i][j] : INT_MAX; } /* 最小路径和:记忆化搜索 */ -int minPathSumDFSMem(int gridCols, int grid[][gridCols], int mem[][gridCols], int i, int j) { +int minPathSumDFSMem(int grid[MAX_SIZE][MAX_SIZE], int mem[MAX_SIZE][MAX_SIZE], int i, int j) { // 若为左上角单元格,则终止搜索 if (i == 0 && j == 0) { return grid[0][0]; @@ -43,17 +46,20 @@ int minPathSumDFSMem(int gridCols, int grid[][gridCols], int mem[][gridCols], in return mem[i][j]; } // 左边和上边单元格的最小路径代价 - int up = minPathSumDFSMem(gridCols, grid, mem, i - 1, j); - int left = minPathSumDFSMem(gridCols, grid, mem, i, j - 1); + int up = minPathSumDFSMem(grid, mem, i - 1, j); + int left = minPathSumDFSMem(grid, mem, i, j - 1); // 记录并返回左上角到 (i, j) 的最小路径代价 - mem[i][j] = min(left, up) != INT_MAX ? min(left, up) + grid[i][j] : INT_MAX; + mem[i][j] = myMin(left, up) != INT_MAX ? myMin(left, up) + grid[i][j] : INT_MAX; return mem[i][j]; } /* 最小路径和:动态规划 */ -int minPathSumDP(int gridCols, int grid[][gridCols], int n, int m) { +int minPathSumDP(int grid[MAX_SIZE][MAX_SIZE], int n, int m) { // 初始化 dp 表 - int dp[n][m]; + int **dp = malloc(n * sizeof(int *)); + for (int i = 0; i < n; i++) { + dp[i] = calloc(m, sizeof(int)); + } dp[0][0] = grid[0][0]; // 状态转移:首行 for (int j = 1; j < m; j++) { @@ -66,16 +72,21 @@ int minPathSumDP(int gridCols, int grid[][gridCols], int n, int m) { // 状态转移:其余行列 for (int i = 1; i < n; i++) { for (int j = 1; j < m; j++) { - dp[i][j] = min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]; + dp[i][j] = myMin(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]; } } - return dp[n - 1][m - 1]; + int res = dp[n - 1][m - 1]; + // 释放内存 + for (int i = 0; i < n; i++) { + free(dp[i]); + } + return res; } /* 最小路径和:空间优化后的动态规划 */ -int minPathSumDPComp(int gridCols, int grid[][gridCols], int n, int m) { +int minPathSumDPComp(int grid[MAX_SIZE][MAX_SIZE], int n, int m) { // 初始化 dp 表 - int dp[m]; + int *dp = calloc(m, sizeof(int)); // 状态转移:首行 dp[0] = grid[0][0]; for (int j = 1; j < m; j++) { @@ -87,33 +98,36 @@ int minPathSumDPComp(int gridCols, int grid[][gridCols], int n, int m) { dp[0] = dp[0] + grid[i][0]; // 状态转移:其余列 for (int j = 1; j < m; j++) { - dp[j] = min(dp[j - 1], dp[j]) + grid[i][j]; + dp[j] = myMin(dp[j - 1], dp[j]) + grid[i][j]; } } - return dp[m - 1]; + int res = dp[m - 1]; + // 释放内存 + free(dp); + return res; } /* Driver Code */ int main() { - int grid[][4] = {{1, 3, 1, 5}, {2, 2, 4, 2}, {5, 3, 2, 1}, {4, 3, 5, 2}}; - int n = sizeof(grid) / sizeof(grid[0]), m = sizeof(grid[0]) / sizeof(grid[0][0]); + int grid[MAX_SIZE][MAX_SIZE] = {{1, 3, 1, 5}, {2, 2, 4, 2}, {5, 3, 2, 1}, {4, 3, 5, 2}}; + int n = 4, m = 4; // 矩阵容量为 MAX_SIZE * MAX_SIZE ,有效行列数为 n * m // 暴力搜索 - int res = minPathSumDFS(m, grid, n - 1, m - 1); + int res = minPathSumDFS(grid, n - 1, m - 1); printf("从左上角到右下角的最小路径和为 %d\n", res); // 记忆化搜索 - int mem[n][m]; + int mem[MAX_SIZE][MAX_SIZE]; memset(mem, -1, sizeof(mem)); - res = minPathSumDFSMem(m, grid, mem, n - 1, m - 1); + res = minPathSumDFSMem(grid, mem, n - 1, m - 1); printf("从左上角到右下角的最小路径和为 %d\n", res); // 动态规划 - res = minPathSumDP(m, grid, n, m); + res = minPathSumDP(grid, n, m); printf("从左上角到右下角的最小路径和为 %d\n", res); // 空间优化后的动态规划 - res = minPathSumDPComp(m, grid, n, m); + res = minPathSumDPComp(grid, n, m); printf("从左上角到右下角的最小路径和为 %d\n", res); return 0; diff --git a/codes/c/chapter_dynamic_programming/unbounded_knapsack.c b/codes/c/chapter_dynamic_programming/unbounded_knapsack.c index ac221f73..9dbde412 100644 --- a/codes/c/chapter_dynamic_programming/unbounded_knapsack.c +++ b/codes/c/chapter_dynamic_programming/unbounded_knapsack.c @@ -7,7 +7,7 @@ #include "../utils/common.h" /* 求最大值 */ -int max(int a, int b) { +int myMax(int a, int b) { return a > b ? a : b; } @@ -15,8 +15,10 @@ int max(int a, int b) { int unboundedKnapsackDP(int wgt[], int val[], int cap, int wgtSize) { int n = wgtSize; // 初始化 dp 表 - int dp[n + 1][cap + 1]; - memset(dp, 0, sizeof(dp)); + int **dp = malloc((n + 1) * sizeof(int *)); + for (int i = 0; i <= n; i++) { + dp[i] = calloc(cap + 1, sizeof(int)); + } // 状态转移 for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { @@ -25,19 +27,23 @@ int unboundedKnapsackDP(int wgt[], int val[], int cap, int wgtSize) { dp[i][c] = dp[i - 1][c]; } else { // 不选和选物品 i 这两种方案的较大值 - dp[i][c] = max(dp[i - 1][c], dp[i][c - wgt[i - 1]] + val[i - 1]); + dp[i][c] = myMax(dp[i - 1][c], dp[i][c - wgt[i - 1]] + val[i - 1]); } } } - return dp[n][cap]; + int res = dp[n][cap]; + // 释放内存 + for (int i = 0; i <= n; i++) { + free(dp[i]); + } + return res; } /* 完全背包:空间优化后的动态规划 */ int unboundedKnapsackDPComp(int wgt[], int val[], int cap, int wgtSize) { int n = wgtSize; // 初始化 dp 表 - int dp[cap + 1]; - memset(dp, 0, sizeof(dp)); + int *dp = calloc(cap + 1, sizeof(int)); // 状态转移 for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { @@ -46,11 +52,14 @@ int unboundedKnapsackDPComp(int wgt[], int val[], int cap, int wgtSize) { dp[c] = dp[c]; } else { // 不选和选物品 i 这两种方案的较大值 - dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]); + dp[c] = myMax(dp[c], dp[c - wgt[i - 1]] + val[i - 1]); } } } - return dp[cap]; + int res = dp[cap]; + // 释放内存 + free(dp); + return res; } /* Driver code */ diff --git a/codes/c/chapter_greedy/CMakeLists.txt b/codes/c/chapter_greedy/CMakeLists.txt index 8c428ebd..b8e6ca42 100644 --- a/codes/c/chapter_greedy/CMakeLists.txt +++ b/codes/c/chapter_greedy/CMakeLists.txt @@ -2,4 +2,7 @@ add_executable(coin_change_greedy coin_change_greedy.c) add_executable(fractional_knapsack fractional_knapsack.c) add_executable(max_capacity max_capacity.c) add_executable(max_product_cutting max_product_cutting.c) -target_link_libraries(max_product_cutting m) + +if (NOT CMAKE_C_COMPILER_ID STREQUAL "MSVC") + target_link_libraries(max_product_cutting m) +endif() diff --git a/codes/c/chapter_greedy/max_capacity.c b/codes/c/chapter_greedy/max_capacity.c index 3b1dcb11..6b13aea2 100644 --- a/codes/c/chapter_greedy/max_capacity.c +++ b/codes/c/chapter_greedy/max_capacity.c @@ -6,8 +6,14 @@ #include "../utils/common.h" -#define MIN(a, b) (a < b ? a : b) -#define MAX(a, b) (a > b ? a : b) +/* 求最小值 */ +int myMin(int a, int b) { + return a < b ? a : b; +} +/* 求最大值 */ +int myMax(int a, int b) { + return a < b ? a : b; +} /* 最大容量:贪心 */ int maxCapacity(int ht[], int htLength) { @@ -19,8 +25,8 @@ int maxCapacity(int ht[], int htLength) { // 循环贪心选择,直至两板相遇 while (i < j) { // 更新最大容量 - int capacity = MIN(ht[i], ht[j]) * (j - i); - res = MAX(res, capacity); + int capacity = myMin(ht[i], ht[j]) * (j - i); + res = myMax(res, capacity); // 向内移动短板 if (ht[i] < ht[j]) { i++; diff --git a/codes/c/chapter_heap/top_k.c b/codes/c/chapter_heap/top_k.c index e7049510..98165f0f 100644 --- a/codes/c/chapter_heap/top_k.c +++ b/codes/c/chapter_heap/top_k.c @@ -38,7 +38,7 @@ int *getMinHeap(MaxHeap *maxHeap) { int *topKHeap(int *nums, int sizeNums, int k) { // 初始化小顶堆 // 请注意:我们将堆中所有元素取反,从而用大顶堆来模拟小顶堆 - int empty[0]; + int *empty = (int *)malloc(0); MaxHeap *maxHeap = newMaxHeap(empty, 0); // 将数组的前 k 个元素入堆 for (int i = 0; i < k; i++) { diff --git a/codes/c/chapter_stack_and_queue/array_deque.c b/codes/c/chapter_stack_and_queue/array_deque.c index 38a6cdfe..8c1a6a33 100644 --- a/codes/c/chapter_stack_and_queue/array_deque.c +++ b/codes/c/chapter_stack_and_queue/array_deque.c @@ -111,16 +111,6 @@ int popLast(ArrayDeque *deque) { return num; } -/* 打印队列 */ -void printArrayDeque(ArrayDeque *deque) { - int arr[deque->queSize]; - // 拷贝 - for (int i = 0, j = deque->front; i < deque->queSize; i++, j++) { - arr[i] = deque->nums[j % deque->queCapacity]; - } - printArray(arr, deque->queSize); -} - /* Driver Code */ int main() { /* 初始化队列 */ @@ -130,7 +120,7 @@ int main() { pushLast(deque, 2); pushLast(deque, 5); printf("双向队列 deque = "); - printArrayDeque(deque); + printArray(deque->nums, deque->queSize); /* 访问元素 */ int peekFirstNum = peekFirst(deque); @@ -141,18 +131,18 @@ int main() { /* 元素入队 */ pushLast(deque, 4); printf("元素 4 队尾入队后 deque = "); - printArrayDeque(deque); + printArray(deque->nums, deque->queSize); pushFirst(deque, 1); printf("元素 1 队首入队后 deque = "); - printArrayDeque(deque); + printArray(deque->nums, deque->queSize); /* 元素出队 */ int popLastNum = popLast(deque); printf("队尾出队元素 = %d ,队尾出队后 deque= ", popLastNum); - printArrayDeque(deque); + printArray(deque->nums, deque->queSize); int popFirstNum = popFirst(deque); printf("队首出队元素 = %d ,队首出队后 deque= ", popFirstNum); - printArrayDeque(deque); + printArray(deque->nums, deque->queSize); /* 获取队列的长度 */ int dequeSize = size(deque); diff --git a/codes/c/chapter_stack_and_queue/array_queue.c b/codes/c/chapter_stack_and_queue/array_queue.c index f8251e32..9c7ea3e9 100644 --- a/codes/c/chapter_stack_and_queue/array_queue.c +++ b/codes/c/chapter_stack_and_queue/array_queue.c @@ -73,16 +73,6 @@ void pop(ArrayQueue *queue) { queue->queSize--; } -/* 打印队列 */ -void printArrayQueue(ArrayQueue *queue) { - int arr[queue->queSize]; - // 拷贝 - for (int i = 0, j = queue->front; i < queue->queSize; i++, j++) { - arr[i] = queue->nums[j % queue->queCapacity]; - } - printArray(arr, queue->queSize); -} - /* Driver Code */ int main() { /* 初始化队列 */ @@ -96,7 +86,7 @@ int main() { push(queue, 5); push(queue, 4); printf("队列 queue = "); - printArrayQueue(queue); + printArray(queue->nums, queue->queSize); /* 访问队首元素 */ int peekNum = peek(queue); @@ -105,7 +95,7 @@ int main() { /* 元素出队 */ pop(queue); printf("出队元素 pop = %d ,出队后 queue = ", peekNum); - printArrayQueue(queue); + printArray(queue->nums, queue->queSize); /* 获取队列的长度 */ int queueSize = size(queue); @@ -120,7 +110,7 @@ int main() { push(queue, i); pop(queue); printf("第 %d 轮入队 + 出队后 queue = ", i); - printArrayQueue(queue); + printArray(queue->nums, queue->queSize); } // 释放内存 diff --git a/codes/c/chapter_stack_and_queue/linkedlist_deque.c b/codes/c/chapter_stack_and_queue/linkedlist_deque.c index 6152f4e9..6501d4af 100644 --- a/codes/c/chapter_stack_and_queue/linkedlist_deque.c +++ b/codes/c/chapter_stack_and_queue/linkedlist_deque.c @@ -153,7 +153,7 @@ int popLast(LinkedListDeque *deque) { /* 打印队列 */ void printLinkedListDeque(LinkedListDeque *deque) { - int arr[deque->queSize]; + int *arr = malloc(sizeof(int) * deque->queSize); // 拷贝链表中的数据到数组 int i; DoublyListNode *node; @@ -162,6 +162,7 @@ void printLinkedListDeque(LinkedListDeque *deque) { node = node->next; } printArray(arr, deque->queSize); + free(arr); } /* Driver Code */ diff --git a/codes/c/chapter_stack_and_queue/linkedlist_queue.c b/codes/c/chapter_stack_and_queue/linkedlist_queue.c index 9dd97e5e..df73857f 100644 --- a/codes/c/chapter_stack_and_queue/linkedlist_queue.c +++ b/codes/c/chapter_stack_and_queue/linkedlist_queue.c @@ -77,7 +77,7 @@ void pop(LinkedListQueue *queue) { /* 打印队列 */ void printLinkedListQueue(LinkedListQueue *queue) { - int arr[queue->queSize]; + int *arr = malloc(sizeof(int) * queue->queSize); // 拷贝链表中的数据到数组 int i; ListNode *node; @@ -86,6 +86,7 @@ void printLinkedListQueue(LinkedListQueue *queue) { node = node->next; } printArray(arr, queue->queSize); + free(arr); } /* Driver Code */ diff --git a/codes/c/utils/print_util.h b/codes/c/utils/print_util.h index d2714fa4..57699b0b 100644 --- a/codes/c/utils/print_util.h +++ b/codes/c/utils/print_util.h @@ -19,49 +19,33 @@ extern "C" { #endif /* Print an Array */ -static void printArray(int arr[], int size) { - printf("["); - if (arr != NULL && size != 0) { - for (int i = 0; i < size - 1; i++) { - if (arr[i] != INT_MAX) { - printf("%d, ", arr[i]); - } else { - printf("NULL, "); - } - } - if (arr[size - 1] != INT_MAX) { - printf("%d]\n", arr[size - 1]); - } else { - printf("NULL]\n"); - } - } else { - printf("]\n"); +void printArray(int arr[], int size) { + if (arr == NULL || size == 0) { + printf("[]"); + return; } + printf("["); + for (int i = 0; i < size - 1; i++) { + printf("%d, ", arr[i]); + } + printf("%d]\n", arr[size - 1]); } /* Print an Array */ -static void printArrayFloat(float arr[], int size) { - printf("["); - if (arr != NULL && size != 0) { - for (int i = 0; i < size - 1; i++) { - if (arr[i] != INT_MAX) { - printf("%.2f, ", arr[i]); - } else { - printf("NULL, "); - } - } - if (arr[size - 1] != INT_MAX) { - printf("%.2f]\n", arr[size - 1]); - } else { - printf("NULL]\n"); - } - } else { - printf("]"); +void printArrayFloat(float arr[], int size) { + if (arr == NULL || size == 0) { + printf("[]"); + return; } + printf("["); + for (int i = 0; i < size - 1; i++) { + printf("%.2f, ", arr[i]); + } + printf("%.2f]\n", arr[size - 1]); } /* Print a linked list */ -static void printLinkedList(ListNode *node) { +void printLinkedList(ListNode *node) { if (node == NULL) { return; } @@ -95,7 +79,7 @@ void showTrunks(Trunk *trunk) { } /* Help to print a binary tree, hide more details */ -static void printTreeHelper(TreeNode *node, Trunk *prev, bool isRight) { +void printTreeHelper(TreeNode *node, Trunk *prev, bool isRight) { if (node == NULL) { return; } @@ -123,12 +107,12 @@ static void printTreeHelper(TreeNode *node, Trunk *prev, bool isRight) { } /* Print a binary tree */ -static void printTree(TreeNode *root) { +void printTree(TreeNode *root) { printTreeHelper(root, NULL, false); } /* Print a Heap */ -static void printHeap(int arr[], int size) { +void printHeap(int arr[], int size) { TreeNode *root; printf("堆的数组表示:"); printArray(arr, size); diff --git a/codes/cpp/chapter_backtracking/preorder_traversal_i_compact.cpp b/codes/cpp/chapter_backtracking/preorder_traversal_i_compact.cpp index 46b21812..fa0a08ed 100644 --- a/codes/cpp/chapter_backtracking/preorder_traversal_i_compact.cpp +++ b/codes/cpp/chapter_backtracking/preorder_traversal_i_compact.cpp @@ -9,7 +9,7 @@ vector res; /* 前序遍历:例题一 */ -static void preOrder(TreeNode *root) { +void preOrder(TreeNode *root) { if (root == nullptr) { return; } diff --git a/codes/cpp/chapter_backtracking/preorder_traversal_ii_compact.cpp b/codes/cpp/chapter_backtracking/preorder_traversal_ii_compact.cpp index bb810afd..26dc7fc4 100644 --- a/codes/cpp/chapter_backtracking/preorder_traversal_ii_compact.cpp +++ b/codes/cpp/chapter_backtracking/preorder_traversal_ii_compact.cpp @@ -10,7 +10,7 @@ vector path; vector> res; /* 前序遍历:例题二 */ -static void preOrder(TreeNode *root) { +void preOrder(TreeNode *root) { if (root == nullptr) { return; }