Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Threaded Binary Tree in OPEN-DSA/Trees/Threaded Binary Tree ) Insert, Delete, some more functions, Conversion from BT to TBT also added. #15

Merged
merged 6 commits into from
Oct 18, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions Data Structures/Trees/Threaded Binary Tree/Binary_to_threaded.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/* C++ program to convert a Binary Tree to Threaded Tree */
#include <bits/stdc++.h>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only include the libraries which are required. Don't include bits/stdc++.h.
Do the same for every file.

using namespace std;

/* Structure of a node in threaded binary tree */
struct Node {
int key;
Node *left, *right;

// Used to indicate whether the right pointer is a normal
// right pointer or a pointer to inorder successor.
bool isThreaded;
};

// Helper function to put the Nodes in inorder into queue
void populateQueue(Node* root, std::queue<Node*>* q)
{
if (root == NULL)
return;
if (root->left)
populateQueue(root->left, q);
q->push(root);
if (root->right)
populateQueue(root->right, q);
}

// Function to traverse queue, and make tree threaded
void createThreadedUtil(Node* root, std::queue<Node*>* q)
{
if (root == NULL)
return;

if (root->left)
createThreadedUtil(root->left, q);
q->pop();

if (root->right)
createThreadedUtil(root->right, q);

// If right pointer is NULL, link it to the
// inorder successor and set 'isThreaded' bit.
else {
root->right = q->front();
root->isThreaded = true;
}
}

// This function uses populateQueue() and
// createThreadedUtil() to convert a given binary tree
// to threaded tree.
void createThreaded(Node* root)
{
// Create a queue to store inorder traversal
std::queue<Node*> q;

// Store inorder traversal in queue
populateQueue(root, &q);

// Link NULL right pointers to inorder successor
createThreadedUtil(root, &q);
}

// A utility function to find leftmost node in a binary
// tree rooted with 'root'. This function is used in inOrder()
Node* leftMost(Node* root)
{
while (root != NULL && root->left != NULL)
root = root->left;
return root;
}

// Function to do inorder traversal of a threaded binary tree
void inOrder(Node* root)
{
if (root == NULL)
return;

// Find the leftmost node in Binary Tree
Node* cur = leftMost(root);

while (cur != NULL) {
cout << cur->key << " ";

// If this Node is a thread Node, then go to
// inorder successor
if (cur->isThreaded)
cur = cur->right;

else // Else go to the leftmost child in right subtree
cur = leftMost(cur->right);
}
}

// A utility function to create a new node
Node* newNode(int key)
{
Node* temp = new Node;
temp->left = temp->right = NULL;
temp->key = key;
return temp;
}

// Driver program to test above functions
int main()
{
/* 1
/ \
2 3
/ \ / \
4 5 6 7 */
Node* root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
root->right->right = newNode(7);

createThreaded(root);

cout << "Inorder traversal of created threaded tree is\n";
inOrder(root);
return 0;
}

// Output:

// Inorder traversal of created threaded tree is
// 4 2 5 1 6 3 7
122 changes: 122 additions & 0 deletions Data Structures/Trees/Threaded Binary Tree/E_Binary_to_threaded.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/* C++ program to convert a Binary Tree to
Threaded Tree */
#include <bits/stdc++.h>
using namespace std;

/* Structure of a node in threaded binary tree */
struct Node
{
int key;
Node *left, *right;

// Used to indicate whether the right pointer
// is a normal right pointer or a pointer
// to inorder successor.
bool isThreaded;
};

// Converts tree with given root to threaded
// binary tree.
// This function returns rightmost child of
// root.
Node *createThreaded(Node *root)
{
// Base cases : Tree is empty or has single
// node
if (root == NULL)
return NULL;
if (root->left == NULL &&
root->right == NULL)
return root;

// Find predecessor if it exists
if (root->left != NULL)
{
// Find predecessor of root (Rightmost
// child in left subtree)
Node* l = createThreaded(root->left);

// Link a thread from predecessor to
// root.
l->right = root;
l->isThreaded = true;
}

// If current node is rightmost child
if (root->right == NULL)
return root;

// Recur for right subtree.
return createThreaded(root->right);
}

// A utility function to find leftmost node
// in a binary tree rooted with 'root'.
// This function is used in inOrder()
Node *leftMost(Node *root)
{
while (root != NULL && root->left != NULL)
root = root->left;
return root;
}

// Function to do inorder traversal of a threadded
// binary tree
void inOrder(Node *root)
{
if (root == NULL) return;

// Find the leftmost node in Binary Tree
Node *cur = leftMost(root);

while (cur != NULL)
{
cout << cur->key << " ";

// If this Node is a thread Node, then go to
// inorder successor
if (cur->isThreaded)
cur = cur->right;

else // Else go to the leftmost child in right subtree
cur = leftMost(cur->right);
}
}

// A utility function to create a new node
Node *newNode(int key)
{
Node *temp = new Node;
temp->left = temp->right = NULL;
temp->key = key;
return temp;
}

