Skip to content

Commit

Permalink
feat: Add C codes for the chapter backtracking (krahets#593)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
Gonglja and krahets authored Jul 29, 2023
1 parent 9e8aee0 commit 8f5ef68
Show file tree
Hide file tree
Showing 12 changed files with 741 additions and 1 deletion.
3 changes: 2 additions & 1 deletion codes/c/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 8 additions & 0 deletions codes/c/chapter_backtracking/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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 changes: 81 additions & 0 deletions codes/c/chapter_backtracking/permutations_i.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**
* File: permutations_i.c
* Created Time: 2023-06-04
* Author: Gonglja ([email protected])
*/

#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 changes: 44 additions & 0 deletions codes/c/chapter_backtracking/preorder_traversal_i_compact.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* File: preorder_traversal_i_compact.c
* Created Time: 2023-05-10
* Author: Gonglja ([email protected])
*/

#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 changes: 67 additions & 0 deletions codes/c/chapter_backtracking/preorder_traversal_ii_compact.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* File: preorder_traversal_ii_compact.c
* Created Time: 2023-05-28
* Author: Gonglja ([email protected])
*/

#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;
}
69 changes: 69 additions & 0 deletions codes/c/chapter_backtracking/preorder_traversal_iii_compact.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* File: preorder_traversal_iii_compact.c
* Created Time: 2023-06-04
* Author: Gonglja ([email protected])
*/

#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 changes: 101 additions & 0 deletions codes/c/chapter_backtracking/preorder_traversal_iii_template.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/**
* File: preorder_traversal_iii_template.c
* Created Time: 2023-06-04
* Author: Gonglja ([email protected])
*/

#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;
}
Loading

0 comments on commit 8f5ef68

Please sign in to comment.