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 <krahets@163.com>
This commit is contained in:
parent
9e8aee04d5
commit
8f5ef68c65
@ -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)
|
||||
|
8
codes/c/chapter_backtracking/CMakeLists.txt
Normal file
8
codes/c/chapter_backtracking/CMakeLists.txt
Normal file
@ -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)
|
81
codes/c/chapter_backtracking/permutations_i.c
Normal file
81
codes/c/chapter_backtracking/permutations_i.c
Normal file
@ -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;
|
||||
}
|
44
codes/c/chapter_backtracking/preorder_traversal_i_compact.c
Normal file
44
codes/c/chapter_backtracking/preorder_traversal_i_compact.c
Normal file
@ -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);
|
||||
}
|
67
codes/c/chapter_backtracking/preorder_traversal_ii_compact.c
Normal file
67
codes/c/chapter_backtracking/preorder_traversal_ii_compact.c
Normal file
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
101
codes/c/chapter_backtracking/preorder_traversal_iii_template.c
Normal file
101
codes/c/chapter_backtracking/preorder_traversal_iii_template.c
Normal file
@ -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;
|
||||
}
|
76
codes/c/chapter_backtracking/subset_sum_i.c
Normal file
76
codes/c/chapter_backtracking/subset_sum_i.c
Normal file
@ -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;
|
||||
}
|
69
codes/c/chapter_backtracking/subset_sum_i_naive.c
Normal file
69
codes/c/chapter_backtracking/subset_sum_i_naive.c
Normal file
@ -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;
|
||||
}
|
83
codes/c/chapter_backtracking/subset_sum_ii.c
Normal file
83
codes/c/chapter_backtracking/subset_sum_ii.c
Normal file
@ -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;
|
||||
}
|
@ -21,6 +21,8 @@
|
||||
// hash table lib
|
||||
#include "uthash.h"
|
||||
|
||||
#include "vector.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
139
codes/c/utils/vector.h
Normal file
139
codes/c/utils/vector.h
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user