// Driver program to test above functions
int main()
{
/* 1
/ \
2 3
/ \ / \
4 5 6 7 */
Node *root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
root->right->right = newNode(7);

createThreaded(root);

cout << "Inorder traversal of created "
"threaded tree is\n";
inOrder(root);
return 0;
}

// Output

// Inorder traversal of created threaded tree is
// 4 2 5 1 6 3 7
98 changes: 98 additions & 0 deletions Data Structures/Trees/Threaded Binary Tree/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
**Threaded Binary Tree:**

The idea of threaded binary trees is to make inorder traversal faster and do it without stack and without recursion. A binary tree is made threaded by making all right child pointers that would normally be NULL point to the inorder successor of the node (if it exists).

**There are two types of threaded binary trees:**

- Single Threaded: Where a NULL right pointers is made to point to the inorder successor (if successor exists)
- Double Threaded: Where both left and right NULL pointers are made to point to inorder predecessor and inorder successor respectively. The predecessor threads are useful for reverse inorder traversal and postorder traversal.

The threads are also useful for fast accessing ancestors of a node.

**Single Threaded Binary Tree:** Here only the right NULL pointer are made to point to inorder successor.

**Double Threaded Binary Tree:** Here both the right as well as the left NULL pointers are made to point inorder successor and inorder predecessor respectively. (here the left threads are helpful in reverse inorder traveral of the tree )

**Structure of node in threaded binary tree:**

A node in threaded binary tree has two additional attributes:

- rightThread
- leftThread

Both new attributes are of type bolean.

**Following is the node structure in a Single threaded binary tree and Double threaded binary tree:**

// **single** threaded<br>

struct Node{<br>
Node *left ;<br>
Node *right ;<br>
bool rightThread ;<br>
}<br>

// **double** threaded<br>

struct Node{<br>
int data ;<br>
Node *left ;<br>
Node *right ;<br>
bool leftThread ;<br>
bool rightThread ;<br>
}<br>

**Significance of bool variable (leftThread and rightThread) in structure:**

If we have some address stored in some node to diffrentiate whether that address is of parent node or of child node we use leftThread and rightThread bool variables.

LeftThread and rightThread bool variables stores whether left and right pointers point to child node or some ancestor node , if the bool variable is set to true that means pointer is pointing to child node and if it is set to 1 that means that pointer is pointing to parent node.

**For example:**

Let's us say for some node right pointer is pointing to some node and righThread is set to true, this means that it is pointing to it's children, but if in the same case if rightThread is set to false this means that it is pointing to it's parent node (and not child ).

**What happens with righmost and leftmost null nodes ?**

When we create a threaded binary tree the left most and rightmost pointers do not have inorder predecessor or inorder successor so they are made to point to a dummy node as you can see in the image and leftThread of leftmost node and rightThread of rightmost node is set to false.

**Operations in Threaded Binary Tree**

We can also perform various operations in a threaded binary tree like -

1.**Insert**<br>
2.**search**<br>
3.**Delete**<br>

After performing the following operations we need to make sure that our new binary tree still follows all the conditions of a threaded binary tree and also these operations should be performed with least amount of space and time complexity possible.

**Applications of Threaded Binary Tree:**

The idea of threaded binary trees is to make inorder traversal of the binary tree faster and do it without using any extra space, so sometimes in small systems where hardware is very limited we use threaded binary tree for better efficiency of the software in a limited hardware space.

**Time and space complexity for operations**

Time complexity for:

- For insertion : log(n)<br>
- For deletion : log(n)<br>
- For seaching : log(n)<br>

**Space complexity** for insertion is O(1) , for deletion and searching we donot require any extra space.

The time required for finding inorder predecessor or successor for a given node is O(1) provided we are on that node.

**The Code for Threaded Binary Tree and all other Operations are given in Threaded_Binary_Tree_all.cpp**

**Convert a Binary Tree to Threaded Binary Tree (Using Queue)**

We basically need to set NULL right pointers to inorder successor. We first do an inorder traversal of the tree and store it in a queue (we can use a simple array also) so that the inorder successor becomes the next node. We again do an inorder traversal and whenever we find a node whose right is NULL, we take the front item from queue and make it the right of current node. We also set isThreaded to true to indicate that the right pointer is a threaded link.

**The Code for conversion of a Binary Tree to Threaded Binary Tree (Using Queue) is given in Binary_to_threaded.cpp**

**Convert a Binary Tree to Threaded Binary Tree (Efficient Method)**

In this efficient case, a space-efficient solution is discussed that doesn’t require a queue.
The idea is based on the fact that we link from inorder predecessor to a node. We link those inorder predecessor which lie in subtree of node. So we find inorder predecessor of a node if its left is not NULL. Inorder predecessor of a node (whose left is NULL) is a rightmost node in the left child. Once we find the predecessor, we link a thread from it to the current node. This algorithm works in O(n) time complexity and O(1) space other than function call stack.

**The Code for conversion of a Binary Tree to Threaded Binary Tree (Efficient Method) is given in E_Binary_to_threaded.cpp**
Loading