diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a9fc6d..ee0f79c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,6 +146,8 @@ set(SOURCE_FILE_HEADERS stack.h linked_stack.h circular_queue.h + binary_tree.h + binary_search_tree.h ) if (NOT HAVE_STRPTIME) @@ -195,7 +197,7 @@ if (ENABLE_UTILS_TESTING) set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) add_subdirectory(googletest) enable_testing() - add_executable(unittest test/stack_test.cpp test/queue_test.cpp) + add_executable(unittest test/stack_test.cpp test/queue_test.cpp test/binary_tree_test.cpp) target_link_libraries(unittest GTest::gtest_main utils) include(GoogleTest) gtest_discover_tests(unittest) diff --git a/binary_search_tree.h b/binary_search_tree.h new file mode 100644 index 0000000..2179f72 --- /dev/null +++ b/binary_search_tree.h @@ -0,0 +1,96 @@ +#ifndef _UTIL_BINARY_SEARCH_TREE_H +#define _UTIL_BINARY_SEARCH_TREE_H +#include "binary_tree.h" + +template +struct BinarySearchTreePair { + K key; + V value; +}; + +template +using BinarySearchTree = BinaryTree>; + +template +void binary_search_tree_clear(BinarySearchTree*& root, std::function free_key = std::function(), std::function free_value = std::function()) { + if (free_key || free_value) { + binary_tree_clear(root, [&free_key, &free_value](BinarySearchTreePair e) { + if (free_key) free_key(e.key); + if (free_value) free_value(e.value); + }); + } else { + binary_tree_clear(root); + } +} + +template +inline void binary_search_tree_clear(BinarySearchTree*& root, F free_key, G free_value = nullptr) { + binary_search_tree_clear(root, std::function(free_key), std::function(free_value)); +} + +template +void binary_search_tree_iter(BinarySearchTree* root, std::function callback, Args... args) { + binary_tree_lnr(root, [&callback](BinarySearchTree* e, Args... args) { + callback(e->data.key, e->data.value, args...); + }, args...); +} + +template +inline void binary_search_tree_iter(BinarySearchTree* root, F callback, Args... args) { + binary_search_tree_iter(root, std::function(callback), args...); +} + +template +bool binary_search_tree_insert(BinarySearchTree*& root, K key, V value, std::function comp, std::function free_key = std::function(), std::function free_value = std::function()) { + if (!root) { + root = binary_tree_new>({ key, value }); + if (!root) { + if (free_key) free_key(key); + if (free_value) free_value(value); + } + return root != nullptr; + } + BinarySearchTree* cur = root; + int re = comp(key, cur->data.key); + while (!binary_tree_is_leaf(cur)) { + if (re == 0) { + break; + } + if (re < 0 && !cur->left) break; + if (re > 0 && !cur->right) break; + cur = re < 0 ? cur->left : cur->right; + re = comp(key, cur->data.key); + } + if (re == 0) { + if (free_value) free_value(cur->data.value); + if (free_key) free_key(key); + cur->data.value = value; + return true; + } + BinarySearchTree* node = binary_tree_new>({key, value}); + if (!node) { + if (free_key) free_key(key); + if (free_value) free_value(value); + return false; + } + if (re == -1) { + cur->left = node; + } else { + cur->right = node; + } + return true; +} + +template +inline bool binary_search_tree_insert(BinarySearchTree*& root, K key, V value, F comp) { + return binary_search_tree_insert(root, key, value, std::function(comp)); +} + +template +bool binary_search_tree_insert(BinarySearchTree*& root, K key, V value) { + return binary_search_tree_insert(root, key, value, [](K k1, K k2) { + return k1 == k2 ? 0 : k1 < k2 ? -1 : 1; + }); +} + +#endif diff --git a/binary_tree.h b/binary_tree.h new file mode 100644 index 0000000..2a3d410 --- /dev/null +++ b/binary_tree.h @@ -0,0 +1,115 @@ +#ifndef _UTIL_BINARY_TREE_H +#define _UTIL_BINARY_TREE_H +#include +#include +#include +#include +#include "linked_queue.h" + +template +struct BinaryTree { + T data; + struct BinaryTree* left; + struct BinaryTree* right; +}; + +template +void binary_tree_clear(struct BinaryTree*& top, std::function free_func = std::function()) { + if (!top) return; + binary_tree_dfs(top, [&free_func](struct BinaryTree* node) { + if (free_func) { + free_func(node->data); + } + node->left = nullptr; + node->right = nullptr; + free(node); + }); + top = nullptr; +} + +template +inline void binary_tree_clear(struct BinaryTree*& top, F free_func) { + binary_tree_clear(top, std::function(free_func)); +} + +template +void binary_tree_dfs(struct BinaryTree* top, std::function*, Args...)> callback, Args... args) { + if (!top) return; + if (top->left) binary_tree_dfs(top->left, callback, args...); + if (top->right) binary_tree_dfs(top->right, callback, args...); + callback(top, args...); +} + +template +inline void binary_tree_dfs(struct BinaryTree* top, F callback, Args... args) { + binary_tree_dfs(top, std::function*, Args...)>(callback), args...); +} + +#define binary_tree_lrn binary_tree_dfs + +template +void binary_tree_lnr(struct BinaryTree* top, std::function*, Args...)> callback, Args... args) { + if (!top) return; + if (top->left) binary_tree_lnr(top->left, callback, args...); + callback(top, args...); + if (top->right) binary_tree_lnr(top->right, callback, args...); +} + +template +inline void binary_tree_lnr(struct BinaryTree* top, F callback, Args... args) { + binary_tree_lnr(top, std::function*, Args...)>(callback), args...); +} + +template +void binary_tree_nlr(struct BinaryTree* top, std::function*, Args...)> callback, Args... args) { + if (!top) return; + callback(top, args...); + if (top->left) binary_tree_nlr(top->left, callback, args...); + if (top->right) binary_tree_nlr(top->right, callback, args...); +} + +template +inline void binary_tree_nlr(struct BinaryTree* top, F callback, Args... args) { + binary_tree_nlr(top, std::function*, Args...)>(callback), args...); +} + +template +void binary_tree_bfs(struct BinaryTree* top, std::function*, Args...)> callback, Args... args) { + if (!top) return; + struct LinkedQueue*> queue; + linked_queue_init(queue); + linked_queue_push(queue, top); + struct BinaryTree* tmp; + while (linked_queue_pop(queue, tmp)) { + if (tmp->left) linked_queue_push(queue, tmp->left); + if (tmp->right) linked_queue_push(queue, tmp->right); + callback(tmp, args...); + } +} + +template +inline void binary_tree_bfs(struct BinaryTree* top, F callback, Args... args) { + binary_tree_bfs(top, std::function*, Args...)>(callback), args...); +} + +template +struct BinaryTree* binary_tree_new(T data) { + struct BinaryTree* node = (struct BinaryTree*)malloc(sizeof(struct BinaryTree)); + if (!node) return nullptr; + node->data = data; + node->left = nullptr; + node->right = nullptr; + return node; +} + +template +inline bool binary_tree_is_leaf(struct BinaryTree* node) { + return node->left == nullptr && node->right == nullptr; +} + +template +inline bool binary_tree_node_is_full(struct BinaryTree* node) { + return node->left != nullptr && node->right != nullptr; +} + +#endif diff --git a/linked_queue.h b/linked_queue.h index 4c1297a..256227e 100644 --- a/linked_queue.h +++ b/linked_queue.h @@ -16,6 +16,12 @@ struct LinkedQueue { struct LinkedQueueNode* rear; }; +template +void linked_queue_init(struct LinkedQueue& queue) { + queue.front = nullptr; + queue.rear = nullptr; +} + template size_t linked_queue_length(struct LinkedQueue& queue) { if (!queue.front) return 0; diff --git a/test/binary_tree_test.cpp b/test/binary_tree_test.cpp new file mode 100644 index 0000000..71295a8 --- /dev/null +++ b/test/binary_tree_test.cpp @@ -0,0 +1,72 @@ +#include "gtest/gtest.h" +#include "binary_search_tree.h" +#include + +TEST(BinaryTreeTest, BinaryTree1) { + struct BinaryTree* top = binary_tree_new(1); + top->left = binary_tree_new(2); + top->right = binary_tree_new(3); + top->left->left = binary_tree_new(4); + top->left->right = binary_tree_new(5); + top->right->right = binary_tree_new(6); + std::string text; + binary_tree_dfs(top, [&text](struct BinaryTree* ele) { + if (!text.empty()) { + text += ","; + } + text += std::to_string(ele->data); + }); + GTEST_ASSERT_EQ(text, "4,5,2,6,3,1"); + text = ""; + binary_tree_lnr(top, [&text](struct BinaryTree* ele) { + if (!text.empty()) { + text += ","; + } + text += std::to_string(ele->data); + }); + GTEST_ASSERT_EQ(text, "4,2,5,1,3,6"); + text = ""; + binary_tree_nlr(top, [&text](struct BinaryTree* ele) { + if (!text.empty()) { + text += ","; + } + text += std::to_string(ele->data); + }); + GTEST_ASSERT_EQ(text, "1,2,4,5,3,6"); + text = ""; + binary_tree_bfs(top, [&text](struct BinaryTree* ele) { + if (!text.empty()) { + text += ","; + } + text += std::to_string(ele->data); + }); + GTEST_ASSERT_EQ(text, "1,2,3,4,5,6"); + binary_tree_clear(top); +} + +TEST(BinaryTreeTest, BinarySearchTree1) { + BinarySearchTree* tree = nullptr; + binary_search_tree_insert(tree, 100, 3); + GTEST_ASSERT_EQ(tree->data.key, 100); + GTEST_ASSERT_EQ(tree->data.value, 3); + binary_search_tree_insert(tree, 100, 20); + GTEST_ASSERT_EQ(tree->data.value, 20); + binary_search_tree_insert(tree, 20, 45); + binary_search_tree_insert(tree, 40, 13); + binary_search_tree_insert(tree, 33, 23); + binary_search_tree_insert(tree, 77, 33); + binary_search_tree_insert(tree, 120, 222); + std::string keys; + std::string values; + binary_search_tree_iter(tree, [&keys, &values](int key, int value) { + if (!keys.empty()) { + keys += ","; + values += ","; + } + keys += std::to_string(key); + values += std::to_string(value); + }); + GTEST_ASSERT_EQ(keys, "20,33,40,77,100,120"); + GTEST_ASSERT_EQ(values, "45,23,13,33,20,222"); + binary_search_tree_clear(tree); +} diff --git a/test/queue_test.cpp b/test/queue_test.cpp index 30a65e6..fc9ab36 100644 --- a/test/queue_test.cpp +++ b/test/queue_test.cpp @@ -85,8 +85,7 @@ TEST(Queue_Test, CircularQueue2) { TEST(Queue_Test, LinkedQueue1) { struct LinkedQueue queue; - queue.front = nullptr; - queue.rear = nullptr; + linked_queue_init(queue); EXPECT_EQ(linked_queue_push(queue, 3), true); EXPECT_EQ(linked_queue_push(queue, 4), true); EXPECT_EQ(linked_queue_push(queue, 9), true); @@ -105,3 +104,20 @@ TEST(Queue_Test, LinkedQueue1) { EXPECT_EQ(text, "4,9,7"); free_linked_queue(queue); } + +TEST(Queue_Test, LinkedQueue2) { + struct LinkedQueue queue; + linked_queue_init(queue); + EXPECT_EQ(linked_queue_push(queue, 3), true); + EXPECT_EQ(linked_queue_push(queue, 4), true); + EXPECT_EQ(linked_queue_push(queue, 9), true); + int v; + EXPECT_EQ(linked_queue_pop(queue, v), true); + EXPECT_EQ(v, 3); + EXPECT_EQ(linked_queue_pop(queue, v), true); + EXPECT_EQ(linked_queue_pop(queue, v), true); + EXPECT_EQ(linked_queue_pop(queue, v), false); + EXPECT_EQ(v, 9); + EXPECT_EQ(queue.front, nullptr); + EXPECT_EQ(queue.rear, nullptr); +}