From 8f5ef68c65abbd933a7fc52dc089a16fbede8648 Mon Sep 17 00:00:00 2001 From: gonglja <39959756+Gonglja@users.noreply.github.com> Date: Sat, 29 Jul 2023 15:14:01 +0800 Subject: [PATCH] feat: Add C codes for the chapter backtracking (#593) * fix(codes/cpp): Memory leak fix: the space was not freed when pop removed the element. * fix(codes/cpp): Fix access error when printArray(arr, 0) * Update PrintUtil.hpp * fix(codes/c): Fix some errors of cmake build * feat(codes/c): Add hashing_search.c * styles(codes/c): Modify function description * styles(codes/c): Modify binary_search.c code style * fix(codes/c): Fix the problem in binary_tree_bfs.c and the problem that the memory is not released. * feat: Add preorder_traversal_i_compact.c * feat(codes/c): Add head_sort.c * feat(codes/c): Add bucket_sort.c * feat(codes/c): Add binary_search_edge.c * fix(codes/c): Add programs that are not managed by cmake (c code) * feat(codes/c): Add selection_sort.c * style(codes/c): Change swap in selection_sort.c to `selectionSort` * styles(codes/c): Change style. * fix(codes/c): Fix some formatting errors and temporarily remove backtracking chapters * feat(codes/c): Add part of the c code in the backtracking chapter * feat(codes/c): Add preorder_traversal_iii_compact.c * feat(codes/c): Add preorder_traversal_iii_template.c * feat(codes/c): Add permutations_i.c * style(codes/c): Adjust the format * feat(codes/c): Add memory release in chapter_backtracking * fix(codes/c): Fix memory release issue. * style(codes/c): Update format and Merge duplicate code * style(code/c): Change print format in preorder_traversal_iii_template.c * Update preorder_traversal_iii_template.c * Update permutations_i.c * feat(codes/c): Remove myArray, use public vector. * feat(codes/c): Add subset_sum_i_naive.c in C codes. * feat(codes/c): Add permutations_i in CMakeLists.txt * feat(codes/c): Update printf function in vector.h. * feat(codes/c): Add subset_sum_i.c and subset_sum_ii.c --------- Co-authored-by: Yudong Jin --- codes/c/CMakeLists.txt | 3 +- codes/c/chapter_backtracking/CMakeLists.txt | 8 + codes/c/chapter_backtracking/permutations_i.c | 81 ++++++++++ .../preorder_traversal_i_compact.c | 44 ++++++ .../preorder_traversal_ii_compact.c | 67 +++++++++ .../preorder_traversal_iii_compact.c | 69 +++++++++ .../preorder_traversal_iii_template.c | 101 +++++++++++++ codes/c/chapter_backtracking/subset_sum_i.c | 76 ++++++++++ .../chapter_backtracking/subset_sum_i_naive.c | 69 +++++++++ codes/c/chapter_backtracking/subset_sum_ii.c | 83 +++++++++++ codes/c/utils/common.h | 2 + codes/c/utils/vector.h | 139 ++++++++++++++++++ 12 files changed, 741 insertions(+), 1 deletion(-) create mode 100644 codes/c/chapter_backtracking/CMakeLists.txt create mode 100644 codes/c/chapter_backtracking/permutations_i.c create mode 100644 codes/c/chapter_backtracking/preorder_traversal_i_compact.c create mode 100644 codes/c/chapter_backtracking/preorder_traversal_ii_compact.c create mode 100644 codes/c/chapter_backtracking/preorder_traversal_iii_compact.c create mode 100644 codes/c/chapter_backtracking/preorder_traversal_iii_template.c create mode 100644 codes/c/chapter_backtracking/subset_sum_i.c create mode 100644 codes/c/chapter_backtracking/subset_sum_i_naive.c create mode 100644 codes/c/chapter_backtracking/subset_sum_ii.c create mode 100644 codes/c/utils/vector.h diff --git a/codes/c/CMakeLists.txt b/codes/c/CMakeLists.txt index 8b74fec3..5e583b65 100644 --- a/codes/c/CMakeLists.txt +++ b/codes/c/CMakeLists.txt @@ -11,6 +11,7 @@ add_subdirectory(chapter_stack_and_queue) add_subdirectory(chapter_heap) add_subdirectory(chapter_hashing) add_subdirectory(chapter_tree) +add_subdirectory(chapter_graph) add_subdirectory(chapter_searching) add_subdirectory(chapter_sorting) -add_subdirectory(chapter_graph) +add_subdirectory(chapter_backtracking) diff --git a/codes/c/chapter_backtracking/CMakeLists.txt b/codes/c/chapter_backtracking/CMakeLists.txt new file mode 100644 index 00000000..87538d37 --- /dev/null +++ b/codes/c/chapter_backtracking/CMakeLists.txt @@ -0,0 +1,8 @@ +add_executable(permutations_i permutations_i.c) +add_executable(preorder_traversal_i_compact preorder_traversal_i_compact.c) +add_executable(preorder_traversal_ii_compact preorder_traversal_ii_compact.c) +add_executable(preorder_traversal_iii_compact preorder_traversal_iii_compact.c) +add_executable(preorder_traversal_iii_template preorder_traversal_iii_template.c) +add_executable(subset_sum_i_naive subset_sum_i_naive.c) +add_executable(subset_sum_i subset_sum_i.c) +add_executable(subset_sum_ii subset_sum_ii.c) \ No newline at end of file diff --git a/codes/c/chapter_backtracking/permutations_i.c b/codes/c/chapter_backtracking/permutations_i.c new file mode 100644 index 00000000..fcf78dd5 --- /dev/null +++ b/codes/c/chapter_backtracking/permutations_i.c @@ -0,0 +1,81 @@ +/** + * File: permutations_i.c + * Created Time: 2023-06-04 + * Author: Gonglja (glj0@outlook.com) + */ + +#include "../utils/common.h" + +/* 回溯算法:全排列 I */ +void backtrack(vector *state, vector *choices, vector *selected, vector *res) { + // 当状态长度等于元素数量时,记录解 + if (state->size == choices->size) { + vector *newState = newVector(); + for (int i = 0; i < state->size; i++) { + vectorPushback(newState, state->data[i]); + } + vectorPushback(res, newState); + return; + } + // 遍历所有选择 + for (int i = 0; i < choices->size; i++) { + int *choice = malloc(sizeof(int)); + *choice = *((int *)(choices->data[i])); + // 剪枝:不允许重复选择元素 且 不允许重复选择相等元素 + bool select = *((bool *)(selected->data[i])); + if (!select) { + // 尝试:做出选择,更新状态 + *((bool *)selected->data[i]) = true; + vectorPushback(state, choice); + // 进行下一轮选择 + backtrack(state, choices, selected, res); + // 回退:撤销选择,恢复到之前的状态 + *((bool *)selected->data[i]) = false; + vectorPopback(state); + } + } +} + +/* 全排列 I */ +vector *permutationsI(vector *nums) { + vector *iState = newVector(); + + int select[3] = {false, false, false}; + vector *bSelected = newVector(); + for (int i = 0; i < nums->size; i++) { + vectorPushback(bSelected, &select[i]); + } + + vector *res = newVector(); + + // 前序遍历 + backtrack(iState, nums, bSelected, res); + return res; +} + +/* 打印向量中的元素 */ +void printFunc(vector *v, void *p) { + TreeNode *node = p; + printf("%d", node->val); +} + +/* Driver Code */ +int main() { + int nums[] = {1, 2, 3}; + vector *iNums = newVector(); // int + for (int i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) { + vectorPushback(iNums, &nums[i]); + } + + vector *res = permutationsI(iNums); + + // 输出结果 + printf("输入数组 nums = "); + printArray(nums, sizeof(nums) / sizeof(nums[0])); + printf("所有排列 res = "); + printVectorMatrix(res, printFunc); + + // 释放内存 + delVector(res); + return 0; +} diff --git a/codes/c/chapter_backtracking/preorder_traversal_i_compact.c b/codes/c/chapter_backtracking/preorder_traversal_i_compact.c new file mode 100644 index 00000000..dd5b0181 --- /dev/null +++ b/codes/c/chapter_backtracking/preorder_traversal_i_compact.c @@ -0,0 +1,44 @@ +/** + * File: preorder_traversal_i_compact.c + * Created Time: 2023-05-10 + * Author: Gonglja (glj0@outlook.com) + */ + +#include "../utils/common.h" + +vector *res; + +// 打印向量中的元素 +void printFunc(vector *v, void *p) { + TreeNode *node = p; + printf("%d ", node->val); +} + +/* 前序遍历:例题一 */ +static void preOrder(TreeNode *root) { + if (root == NULL) { + return; + } + if (root->val == 7) { + // 记录解 + vectorPushback(res, root); + } + preOrder(root->left); + preOrder(root->right); +} + +/* Driver Code */ +int main() { + int arr[] = {1, 7, 3, 4, 5, 6, 7}; + res = newVector(); + TreeNode *root = arrToTree(arr, sizeof(arr) / sizeof(arr[0])); + printf("\n初始化二叉树\r\n"); + printTree(root); + + // 前序遍历 + preOrder(root); + + printf("\n输出所有值为 7 的节点\r\n"); + printVector(res, printFunc); + delVector(res); +} \ No newline at end of file diff --git a/codes/c/chapter_backtracking/preorder_traversal_ii_compact.c b/codes/c/chapter_backtracking/preorder_traversal_ii_compact.c new file mode 100644 index 00000000..2152ecd9 --- /dev/null +++ b/codes/c/chapter_backtracking/preorder_traversal_ii_compact.c @@ -0,0 +1,67 @@ +/** + * File: preorder_traversal_ii_compact.c + * Created Time: 2023-05-28 + * Author: Gonglja (glj0@outlook.com) + */ + +#include "../utils/common.h" + +/* 前序遍历:例题二 */ +void preOrder(TreeNode *root, vector *path, vector *res) { + if (root == NULL) { + return; + } + // 尝试 + vectorPushback(path, root); + if (root->val == 7) { + // 记录解 + vector *newPath = newVector(); + for (int i = 0; i < path->size; i++) { + vectorPushback(newPath, path->data[i]); + } + vectorPushback(res, newPath); + } + + preOrder(root->left, path, res); + preOrder(root->right, path, res); + + // 回退 + vectorPopback(path); +} + +// 打印向量中的元素 +void printResult(vector *vv) { + for (int i = 0; i < vv->size; i++) { + vector *v = (vector *)vv->data[i]; + for (int j = 0; j < v->size; j++) { + TreeNode *node = (TreeNode *)v->data[j]; + printf("%d ", node->val); + } + printf("\n"); + } +} + +/* Driver Code */ +int main() { + int arr[] = {1, 7, 3, 4, 5, 6, 7}; + int n = sizeof(arr) / sizeof(arr[0]); + TreeNode *root = arrToTree(arr, n); + printf("\r\n初始化二叉树\r\n"); + printTree(root); + + // 创建存储路径和结果的向量 + vector *path = newVector(); + vector *res = newVector(); + + // 前序遍历 + preOrder(root, path, res); + + // 输出结果 + printf("输出所有根节点到节点 7 的路径:\n"); + printResult(res); + + // 释放内存 + delVector(path); + delVector(res); + return 0; +} diff --git a/codes/c/chapter_backtracking/preorder_traversal_iii_compact.c b/codes/c/chapter_backtracking/preorder_traversal_iii_compact.c new file mode 100644 index 00000000..f0d5aea2 --- /dev/null +++ b/codes/c/chapter_backtracking/preorder_traversal_iii_compact.c @@ -0,0 +1,69 @@ +/** + * File: preorder_traversal_iii_compact.c + * Created Time: 2023-06-04 + * Author: Gonglja (glj0@outlook.com) + */ + +#include "../utils/common.h" + +/* 前序遍历:例题三 */ +void preOrder(TreeNode *root, vector *path, vector *res) { + // 剪枝 + if (root == NULL || root->val == 3) { + return; + } + // 尝试 + vectorPushback(path, root); + if (root->val == 7) { + // 记录解 + vector *newPath = newVector(); + for (int i = 0; i < path->size; i++) { + vectorPushback(newPath, path->data[i]); + } + vectorPushback(res, newPath); + res->depth++; + } + + preOrder(root->left, path, res); + preOrder(root->right, path, res); + + // 回退 + vectorPopback(path); +} + +// 打印向量中的元素 +void printResult(vector *vv) { + for (int i = 0; i < vv->size; i++) { + vector *v = (vector *)vv->data[i]; + for (int j = 0; j < v->size; j++) { + TreeNode *node = (TreeNode *)v->data[j]; + printf("%d ", node->val); + } + printf("\n"); + } +} + +/* Driver Code */ +int main() { + int arr[] = {1, 7, 3, 4, 5, 6, 7}; + int n = sizeof(arr) / sizeof(arr[0]); + TreeNode *root = arrToTree(arr, n); + printf("\r\n初始化二叉树\r\n"); + printTree(root); + + // 创建存储路径和结果的向量 + vector *path = newVector(); + vector *res = newVector(); + + // 前序遍历 + preOrder(root, path, res); + + // 输出结果 + printf("输出所有根节点到节点 7 的路径,要求路径中不包含值为 3 的节点:\n"); + printResult(res); + + // 释放内存 + delVector(path); + delVector(res); + return 0; +} diff --git a/codes/c/chapter_backtracking/preorder_traversal_iii_template.c b/codes/c/chapter_backtracking/preorder_traversal_iii_template.c new file mode 100644 index 00000000..d1216d3a --- /dev/null +++ b/codes/c/chapter_backtracking/preorder_traversal_iii_template.c @@ -0,0 +1,101 @@ +/** + * File: preorder_traversal_iii_template.c + * Created Time: 2023-06-04 + * Author: Gonglja (glj0@outlook.com) + */ + +#include "../utils/common.h" + +/* 判断当前状态是否为解 */ +bool isSolution(vector *state) { + return state->size != 0 && ((TreeNode *)(state->data[state->size - 1]))->val == 7; +} + +/* 记录解 */ +void recordSolution(vector *state, vector *res) { + vector *newPath = newVector(); + for (int i = 0; i < state->size; i++) { + vectorPushback(newPath, state->data[i]); + } + vectorPushback(res, newPath); +} + +/* 判断在当前状态下,该选择是否合法 */ +bool isValid(vector *state, TreeNode *choice) { + return choice != NULL && choice->val != 3; +} + +/* 更新状态 */ +void makeChoice(vector *state, TreeNode *choice) { + vectorPushback(state, choice); +} + +/* 恢复状态 */ +void undoChoice(vector *state, TreeNode *choice) { + vectorPopback(state); +} + +/* 前序遍历:例题三 */ +void backtrack(vector *state, vector *choices, vector *res) { + // 检查是否为解 + if (isSolution(state)) { + // 记录解 + recordSolution(state, res); + return; + } + // 遍历所有选择 + for (int i = 0; i < choices->size; i++) { + TreeNode *choice = choices->data[i]; + // 剪枝:检查选择是否合法 + if (isValid(state, choice)) { + // 尝试:做出选择,更新状态 + makeChoice(state, choice); + // 进行下一轮选择 + vector *nextChoices = newVector(); + vectorPushback(nextChoices, choice->left); + vectorPushback(nextChoices, choice->right); + backtrack(state, nextChoices, res); + // 回退:撤销选择,恢复到之前的状态 + undoChoice(state, choice); + } + } +} + +// 打印向量中的元素 +void printFunc(vector *v, void *p) { + TreeNode *node = p; + printf("%d ", node->val); +} + +/* Driver Code */ +int main() { + int arr[] = {1, 7, 3, 4, 5, 6, 7}; + int n = sizeof(arr) / sizeof(arr[0]); + TreeNode *root = arrToTree(arr, n); + printf("\r\n初始化二叉树\r\n"); + printTree(root); + + // 回溯算法 + vector *state = newVector(); + vector *choices = newVector(); + vector *res = newVector(); + vectorPushback(choices, root); + backtrack(state, choices, res); + + printf("输出所有根节点到节点 7 的路径,要求路径中不包含值为 3 的节点:\n"); + for (int i = 0; i < res->size; i++) { + vector *path = res->data[i]; + vector *vals = newVector(); + for (int j = 0; j < path->size; j++) { + TreeNode *node = path->data[j]; + vectorPushback(vals, &node->val); + } + printVector(vals, printFunc); + } + + // 释放内存 + delVector(state); + delVector(choices); + delVector(res); + return 0; +} diff --git a/codes/c/chapter_backtracking/subset_sum_i.c b/codes/c/chapter_backtracking/subset_sum_i.c new file mode 100644 index 00000000..cfe34157 --- /dev/null +++ b/codes/c/chapter_backtracking/subset_sum_i.c @@ -0,0 +1,76 @@ +/** + * File: subset_sum_i.c + * Created Time: 2023-07-29 + * Author: Gonglja (glj0@outlook.com) + */ + +#include "../utils/common.h" + +/* 回溯算法:子集和 I */ +void backtrack(vector *state, int target, vector *choices, int start, vector *res) { + // 子集和等于 target 时,记录解 + if (target == 0) { + vector *tmpVector = newVector(); + for (int i = 0; i < state->size; i++) { + vectorPushback(tmpVector, state->data[i]); + } + vectorPushback(res, tmpVector); + return; + } + // 遍历所有选择 + // 剪枝二:从 start 开始遍历,避免生成重复子集 + for (int i = start; i < choices->size; i++) { + // 剪枝:若子集和超过 target ,则跳过该选择 + if (target - *(int *)(choices->data[i]) < 0) { + continue; + } + // 尝试:做出选择,更新 target, start + vectorPushback(state, choices->data[i]); + // 进行下一轮选择 + backtrack(state, target - *(int *)(choices->data[i]), choices, i, res); + // 回退:撤销选择,恢复到之前的状态 + vectorPopback(state); + } +} + +/* 用来做比较的函数 */ +int comp(const void *a, const void *b) { + return *(int *)a - *(int *)b; +} + +/* 求解子集和 I */ +vector *subsetSumINaive(vector *nums, int target) { + vector *state = newVector(); // 状态(子集) + qsort(nums->data[0], nums->size, sizeof(int), comp); // 对 nums 进行排序 + int start = 0; // 子集和 + vector *res = newVector(); // 结果列表(子集列表) + backtrack(state, target, nums, start, res); + return res; +} + +/* 打印向量中的元素 */ +void printFunc(vector *v, void *p) { + TreeNode *node = p; + printf("%d", node->val); +} + +/* Driver Code */ +int main() { + int nums[] = {3, 4, 5}; + vector *vNums = newVector(); + for (int i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) { + vectorPushback(vNums, &nums[i]); + } + int target = 9; + + vector *res = subsetSumINaive(vNums, target); + + printf("输入数组 nums = "); + printVector(vNums, printFunc); + printf("target = %d\n", target); + printf("所有和等于 %d 的子集 res = \r\n", target); + printVectorMatrix(res, printFunc); + + delVector(res); + return 0; +} diff --git a/codes/c/chapter_backtracking/subset_sum_i_naive.c b/codes/c/chapter_backtracking/subset_sum_i_naive.c new file mode 100644 index 00000000..b4587256 --- /dev/null +++ b/codes/c/chapter_backtracking/subset_sum_i_naive.c @@ -0,0 +1,69 @@ +/** + * File: subset_sum_i_naive.c + * Created Time: 2023-07-28 + * Author: Gonglja (glj0@outlook.com) + */ + +#include "../utils/common.h" + +/* 回溯算法:子集和 I */ +void backtrack(vector *state, int target, int total, vector *choices, vector *res) { + // 子集和等于 target 时,记录解 + if (total == target) { + vector *tmpVector = newVector(); + for (int i = 0; i < state->size; i++) { + vectorPushback(tmpVector, state->data[i]); + } + vectorPushback(res, tmpVector); + return; + } + // 遍历所有选择 + for (size_t i = 0; i < choices->size; i++) { + // 剪枝:若子集和超过 target ,则跳过该选择 + if (total + *(int *)(choices->data[i]) > target) { + continue; + } + // 尝试:做出选择,更新元素和 total + vectorPushback(state, choices->data[i]); + // 进行下一轮选择 + backtrack(state, target, total + *(int *)(choices->data[i]), choices, res); + // 回退:撤销选择,恢复到之前的状态 + vectorPopback(state); + } +} + +/* 求解子集和 I(包含重复子集) */ +vector *subsetSumINaive(vector *nums, int target) { + vector *state = newVector(); // 状态(子集) + int total = 0; // 子集和 + vector *res = newVector(); // 结果列表(子集列表) + backtrack(state, target, total, nums, res); + return res; +} + +/* 打印向量中的元素 */ +void printFunc(vector *v, void *p) { + TreeNode *node = p; + printf("%d", node->val); +} + +/* Driver Code */ +int main() { + int nums[] = {3, 4, 5}; + vector *vNums = newVector(); + for (int i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) { + vectorPushback(vNums, &nums[i]); + } + int target = 9; + + vector *res = subsetSumINaive(vNums, target); + + printf("输入数组 nums = "); + printVector(vNums, printFunc); + printf("target = %d\n", target); + printf("所有和等于 %d 的子集 res = \r\n", target); + printVectorMatrix(res, printFunc); + + delVector(res); + return 0; +} diff --git a/codes/c/chapter_backtracking/subset_sum_ii.c b/codes/c/chapter_backtracking/subset_sum_ii.c new file mode 100644 index 00000000..e7184326 --- /dev/null +++ b/codes/c/chapter_backtracking/subset_sum_ii.c @@ -0,0 +1,83 @@ +/** + * File: subset_sum_ii.c + * Created Time: 2023-07-29 + * Author: Gonglja (glj0@outlook.com) + */ + +#include "../utils/common.h" + +/* 回溯算法:子集和 I */ +void backtrack(vector *state, int target, vector *choices, int start, vector *res) { + // 子集和等于 target 时,记录解 + if (target == 0) { + vector *tmpVector = newVector(); + for (int i = 0; i < state->size; i++) { + vectorPushback(tmpVector, state->data[i]); + } + vectorPushback(res, tmpVector); + return; + } + // 遍历所有选择 + // 剪枝二:从 start 开始遍历,避免生成重复子集 + // 剪枝三:从 start 开始遍历,避免重复选择同一元素 + for (int i = start; i < choices->size; i++) { + // 剪枝一:若子集和超过 target ,则直接结束循环 + // 这是因为数组已排序,后边元素更大,子集和一定超过 target + if (target - *(int *)(choices->data[i]) < 0) { + continue; + } + + // 剪枝四:如果该元素与左边元素相等,说明该搜索分支重复,直接跳过 + if (i > start && *(int *)(choices->data[i]) == *(int *)(choices->data[i - 1])) { + continue; + } + // 尝试:做出选择,更新 target, start + vectorPushback(state, choices->data[i]); + // 进行下一轮选择 + backtrack(state, target - *(int *)(choices->data[i]), choices, i + 1, res); + // 回退:撤销选择,恢复到之前的状态 + vectorPopback(state); + } +} + +/* 用来做比较的函数 */ +int comp(const void *a, const void *b) { + return *(int *)a - *(int *)b; +} + +/* 求解子集和 I */ +vector *subsetSumINaive(vector *nums, int target) { + vector *state = newVector(); // 状态(子集) + qsort(nums->data[0], nums->size, sizeof(int), comp); // 对 nums 进行排序 + int start = 0; // 子集和 + vector *res = newVector(); // 结果列表(子集列表) + backtrack(state, target, nums, start, res); + return res; +} + +/* 打印向量中的元素 */ +void printFunc(vector *v, void *p) { + TreeNode *node = p; + printf("%d", node->val); +} + +/* Driver Code */ +int main() { + int nums[] = {4, 4, 5}; + vector *vNums = newVector(); + for (int i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) { + vectorPushback(vNums, &nums[i]); + } + int target = 9; + + vector *res = subsetSumINaive(vNums, target); + + printf("输入数组 nums = "); + printVector(vNums, printFunc); + printf("target = %d\n", target); + printf("所有和等于 %d 的子集 res = \r\n", target); + printVectorMatrix(res, printFunc); + + delVector(res); + return 0; +} diff --git a/codes/c/utils/common.h b/codes/c/utils/common.h index e5565f8e..91843b9d 100644 --- a/codes/c/utils/common.h +++ b/codes/c/utils/common.h @@ -21,6 +21,8 @@ // hash table lib #include "uthash.h" +#include "vector.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/codes/c/utils/vector.h b/codes/c/utils/vector.h new file mode 100644 index 00000000..74d5c4dc --- /dev/null +++ b/codes/c/utils/vector.h @@ -0,0 +1,139 @@ +/** + * File: vector.h + * Created Time: 2023-07-13 + * Author: Gonglja (glj0@outlook.com) + */ + +#ifndef VECTOR_H +#define VECTOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* 定义向量类型 */ +typedef struct vector { + int size; // 当前向量的大小 + int capacity; // 当前向量的容量 + int depth; // 当前向量的深度 + void **data; // 指向数据的指针数组 +} vector; + +/* 构造向量 */ +vector *newVector() { + vector *v = malloc(sizeof(vector)); + v->size = 0; + v->capacity = 4; + v->depth = 1; + v->data = malloc(v->capacity * sizeof(void *)); + return v; +} + +/* 析构向量 */ +void delVector(vector *v) { + if (v) { + if (v->depth == 0) { + return; + } else if (v->depth == 1) { + for (int i = 0; i < v->size; i++) { + free(v->data[i]); + } + free(v); + } else { + for (int i = 0; i < v->size; i++) { + delVector(v->data[i]); + } + v->depth--; + } + } +} + +/* 添加元素到向量尾部 */ +void vectorPushback(vector *v, void *elem) { + if (v->size == v->capacity) { + v->capacity *= 2; + v->data = realloc(v->data, v->capacity * sizeof(void *)); + } + v->data[v->size++] = elem; +} + +/* 从向量尾部弹出元素 */ +void vectorPopback(vector *v) { + if (v->size != 0) { + v->size--; + } +} + +/* 清空向量 */ +void vectorClear(vector *v) { + delVector(v); + v->size = 0; + v->capacity = 4; + v->depth = 1; + v->data = malloc(v->capacity * sizeof(void *)); +} + +/* 获取向量的大小 */ +int vectorSize(vector *v) { + return v->size; +} + +/* 获取向量的尾元素 */ +void *vectorBack(vector *v) { + return v->data[v->size]; +} + +/* 获取向量的头元素 */ +void *vectorFront(vector *v) { + return v->data[0]; +} + +/* 打印函数, 需传递一个打印变量的函数进来 */ +/* 当前仅支持打印深度为 1 的 vector*/ +void printVector(vector *v, void (*printFunc)(vector *v, void *p)) { + if (v) { + if (v->depth == 0) { + return; + } else if (v->depth == 1) { + for (int i = 0; i < v->size; i++) { + if (i == 0) { + printf("["); + } else if (i == v->size-1) { + printFunc(v, v->data[i]); + printf("]\r\n"); + break; + } + printFunc(v, v->data[i]); + printf(","); + } + } else { + for (int i = 0; i < v->size; i++) { + printVector(v->data[i], printFunc); + } + v->depth--; + } + } +} + +/* 当前仅支持打印深度为 2 的 vector */ +void printVectorMatrix(vector *vv, void (*printFunc)(vector *v, void *p)) { + printf("[\n"); + for (int i = 0; i < vv->size; i++) { + vector *v = (vector *)vv->data[i]; + printf(" ["); + for (int j = 0; j < v->size; j++) { + printFunc(v, v->data[j]); + if (j != v->size -1) + printf(","); + } + printf("],"); + printf("\n"); + } + printf("]\n"); +} + +#ifdef __cplusplus +} +#endif + +#endif // VECTOR_H \ No newline at end of file