From f8db72bb6365e6cda02e7e26d2153bb98b4230ae Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Sat, 10 Aug 2024 22:05:37 +0530 Subject: [PATCH 1/4] set up and basic implementation added --- Headers/0002_Tree/0001_BinarySearchTree.h | 32 +++++++ .../0002_Tree/0001_BinarySearchTree.cc | 90 +++++++++++++++++++ SourceCodes/0002_Tree/CMakeLists.txt | 7 ++ Tests/0002_Tree/0001_BinarySearchTreeTest.cc | 10 +++ Tests/0002_Tree/CMakeLists.txt | 29 ++++++ 5 files changed, 168 insertions(+) create mode 100644 Headers/0002_Tree/0001_BinarySearchTree.h create mode 100644 SourceCodes/0002_Tree/0001_BinarySearchTree.cc create mode 100644 Tests/0002_Tree/0001_BinarySearchTreeTest.cc diff --git a/Headers/0002_Tree/0001_BinarySearchTree.h b/Headers/0002_Tree/0001_BinarySearchTree.h new file mode 100644 index 0000000..e0d08c2 --- /dev/null +++ b/Headers/0002_Tree/0001_BinarySearchTree.h @@ -0,0 +1,32 @@ +#pragma once +using namespace std; + +class Node +{ +public: + int data; + Node* parent; + Node* left; + Node* right; + + Node(int data, Node* parent, Node* left, Node* right); +}; + +class BinarySearchTree +{ +private: + Node* _root; + void _InsertNode(Node* node, int value); + Node* _FindNode(Node* node, int value); + Node* _FindMinimumValueNode(Node* node); + void _DeleteNode(Node* node); + void _RecursiveInorderTraversal(Node* node); + void _RecursivePreorderTraversal(Node* node); + void _RecursivePostorderTraversal(Node* node); + void _MorrisInorderTraversal(Node* node); + void _MorrisPreorderTraversal(Node* node); + void _MorrisPostorderTraversal(Node* node); +public: + BinarySearchTree(); + void InsertNode(int value); +}; \ No newline at end of file diff --git a/SourceCodes/0002_Tree/0001_BinarySearchTree.cc b/SourceCodes/0002_Tree/0001_BinarySearchTree.cc new file mode 100644 index 0000000..92e8a52 --- /dev/null +++ b/SourceCodes/0002_Tree/0001_BinarySearchTree.cc @@ -0,0 +1,90 @@ +#include "../Headers/0002_Tree/0001_BinarySearchTree.h" +#include +using namespace std; + + +Node::Node(int data, Node* parent, Node* left, Node* right) +{ + this->data = data; + this->parent = parent; + this->left = left; + this->right = right; +} + +BinarySearchTree::BinarySearchTree() +{ + this->_root = NULL; +} + + +void BinarySearchTree::_InsertNode(Node* node, int value) +{ + if (value < node->data) + { + if (node->left == NULL) + { + node->left = new Node(value, NULL, NULL, NULL); + } + else + { + this->_InsertNode(node->left, value); + } + } + else + { + if (node->right == NULL) + { + node->right = new Node(value, NULL, NULL, NULL); + } + else + { + this->_InsertNode(node->right, value); + } + } +} + +Node* BinarySearchTree::_FindNode(Node* node, int value) +{ + while (node != NULL) + { + if (value < node->data) + { + node = node->left; + } + else if(value > node->data) + { + node = node->right; + } + else + { + break; + } + return node; + } +} + +Node* BinarySearchTree::_FindMinimumValueNode(Node* node) +{ + while (node->left != NULL) + { + node = node->left; + } + return node; +} + +void BinarySearchTree::_DeleteNode(Node* node) +{ + +} + +void BinarySearchTree::InsertNode(int value) +{ + if (this->_root == NULL) + { + this->_root = new Node(value, NULL, NULL, NULL); + } + else + { + this->_InsertNode(this->_root, value); + } +} \ No newline at end of file diff --git a/SourceCodes/0002_Tree/CMakeLists.txt b/SourceCodes/0002_Tree/CMakeLists.txt index e69de29..e3b68a8 100644 --- a/SourceCodes/0002_Tree/CMakeLists.txt +++ b/SourceCodes/0002_Tree/CMakeLists.txt @@ -0,0 +1,7 @@ +# Specify the source files +set(0002TREE_SOURCES + 0001_BinarySearchTree.cc +) + +# Create a library target +add_library(0002Tree ${0002TREE_SOURCES}) \ No newline at end of file diff --git a/Tests/0002_Tree/0001_BinarySearchTreeTest.cc b/Tests/0002_Tree/0001_BinarySearchTreeTest.cc new file mode 100644 index 0000000..8d55a8f --- /dev/null +++ b/Tests/0002_Tree/0001_BinarySearchTreeTest.cc @@ -0,0 +1,10 @@ +#include +#include "../Headers/0002_Tree/0001_BinarySearchTree.h" + +namespace BinarySearchTreeTest +{ + TEST(BSTTesting, ShowBSTResultTest) + { + ASSERT_EQ(1, 1); + } +} \ No newline at end of file diff --git a/Tests/0002_Tree/CMakeLists.txt b/Tests/0002_Tree/CMakeLists.txt index e69de29..8f2dcc4 100644 --- a/Tests/0002_Tree/CMakeLists.txt +++ b/Tests/0002_Tree/CMakeLists.txt @@ -0,0 +1,29 @@ +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + + +enable_testing() + +add_executable( + 0002-TreeTests + 0001_BinarySearchTreeTest.cc) + +target_link_libraries( + 0002-TreeTests + GTest::gtest_main +) + +target_link_libraries( + 0002-TreeTests + 0001Basics +) + + +include(GoogleTest) +gtest_discover_tests(0002-TreeTests) \ No newline at end of file From a8fba9f54e56b0af8e3c220dda127a6b60bda400 Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Tue, 27 Aug 2024 22:31:07 +0530 Subject: [PATCH 2/4] bst insertion, min, max logic added --- Headers/0002_Tree/0001_BinarySearchTree.h | 21 +++-- .../0002_Tree/0001_BinarySearchTree.cc | 81 ++++++++++++++----- Tests/0002_Tree/0001_BinarySearchTreeTest.cc | 1 + Tests/0002_Tree/CMakeLists.txt | 8 +- 4 files changed, 77 insertions(+), 34 deletions(-) diff --git a/Headers/0002_Tree/0001_BinarySearchTree.h b/Headers/0002_Tree/0001_BinarySearchTree.h index e0d08c2..0153b89 100644 --- a/Headers/0002_Tree/0001_BinarySearchTree.h +++ b/Headers/0002_Tree/0001_BinarySearchTree.h @@ -1,6 +1,7 @@ #pragma once -using namespace std; +#include +using namespace std; class Node { public: @@ -16,17 +17,21 @@ class BinarySearchTree { private: Node* _root; - void _InsertNode(Node* node, int value); + void _InsertNode(Node* node); Node* _FindNode(Node* node, int value); Node* _FindMinimumValueNode(Node* node); + Node* _FindMaximumValueNode(Node* node); + Node* _FindSuccessorNode(Node* node); + Node* _FindPredecessorNode(Node* node); void _DeleteNode(Node* node); - void _RecursiveInorderTraversal(Node* node); - void _RecursivePreorderTraversal(Node* node); - void _RecursivePostorderTraversal(Node* node); - void _MorrisInorderTraversal(Node* node); - void _MorrisPreorderTraversal(Node* node); - void _MorrisPostorderTraversal(Node* node); + string _RecursiveInorderTraversal(Node* node); + string _RecursivePreorderTraversal(Node* node); + string _RecursivePostorderTraversal(Node* node); + string _MorrisInorderTraversal(Node* node); + string _MorrisPreorderTraversal(Node* node); + string _MorrisPostorderTraversal(Node* node); public: BinarySearchTree(); + void CheckBSTresult(); void InsertNode(int value); }; \ No newline at end of file diff --git a/SourceCodes/0002_Tree/0001_BinarySearchTree.cc b/SourceCodes/0002_Tree/0001_BinarySearchTree.cc index 92e8a52..e461ed3 100644 --- a/SourceCodes/0002_Tree/0001_BinarySearchTree.cc +++ b/SourceCodes/0002_Tree/0001_BinarySearchTree.cc @@ -13,39 +13,44 @@ Node::Node(int data, Node* parent, Node* left, Node* right) BinarySearchTree::BinarySearchTree() { - this->_root = NULL; + this->_root = nullptr; } -void BinarySearchTree::_InsertNode(Node* node, int value) +void BinarySearchTree::_InsertNode(Node* node) { - if (value < node->data) + Node* nodeY = nullptr; + Node* nodeX = this->_root; + while (nodeX != nullptr) { - if (node->left == NULL) + nodeY = nodeX; + if (node->data < nodeX->data) { - node->left = new Node(value, NULL, NULL, NULL); + nodeX = nodeX->left; } else { - this->_InsertNode(node->left, value); + nodeX = nodeX->right; } } + node->parent = nodeY; + if (nodeY == nullptr) + { + this->_root = node; + } + else if (node->data < nodeY->data) + { + nodeY->left = node; + } else { - if (node->right == NULL) - { - node->right = new Node(value, NULL, NULL, NULL); - } - else - { - this->_InsertNode(node->right, value); - } + nodeY->right = node; } } Node* BinarySearchTree::_FindNode(Node* node, int value) { - while (node != NULL) + while (node != nullptr) { if (value < node->data) { @@ -65,26 +70,58 @@ Node* BinarySearchTree::_FindNode(Node* node, int value) Node* BinarySearchTree::_FindMinimumValueNode(Node* node) { - while (node->left != NULL) + while (node->left != nullptr) { node = node->left; } return node; } -void BinarySearchTree::_DeleteNode(Node* node) +Node* BinarySearchTree::_FindMaximumValueNode(Node* node) { + while (node->right != nullptr) + { + node = node->right; + } + return node; +} +Node* BinarySearchTree::_FindSuccessorNode(Node* node) +{ + if (node->right != nullptr) + { + return this->_FindMinimumValueNode(node->right); + } + Node* nodeY = node->parent; + while (nodeY != nullptr && node == nodeY->right) + { + node = nodeY; + nodeY = nodeY->parent; + } + return nodeY; } -void BinarySearchTree::InsertNode(int value) +Node* BinarySearchTree::_FindPredecessorNode(Node* node) { - if (this->_root == NULL) + if (node->left != nullptr) { - this->_root = new Node(value, NULL, NULL, NULL); + return this->_FindMaximumValueNode(node->left); } - else + Node* nodeY = node->parent; + while (nodeY != nullptr && node == nodeY->left) { - this->_InsertNode(this->_root, value); + node = nodeY; + nodeY = nodeY->parent; } +} + +void BinarySearchTree::_DeleteNode(Node* node) +{ + +} + +void BinarySearchTree::InsertNode(int value) +{ + Node* node = new Node(value, nullptr, nullptr, nullptr); + this->_InsertNode(node); } \ No newline at end of file diff --git a/Tests/0002_Tree/0001_BinarySearchTreeTest.cc b/Tests/0002_Tree/0001_BinarySearchTreeTest.cc index 8d55a8f..7d199ca 100644 --- a/Tests/0002_Tree/0001_BinarySearchTreeTest.cc +++ b/Tests/0002_Tree/0001_BinarySearchTreeTest.cc @@ -1,4 +1,5 @@ #include +#include #include "../Headers/0002_Tree/0001_BinarySearchTree.h" namespace BinarySearchTreeTest diff --git a/Tests/0002_Tree/CMakeLists.txt b/Tests/0002_Tree/CMakeLists.txt index 8f2dcc4..36bfab2 100644 --- a/Tests/0002_Tree/CMakeLists.txt +++ b/Tests/0002_Tree/CMakeLists.txt @@ -11,19 +11,19 @@ FetchContent_MakeAvailable(googletest) enable_testing() add_executable( - 0002-TreeTests + 0002_Tree_Tests 0001_BinarySearchTreeTest.cc) target_link_libraries( - 0002-TreeTests + 0002_Tree_Tests GTest::gtest_main ) target_link_libraries( - 0002-TreeTests + 0002_Tree_Tests 0001Basics ) include(GoogleTest) -gtest_discover_tests(0002-TreeTests) \ No newline at end of file +gtest_discover_tests(0002_Tree_Tests) \ No newline at end of file From fe9db0aa956c0db14737c5bf7fee45c5b6135ff4 Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Tue, 10 Sep 2024 01:08:43 +0530 Subject: [PATCH 3/4] bst implementation and basic test added --- Headers/0002_Tree/0001_BinarySearchTree.h | 7 +- .../0002_Tree/0001_BinarySearchTree.cc | 125 +++++++++++++++++- SourceCodes/0002_Tree/CMakeLists.txt | 2 +- Tests/0002_Tree/0001_BinarySearchTreeTest.cc | 20 ++- Tests/0002_Tree/CMakeLists.txt | 10 +- 5 files changed, 148 insertions(+), 16 deletions(-) diff --git a/Headers/0002_Tree/0001_BinarySearchTree.h b/Headers/0002_Tree/0001_BinarySearchTree.h index 0153b89..6e4963d 100644 --- a/Headers/0002_Tree/0001_BinarySearchTree.h +++ b/Headers/0002_Tree/0001_BinarySearchTree.h @@ -18,11 +18,12 @@ class BinarySearchTree private: Node* _root; void _InsertNode(Node* node); - Node* _FindNode(Node* node, int value); + Node* _FindNode(int value); Node* _FindMinimumValueNode(Node* node); Node* _FindMaximumValueNode(Node* node); Node* _FindSuccessorNode(Node* node); Node* _FindPredecessorNode(Node* node); + void _Transplant(Node* nodeU, Node* nodeV); void _DeleteNode(Node* node); string _RecursiveInorderTraversal(Node* node); string _RecursivePreorderTraversal(Node* node); @@ -32,6 +33,8 @@ class BinarySearchTree string _MorrisPostorderTraversal(Node* node); public: BinarySearchTree(); - void CheckBSTresult(); void InsertNode(int value); + void DeleteNode(int value); + string GetRecursiveInorderTravesalResult(); + string GetMorrisInorderTraversalResult(); }; \ No newline at end of file diff --git a/SourceCodes/0002_Tree/0001_BinarySearchTree.cc b/SourceCodes/0002_Tree/0001_BinarySearchTree.cc index e461ed3..a29db5d 100644 --- a/SourceCodes/0002_Tree/0001_BinarySearchTree.cc +++ b/SourceCodes/0002_Tree/0001_BinarySearchTree.cc @@ -48,8 +48,9 @@ void BinarySearchTree::_InsertNode(Node* node) } } -Node* BinarySearchTree::_FindNode(Node* node, int value) +Node* BinarySearchTree::_FindNode(int value) { + Node* node = this->_root; while (node != nullptr) { if (value < node->data) @@ -64,8 +65,8 @@ Node* BinarySearchTree::_FindNode(Node* node, int value) { break; } - return node; } + return node; } Node* BinarySearchTree::_FindMinimumValueNode(Node* node) @@ -115,13 +116,131 @@ Node* BinarySearchTree::_FindPredecessorNode(Node* node) } } +void BinarySearchTree::_Transplant(Node* nodeU, Node* nodeV) +{ + if (nodeU->parent == nullptr) + { + this->_root = nodeV; + } + else if (nodeU == nodeU->parent->left) + { + nodeU->parent->left = nodeV; + } + else + { + nodeU->parent->right = nodeV; + } + + if (nodeV != nullptr) + { + nodeV->parent = nodeU->parent; + } +} + void BinarySearchTree::_DeleteNode(Node* node) { - + if (node->left == nullptr) + { + this->_Transplant(node, node->right); + } + else if (node->right == nullptr) + { + this->_Transplant(node, node->left); + } + else + { + Node* nodeY = this->_FindMinimumValueNode(node->right); + if (nodeY->parent != node) + { + this->_Transplant(nodeY, nodeY->right); + nodeY->right = node->right; + nodeY->right->parent = nodeY; + } + this->_Transplant(node, nodeY); + nodeY->left = node->left; + nodeY->left->parent = nodeY; + delete node; + } +} + +string BinarySearchTree::_RecursiveInorderTraversal(Node* node) +{ + if (node == nullptr) + { + return ""; + } + string leftSubTree = this->_RecursiveInorderTraversal(node->left); + string currentNode = to_string(node->data); + string rightSubTree = this->_RecursiveInorderTraversal(node->right); + + string result = leftSubTree; + if (!leftSubTree.empty()) + { + result += " "; + } + result += currentNode; + if (!rightSubTree.empty()) + { + result += " " + rightSubTree; + } + return result; +} + +string BinarySearchTree::_MorrisInorderTraversal(Node* node) +{ + string result = ""; + while (node != nullptr) + { + if (node->left == nullptr) + { + result += to_string(node->data) + " "; + node = node->right; + } + else + { + Node* predecessor = node->left; + while (predecessor->right != nullptr && predecessor->right != node) + { + predecessor = predecessor->right; + } + if (predecessor->right == nullptr) + { + predecessor->right = node; + node = node->left; + } + else + { + predecessor->right = nullptr; + result += to_string(node->data) + " "; + node = node->right; + } + } + } + if (!result.empty()) + { + result.pop_back(); + } + return result; } void BinarySearchTree::InsertNode(int value) { Node* node = new Node(value, nullptr, nullptr, nullptr); this->_InsertNode(node); +} + +void BinarySearchTree::DeleteNode(int value) +{ + Node* node = this->_FindNode(value); + this->_DeleteNode(node); +} + +string BinarySearchTree::GetRecursiveInorderTravesalResult() +{ + return this->_RecursiveInorderTraversal(this->_root); +} + +string BinarySearchTree::GetMorrisInorderTraversalResult() +{ + return this->_MorrisInorderTraversal(this->_root); } \ No newline at end of file diff --git a/SourceCodes/0002_Tree/CMakeLists.txt b/SourceCodes/0002_Tree/CMakeLists.txt index e3b68a8..cc7027a 100644 --- a/SourceCodes/0002_Tree/CMakeLists.txt +++ b/SourceCodes/0002_Tree/CMakeLists.txt @@ -4,4 +4,4 @@ set(0002TREE_SOURCES ) # Create a library target -add_library(0002Tree ${0002TREE_SOURCES}) \ No newline at end of file +add_library(0002TREE ${0002TREE_SOURCES}) \ No newline at end of file diff --git a/Tests/0002_Tree/0001_BinarySearchTreeTest.cc b/Tests/0002_Tree/0001_BinarySearchTreeTest.cc index 7d199ca..dec2e0d 100644 --- a/Tests/0002_Tree/0001_BinarySearchTreeTest.cc +++ b/Tests/0002_Tree/0001_BinarySearchTreeTest.cc @@ -1,11 +1,21 @@ -#include +#include #include #include "../Headers/0002_Tree/0001_BinarySearchTree.h" +// Demonstrate some basic assertions. namespace BinarySearchTreeTest { - TEST(BSTTesting, ShowBSTResultTest) - { - ASSERT_EQ(1, 1); - } + TEST(BSTTesting, ShowBSTResultTest) + { + BinarySearchTree bst; + bst.InsertNode(50); + bst.InsertNode(30); + bst.InsertNode(60); + + + string actualResult = bst.GetRecursiveInorderTravesalResult(); + string expectedResult = "30 50 60"; + + EXPECT_EQ(actualResult, expectedResult); + } } \ No newline at end of file diff --git a/Tests/0002_Tree/CMakeLists.txt b/Tests/0002_Tree/CMakeLists.txt index 36bfab2..c662127 100644 --- a/Tests/0002_Tree/CMakeLists.txt +++ b/Tests/0002_Tree/CMakeLists.txt @@ -11,19 +11,19 @@ FetchContent_MakeAvailable(googletest) enable_testing() add_executable( - 0002_Tree_Tests + 0002TreeTests 0001_BinarySearchTreeTest.cc) target_link_libraries( - 0002_Tree_Tests + 0002TreeTests GTest::gtest_main ) target_link_libraries( - 0002_Tree_Tests - 0001Basics + 0002TreeTests + 0002TREE ) include(GoogleTest) -gtest_discover_tests(0002_Tree_Tests) \ No newline at end of file +gtest_discover_tests(0002TreeTests) \ No newline at end of file From b90f85c5f1cc344ea66e713c24f1a5e8937fd490 Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Tue, 10 Sep 2024 01:16:03 +0530 Subject: [PATCH 4/4] minor fix --- SourceCodes/0002_Tree/0001_BinarySearchTree.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/SourceCodes/0002_Tree/0001_BinarySearchTree.cc b/SourceCodes/0002_Tree/0001_BinarySearchTree.cc index a29db5d..9e8a095 100644 --- a/SourceCodes/0002_Tree/0001_BinarySearchTree.cc +++ b/SourceCodes/0002_Tree/0001_BinarySearchTree.cc @@ -114,6 +114,7 @@ Node* BinarySearchTree::_FindPredecessorNode(Node* node) node = nodeY; nodeY = nodeY->parent; } + return nodeY; } void BinarySearchTree::_Transplant(Node* nodeU, Node* nodeV)