From 00009c8e490c3d5ebbe625d41e686bebf0c5052c Mon Sep 17 00:00:00 2001 From: reanon <793584285@qq.com> Date: Sun, 15 Jan 2023 21:49:22 +0800 Subject: [PATCH] feat(tree): add go codes --- codes/c/chapter_tree/CMakeLists.txt | 1 + codes/c/chapter_tree/avl_tree.c | 260 ++++++++++++++++++++++ codes/c/chapter_tree/binary_search_tree.c | 163 ++++++++++++++ codes/go/chapter_tree/avl_tree_test.go | 2 +- 4 files changed, 425 insertions(+), 1 deletion(-) create mode 100644 codes/c/chapter_tree/avl_tree.c diff --git a/codes/c/chapter_tree/CMakeLists.txt b/codes/c/chapter_tree/CMakeLists.txt index 779315b7b..1ff3b27b7 100644 --- a/codes/c/chapter_tree/CMakeLists.txt +++ b/codes/c/chapter_tree/CMakeLists.txt @@ -1,3 +1,4 @@ +add_executable(avl_tree avl_tree.c) add_executable(binary_search binary_tree.c) add_executable(binary_tree_bfs binary_tree_bfs.c) add_executable(binary_tree_dfs binary_tree_dfs.c) diff --git a/codes/c/chapter_tree/avl_tree.c b/codes/c/chapter_tree/avl_tree.c new file mode 100644 index 000000000..f3f84a1e3 --- /dev/null +++ b/codes/c/chapter_tree/avl_tree.c @@ -0,0 +1,260 @@ +/** + * File: avl_tree.c + * Created Time: 2023-01-15 + * Author: Reanon (793584285@qq.com) + */ + +#include "../include/include.h" + +/* AVL Tree */ +struct avlTree { + TreeNode *root; +}; + +typedef struct avlTree avlTree; + +/* 构建 AVL 树 */ +avlTree *newAVLTree() { + avlTree *tree = (avlTree *) malloc(sizeof(avlTree)); + tree->root = NULL; + return tree; +} + +int height(TreeNode *node) { + // 空结点高度为 -1 ,叶结点高度为 0 + if (node != NULL) { + return node->height; + } + return -1; +} + +/* 更新结点高度 */ +int updateHeight(TreeNode *node) { + int lh = height(node->left); + int rh = height(node->right); + // 结点高度等于最高子树高度 + 1 + if (lh > rh) { + node->height = lh + 1; + } else { + node->height = rh + 1; + } +} + +/* 获取平衡因子 */ +int balanceFactor(TreeNode *node) { + // 空结点平衡因子为 0 + if (node == NULL) { + return 0; + } + // 结点平衡因子 = 左子树高度 - 右子树高度 + return height(node->left) - height(node->right); +} + +/* 右旋操作 */ +TreeNode *rightRotate(TreeNode *node) { + TreeNode *child, *grandChild; + child = node->left; + grandChild = child->right; + // 以 child 为原点,将 node 向右旋转 + child->right = node; + node->left = grandChild; + // 更新结点高度 + updateHeight(node); + updateHeight(child); + // 返回旋转后子树的根节点 + return child; +} + +/* 左旋操作 */ +TreeNode *leftRotate(TreeNode *node) { + TreeNode *child, *grandChild; + child = node->right; + grandChild = child->left; + // 以 child 为原点,将 node 向左旋转 + child->left = node; + node->right = grandChild; + // 更新结点高度 + updateHeight(node); + updateHeight(child); + // 返回旋转后子树的根节点 + return child; +} + +/* 执行旋转操作,使该子树重新恢复平衡 */ +TreeNode *rotate(TreeNode *node) { + // 获取结点 node 的平衡因子 + int bf = balanceFactor(node); + // 左偏树 + if (bf > 1) { + if (balanceFactor(node->left) >= 0) { + // 右旋 + return rightRotate(node); + } else { + // 先左旋后右旋 + node->left = leftRotate(node->left); + return rightRotate(node); + } + } + // 右偏树 + if (bf < -1) { + if (balanceFactor(node->right) <= 0) { + // 左旋 + return leftRotate(node); + } else { + // 先右旋后左旋 + node->right = rightRotate(node->right); + return leftRotate(node); + } + } + // 平衡树,无需旋转,直接返回 + return node; +} + +/* 递归插入结点(辅助函数) */ +TreeNode *insertHelper(TreeNode *node, int val) { + if (node == NULL) { + return newTreeNode(val); + } + /* 1. 查找插入位置,并插入结点 */ + if (val < node->val) { + node->left = insertHelper(node->left, val); + } else if (val > node->val) { + node->right = insertHelper(node->right, val); + } else { + // 重复结点不插入,直接返回 + return node; + } + // 更新结点高度 + updateHeight(node); + /* 2. 执行旋转操作,使该子树重新恢复平衡 */ + node = rotate(node); + // 返回子树的根节点 + return node; +} + + +/* 插入结点 */ +TreeNode *insert(avlTree *tree, int val) { + tree->root = insertHelper(tree->root, val); + return tree->root; +} + +/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */ +TreeNode *getInOrderNext(TreeNode *node) { + if (node == NULL) { + return node; + } + // 循环访问左子结点,直到叶结点时为最小结点,跳出 + while (node->left != NULL) { + node = node->left; + } + return node; +} + +/* 递归删除结点(辅助函数) */ +TreeNode *removeHelper(TreeNode *node, int val) { + TreeNode *child, *grandChild, *temp; + if (node == NULL) { + return NULL; + } + /* 1. 查找结点,并删除之 */ + if (val < node->val) { + node->left = removeHelper(node->left, val); + } else if (val > node->val) { + node->right = removeHelper(node->right, val); + } else { + if (node->left == NULL || node->right == NULL) { + child = node->left; + if (node->right != NULL) { + child = node->right; + } + // 子结点数量 = 0 ,直接删除 node 并返回 + if (child == NULL) { + return NULL; + } else { + // 子结点数量 = 1 ,直接删除 node + node = child; + } + } else { + // 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 + temp = getInOrderNext(node->right); + node->right = removeHelper(node->right, temp->val); + node->val = temp->val; + } + } + // 更新结点高度 + updateHeight(node); + /* 2. 执行旋转操作,使该子树重新恢复平衡 */ + node = rotate(node); + // 返回子树的根节点 + return node; +} + +/* 删除结点 */ +TreeNode *removeNode(avlTree *tree, int val) { + TreeNode *root = removeHelper(tree->root, val); + return root; +} + +/* 查找结点 */ +TreeNode *search(avlTree *tree, int val) { + TreeNode *cur = tree->root; + // 循环查找,越过叶结点后跳出 + while (cur != NULL) { + // 目标结点在 root 的右子树中 + if (cur->val < val) { + cur = cur->right; + } else if (cur->val > val) { + // 目标结点在 root 的左子树中 + cur = cur->left; + } else { + // 找到目标结点,跳出循环 + break; + } + } + // 找到目标结点,跳出循环 + return cur; +} + +void testInsert(avlTree *tree, int val) { + insert(tree, val); + printf("\n插入结点 %d 后,AVL 树为 \n", val); + printTree(tree->root); +} + +void testRemove(avlTree *tree, int val) { + removeNode(tree, val); + printf("\n删除结点 %d 后,AVL 树为 \n", val); + printTree(tree->root); +} + +/* Driver Code */ +int main() { + /* 初始化空 AVL 树 */ + avlTree *tree = (avlTree *) newAVLTree(); + /* 插入结点 */ + // 请关注插入结点后,AVL 树是如何保持平衡的 + testInsert(tree, 1); + testInsert(tree, 2); + testInsert(tree, 3); + testInsert(tree, 4); + testInsert(tree, 5); + testInsert(tree, 8); + testInsert(tree, 7); + testInsert(tree, 9); + testInsert(tree, 10); + testInsert(tree, 6); + + /* 插入重复结点 */ + testInsert(tree, 7); + + /* 删除结点 */ + // 请关注删除结点后,AVL 树是如何保持平衡的 + testRemove(tree, 8); // 删除度为 0 的结点 + testRemove(tree, 5); // 删除度为 1 的结点 + testRemove(tree, 4); // 删除度为 2 的结点 + + /* 查询结点 */ + TreeNode *node = search(tree, 7); + printf("\n查找到的结点对象结点值 = %d \n", node->val); +} \ No newline at end of file diff --git a/codes/c/chapter_tree/binary_search_tree.c b/codes/c/chapter_tree/binary_search_tree.c index f993faec3..dcf1736a7 100644 --- a/codes/c/chapter_tree/binary_search_tree.c +++ b/codes/c/chapter_tree/binary_search_tree.c @@ -6,3 +6,166 @@ #include "../include/include.h" +/* 二叉搜索树 */ +struct binarySearchTree { + TreeNode *root; +}; + +typedef struct binarySearchTree binarySearchTree; + +int sortIntHelper(const void *a, const void *b) { + // 从小到大排序 + return (*(int *) a - *(int *) b); +} + +/* 构建二叉搜索树 */ +TreeNode *buildTree(int nums[], int i, int j) { + if (i > j) { + return NULL; + } + // 将数组中间结点作为根结点 + int mid = (i + j) / 2; + TreeNode *root = newTreeNode(nums[mid]); + // 递归建立左子树和右子树 + root->left = buildTree(nums, i, mid - 1); + root->right = buildTree(nums, mid + 1, j); + return root; +} + +binarySearchTree *newBinarySearchTree(int nums[], int size) { + binarySearchTree *bst = (binarySearchTree *) malloc(sizeof(binarySearchTree)); + TreeNode *root; + // 从小到大排序数组 + qsort(nums, size, sizeof(int), sortIntHelper); + // 构建二叉搜索树 + root = buildTree(nums, 0, size - 1); + bst->root = root; + return bst; +} + +/* 获取二叉树根结点 */ +TreeNode *getRoot(binarySearchTree *bst) { + return bst->root; +} + +/* 查找结点 */ +TreeNode *search(binarySearchTree *bst, int num) { + TreeNode *cur = bst->root; + // 循环查找,越过叶结点后跳出 + while (cur != NULL) { + // 目标结点在 root 的右子树中 + if (cur->val < num) cur = cur->right; + // 目标结点在 root 的左子树中 + else if (cur->val > num) cur = cur->left; + // 找到目标结点,跳出循环 + else break; + } + // 返回目标结点 + return cur; +} + +/* 插入结点 */ +TreeNode *insert(binarySearchTree *bst, int num) { + // 若树为空,直接提前返回 + if (bst->root == NULL) return NULL; + TreeNode *cur = bst->root, *pre = NULL; + // 循环查找,越过叶结点后跳出 + while (cur != NULL) { + // 找到重复结点,直接返回 + if (cur->val == num) return NULL; + pre = cur; + // 插入位置在 root 的右子树中 + if (cur->val < num) cur = cur->right; + // 插入位置在 root 的左子树中 + else cur = cur->left; + } + // 插入结点 val + TreeNode *node = newTreeNode(num); + if (pre->val < num) pre->right = node; + else pre->left = node; + return node; +} + +/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */ +TreeNode *getInOrderNext(TreeNode *root) { + if (root == NULL) return root; + // 循环访问左子结点,直到叶结点时为最小结点,跳出 + while (root->left != NULL) { + root = root->left; + } + return root; +} + +/* 删除结点 */ +TreeNode *removeNode(binarySearchTree *bst, int num) { + // 若树为空,直接提前返回 + if (bst->root == NULL) return NULL; + TreeNode *cur = bst->root, *pre = NULL; + // 循环查找,越过叶结点后跳出 + while (cur != NULL) { + // 找到待删除结点,跳出循环 + if (cur->val == num) break; + pre = cur; + // 待删除结点在 root 的右子树中 + if (cur->val < num) cur = cur->right; + // 待删除结点在 root 的左子树中 + else cur = cur->left; + } + // 若无待删除结点,则直接返回 + if (cur == NULL) return NULL; + // 子结点数量 = 0 or 1 + if (cur->left == NULL || cur->right == NULL) { + // 当子结点数量 = 0 / 1 时, child = nullptr / 该子结点 + TreeNode *child = cur->left != NULL ? cur->left : cur->right; + // 删除结点 cur + if (pre->left == cur) pre->left = child; + else pre->right = child; + } + // 子结点数量 = 2 + else { + // 获取中序遍历中 cur 的下一个结点 + TreeNode *nex = getInOrderNext(cur->right); + int tmp = nex->val; + // 递归删除结点 nex + removeNode(bst, nex->val); + // 将 nex 的值复制给 cur + cur->val = tmp; + } + return cur; +} + +/* Driver Code */ +int main() { + /* 初始化二叉搜索树 */ + int nums[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + binarySearchTree *bst = newBinarySearchTree(nums, sizeof(nums) / sizeof(int)); + printf("初始化的二叉树为\n"); + printTree(getRoot(bst)); + + /* 查找结点 */ + TreeNode *node = search(bst, 7); + printf("查找到的结点对象的结点值 = %d\n", node->val); + + + /* 插入结点 */ + insert(bst, 16); + printf("插入结点 16 后,二叉树为\n"); + printTree(getRoot(bst)); + + + /* 删除结点 */ + removeNode(bst, 1); + printf("删除结点 1 后,二叉树为\n"); + printTree(getRoot(bst)); + removeNode(bst, 2); + printf("删除结点 2 后,二叉树为\n"); + printTree(getRoot(bst)); + removeNode(bst, 4); + printf("删除结点 4 后,二叉树为\n"); + printTree(getRoot(bst)); + + // 释放内存 + free(bst); + + return 0; +} diff --git a/codes/go/chapter_tree/avl_tree_test.go b/codes/go/chapter_tree/avl_tree_test.go index c4fc6b719..c02b8013a 100644 --- a/codes/go/chapter_tree/avl_tree_test.go +++ b/codes/go/chapter_tree/avl_tree_test.go @@ -49,6 +49,6 @@ func testInsert(tree *avlTree, val int) { func testRemove(tree *avlTree, val int) { tree.remove(val) - fmt.Printf("\n删除结点 %d 后,AVL 树为 \n", val) + fmt.Printf("\n删除结点 %d 后,AVL 树为 \n", val) PrintTree(tree.root) }