How do i implement a Queue using a BST.
Is this the way to do it, keep on inserting the nodes in the tree while maintaining a count value associated with each and every node,but while deletion BST should work like queue(FIFO) so start deleting from BST with the node having lowest count value in the tree.
Did i get the question and solution right? If not,then please explain me the question.
A BST is really an inappropriate data structure to use to back a queue. You really ought to use a linked list instead, because it would be way faster, less complicated, and plain old better.
However, if you insist on using a BST...
You would use the BST as a priority queue, and define a wrapper type that also holds a 'queue index', which is what the items would be sorted by. You would have to define the comparison to take into account the current queue index though, because otherwise you could only ever add as many items as the difference between the highest and lowest values of your index type.
You can have a Queue like this:
BST // to store data
pointer to head; // Points to the head of the Queue
pointer to tail // Points to the tail of the Queue
You add to the nodes structs of BST also a pointer to another node that will represent the order of insertion.
struct Node{
int x;
//left pointer
//right pointer
struct Node *next_queune_element;
}
During the insertion
When you want to add an element, you first access the node that the pointer tail points to and make it point to the new element that you just inserted (the BST node). Then you update the tail pointer to point to the new element.
During the deletion
When you remove an element, you first access the node that the head pointer points to, you store the next_queune_element in an auxiliary temporary variable and remove the node. Finally, make the head pointer to point to the auxiliary temporary variable.
I think a binary tree would be the desired data structure here and not a binary search tree. Using a binary tree for implementing a queue might be usefull when doing functional programming. You can do it using a binary tree which stays height balanced after each push and pop operation so they will always be O(log n). Push and pop look like:
a function to insert an element to the very left of the tree (the push function);
a function to delete an element from the very right of the tree (the pop fuction).
In both cases rebalancing won't violate the insertion order. Both are easy too implement as well. You are in fact using an AVL tree with altered insert functions. A bonus is the elements do not need to be (totally) orderable.
Related
I am trying to implement a B-tree and from what I understand this is how you split a node:
Attempt to insert a new value V at a leaf node N
If the leaf node has no space, create a new node and pick a middle value of N and anything right of it move to the new node and anything to the left of the middle value leave in the old node, but move it left to free up the right indices and insert V in the appropriate of the now two nodes
Insert the middle value we picked into the parent node of N and also add the newly created node to the list of children of the parent of N (thus making N and the new node siblings)
If the parent of N has no free space, perform the same operation and along with the values also split the children between the two split nodes (so this last part applies only to non-leaf nodes)
Continue trying to insert the previous split's middle point into the parent until you reach the root and potentially split the root itself, making a new root
This brings me to the question - how do I traverse upwards, am I supposed to keep a pointer of the parent?
Because I can only know if I have to split the leaf node when I have reached it for insertion. So once I have to split it, I have to somehow go back to its parent and if I have to split the parent as well, I have to keep going back up.
Otherwise I would have to re-traverse the tree again and again each time to find the next parent.
Here is an example of my node class:
template<typename KEY, typename VALUE, int DEGREE>
struct BNode
{
KEY Keys[DEGREE];
VALUE Values[DEGREE];
BNode<KEY, VALUE, DEGREE>* Children[DEGREE + 1];
BNode<KEY, VALUE, DEGREE>* Parent;
bool IsLeaf;
};
(Maybe I should not have an IsLeaf field and instead just check if it has any children, to save space)
Even if you don't use recursion or an explicit stack while going down the tree, you can still do it without parent pointers if you split nodes a bit sooner with a slightly modified algorithm, which has this key characteristic:
When encountering a node that is full, split it, even when it is not a leaf.
With this pre-emptive splitting algorithm, you only need to keep a reference to the immediate parent (not any other ancestor) to make the split possible, since now it is guaranteed that a split will not lead to another, cascading split more upwards in the tree. This algorithm requires that the maximum degree (number of children) of the B-tree is even (as otherwise one of the two split nodes would have too few keys to be considered valid).
See also Wikipedia which describes this alternative algorithm as follows:
An alternative algorithm supports a single pass down the tree from the root to the node where the insertion will take place, splitting any full nodes encountered on the way preemptively. This prevents the need to recall the parent nodes into memory, which may be expensive if the nodes are on secondary storage. However, to use this algorithm, we must be able to send one element to the parent and split the remaining 𝑈−2 elements into two legal nodes, without adding a new element. This requires 𝑈 = 2𝐿 rather than 𝑈 = 2𝐿−1, which accounts for why some textbooks impose this requirement in defining B-trees.
The same article defines 𝑈 and 𝐿:
Every internal node contains a maximum of 𝑈 children and a minimum of 𝐿 children.
For a comparison with the standard insertion algorithm, see also Will a B-tree with preemptive splitting always have the same height for any input order of keys?
You don't need parent pointers if all your operations start at the root.
I usually code the insert recursively, such that calling node.insert(key) either returns null or a new key to insert at its parent's level. The insert starts with root.insert(key), which finds the appropriate child and calls child.insert(key).
When a leaf node is reached the insert is performed, and non-null is returned if the leaf splits. The parent would then insert the new internal key and return non-null if it splits, etc. If root.insert(key) returns non-null, then it's time to make a new root
I have been wanting to write remove() method for my Binary Search Tree (which happens to be an array representation). But before writing it, I must consider all cases. Omitting all cases (since they are easy) except when the node has two children, in all the explanations I have read so far, most of the cases I see remove an element from an already balanced binary search tree. In the few cases where I have seen an element being removed from an unbalanced binary search tree, I find that they balance it through zigs and zags, and then remove the element.
Is there a way that I can possibly remove an element from an unbalanced binary search tree without having to balance it beforehand?
If not, would it be easier to write an AVL tree (in array representation)?
You don't need to balance it, but you do need to recursively go down the tree performing some swaps here and there so you actually end up with a valid BST.
Deletion of a node with 2 children in an (unbalanced) BST: (from Wikipedia)
Call the node to be deleted N. Do not delete N. Instead, choose either its in-order successor node or its in-order predecessor node, R. Copy the value of R to N, then recursively call delete on R until reaching one of the first two cases.
Deleting a node with two children from a binary search tree. First the rightmost node in the left subtree, the inorder predecessor 6, is identified. Its value is copied into the node being deleted. The inorder predecessor can then be easily deleted because it has at most one child. The same method works symmetrically using the inorder successor labelled 9.
Although, why do you want an unbalanced tree? All operations on it take on it take longer (or at least as long), and the additional overhead to balance doesn't change the asymptotic complexity of any operations. And, if you're using the array representation where the node at index i has children at indices 2i and 2i+1, it may end up fairly sparse, i.e. there will be quite a bit of wasted memory.
i am trying to make c++ program for binary search tree which will contain following functionality (actually this is a part of my college assignment):
A) CREATE Binary search tree.
B) Inorder, preorder, postorder traversals. ( non-recursive )
C) Search the Val in tree.
D) Breadth first traversal.
E) Depth first traversal
F) Count leaf nodes, non-leaf nodes.
G) Count no. of levels
my doubt is:-
1. usually a tree node have following structure:
class node{
private:
node *lChild;
int info;
node *rChild;
}
so in case i want to perform depth-first or breadth-first traversal can i change the node structure and add one more pointer pointing to the parent so that i can easily move backward in the hierarchy
class node{
private:
node *parent //pointer to parent node
node *lChild;
int info;
node *rChild;
}
is this considered as normal practice or bad form of programming a binary tree ? and if it is not considered as good way of programming a tree is there any other way or do i have to use the method given in books of using stack (for Depth First) and queue(for breadth first) to store nodes (visited or non-visited accordingly)
2. This is first time i am learning data structures so it will be a great help if someone can explain in simple words that what is the difference between recursive and non-recursive traversal with binary tree in consideration
i change the node structure and add one more pointer pointing to the parent [...] is this considered as normal practice or bad form of programming a binary tree ?
It is not a normal practice (but not quite "bad form"). Each node is a collection of data and two pointers. If you add a third pointer to each node, you will have increased the overhead of each node by 50% (two pointers to three pointers per node) which for a large binary tree will be quite a lot.
This is first time i am learning data structures so it will be a great help if someone can explain in simple words that what is the difference between recursive and non-recursive traversal
A recursive implementation is a function that only applies on a node, then calls itself for the subsequent nodes. This makes use of the application call-stack to process the nodes of the tree.
A non-recursive implementation uses a local stack to push non-processed nodes; then it loops as long as there is data on the stack and processes each entry.
Here's an example for printing to console, that shows difference between recursive and non-recursive ( the example is incomplete, as this is homework :] ):
void recursive_print(node* n) {
std::cout << n->info << "\n";
if(n->lChild)
recursive_print(n->lChild); // recursive call
// n->rChild is processed the same
}
void non_recursive_print(node* n) {
std::stack<node*> stack;
stack.push(n);
while(!stack.empty()) { // behaves (more or less) the same as
// the call-stack in the recursive call
node* x = stack.top();
stack.pop();
std::cout << x->info << "\n";
if(x->lChild)
stack.push(x->lChild); // non-recursive: push to the stack
// x->rChild is processed the same way
}
}
// client code:
node *root; // initialized elsewhere
if(root) {
recursive_print(root);
non_recursive_print(root);
}
You don't need a pointer to the parent node. Think about the cases when you would use it. The only way you can reach a node is through its parent, so you have already visited the parent.
Do you know what recursive means?
There's nothing to stop you adding a parent pointer if you want to. However, it's not usually necessary, and slightly increases the size and complexity.
The normal approach for traversing a tree is some kind of recursive function. You first call the function and pass in the root node of the tree. The function then calls itself, passing the child pointers (one at a time). This happens recursively all the way down the tree until there are no child nodes left.
The function does whatever processing you want on its own node after the recursive calls have returned. That means you're basically traversing down the tree with each call (making your call stack progressively deeper), and then doing the processing on the way back up as each function returns.
The function should never try to go back up the tree the same way it came down (i.e. passing in a parent pointer), otherwise you'll end up with an infinite recursion.
Typically you only need a parent pointer if you need to support iteration
Imagine that you have found a leaf node and then want to find the next node (lowest key greater than current key), for example:
mytree::iterator it1=mytree_local.find(7);
if (it1 != mytree_local.end())
{
mytree::iterator it2=it1.next(); // it1 is a leaf node and next() needs to go up
}
Since here you are starting at the bottom and not the top, you need to go up
But your assignment only requires operations that start at the root node, you shouldn't have a up pointer, follow the other answers for approaches that avoid the need to go up.
I would suggest you look into the Visitor pattern - for its flavor, not specifically for its structure (it's very complex).
Essentially, it is a design pattern that disconnects traversal of a tree in such a way that you have only one set of code that does tree traversal, and you use that set of code to execute various functionality on each node. The traversal code is generally not part of the Node class.
Specifically, it will allow you to not have to write the traversal code more than once - For example, utnapistims answer will force you to write traversal code for every piece of functionality you need; that example covers printing - to ouputXML() would require another copy of traversal code. Eventually, your Node class becomes a huge ungainly beast.
With Visitor, you would have your Tree and Node classes, a separate Traversal class, and numerous functional classes, such as PrintNode, NodeToXML, and possibly DeleteNode, to use with the Traversal class.
As for adding a Parent pointer, that would only be useful if you intended to park on a given node between calls to the Tree - i.e. you were going to do a relative search beginning on a pre-selected arbitrary node. This would probably mean that you had better not do any multi-threaded work with said tree. The Parent pointer will also be difficult to update as a red/black tree can easily insert a new node between the current node and its "parent".
I would suggest a BinaryTree class, with a method that instantiates a single Visitor class, and the visitor class accepts an implementation of a Traversal interface, which would be one of either Breadth, Width or Binary. Basically, when the Visitor is ready to move to the next node, it calls the Traversal interface implementation to get it (the next node).
When programming a simple binary search tree data structure (non self-balancing), the advice most resources give when deleting a node with two children is to copy the data out of one of the left child to the node that is being deleted. Is this bad practice? Wouldn't some sort of pointer manipulation provide faster results? Is there a BST rotation algorithm that can generalize this?
Yes, you don't want to copy the node, you just want to "move" it (i.e., change pointers around) to put it into the spot of the one you're deleting. If you're not trying to maintain balance, you don't really need to do any kind of rotation though -- you just pick the right-most node in the left sub-tree (or the left-most node in the right sub-tree). You delete that from its current place, and insert it into the place of the node you need to delete (all strictly by manipulating pointers).
Copying data has O(1) complexity vs. possible O(N) when manipulating pointers: the source node (the right-most node in the left sub-tree or the left-most node in the right sub-tree) may have one child and a sub-tree under it. Unlike a single node insertion, merging sub-trees would be required in this case. To avoid copying overhead, one should store pointers to objects rather than objects in BST.
I want to add Bi-Directional Iterator (like Iterator exported by std::set) in my Parametrized BinaryTree class but I'm unable to comeup with any algorithm.
Simply structure of Binary tree node is , it contains three pointers , left , right , parent:
With the given structure you want to proceed like this:
To start the iteration you would find the left-most node.
To go to the next node the operation depends on where you currently are:
If your node has a right child you go to this child and find its left-most successor (if there is no left child the node you are on is the next node).
If you nodes doesn't have a right child you move up the chain of parents until you find a parent for which you used the link to the left node: the next node becomes this node.
To move in the other direction you reverse the roles of left and right.
Effectively, this is implements a stack-less in-order traversal of the tree. If your tree isn't changed while iterating (an unlikely scenario) or you don't have a link to the parent node, you can maintain the stack explicitly in the iterator.
A good approach to this issue may be to first write your recursive pre-order algorithm, without using templates, and then you can from that create a templated version and implement the correct Iterators.
Just a thought.
You can't use recursion to implement an iterator in C++ because your iterator needs to return from all processing before it can return the result.
Only languages like C# and Python, that have a concept of yield can use recursion to create iterators.
Your iterator needs to maintain a stack of yet-to-be-visited nodes.
Of the top of my head, I think the algorithm is something like:
Keep going down and to the left
Every time you come across a right branch, add it to the stack
If at any point you can't go left, pop the first branch off the stack and begin visiting that in the same way.