Time Complexity of printing BST using inorder successor method - java

I have a method for finding the next inorder successor within a Binary Search Tree (BST). The "inorderSuccessor" method takes any node of the BST as input and output the next inorder successor. The method and tree class are defined as follow:
class BSTInorderSuccessor{
public static Node inorderSuccessor(Node node) {
if (node.right != null) {
return minValue(node.right);
}
Node parent = node.parent;
while (parent != null && node == parent.right){
node = parent;
parent = parent.parent;
}
return parent;
}
}
class TreeNode{
int data;
Node left;
Node right;
Node parent;
public TreeNode(int data){
this.data = data;
this.left = null;
this.right = null;
this.parent = null;
}
}
Suppose the height of the BST is h, and there are n nodes within this tree structure. I know that the time complexity of "inorderSuccessor" method is O(h).
My question is: Given the smallest node of the BST. When I write a method to continuously call "inorderSuccessor" to print all the nodes of the BST, what is the total time complexity? I think it is O(n * h). Is that correct?

You can upper-bound the cost of printing everything out by always finding the inorder successor at O(nh), but that's actually not a tight bound. You can show that the runtime is actually Θ(n), independently of the height of the tree!
One way to see this is to look at how many times each edge in the tree gets visited. If you trace out the execution of all those inorder traversals, you'll find that you go down each edge exactly once and go up each edge exactly once, and the total work done is proportional to the number of times each edge is visited. The number of edges in an n-node tree is Θ(n), hence the runtime bound.
Note that you can't say that each individual operation will take time O(1). That's not true. What you can say is that in aggregate each one takes an average of O(1) time.

Related

How do I find a certain node of a binary tree, using recursion?

How do I write the code to find a certain node. Specifically how do I say a node was visited after I check it?
public Iterator<T> pathToRoot(T targetElement, BinaryTreeNode<T> current)
throws ElementNotFoundException
{
Stack<BinaryTreeNode<T>> myStack = new Stack<>();
if (current == null)
return null;
if (current.element.equals(targetElement)) //found it
{
myStack.push(current); //adds the current element to the stack
}
// mark as visited
//mark node also as found
// return the found element
if (current.hasLeftChild() || current.hasRightChild()) //if the current node has a left or right child
{
// mark node as visited
}
if (current.hasLeftChild())//if the current node has a left child node
pathToRoot(targetElement, current.getLeft()); // check the left child node
if (current.hasRightChild())//same thing as above but for the right
pathToRoot(targetElement, current.getRight());
if(current != targetElement && /*node has been visited*/)
myStack.pop(); // pop node from the stack
return myStack.toString(); //return string of path to root
}
/using a dfs search to find a node/
The sole purpose of marking a graph node as visited is to make sure you won't get into an infinite loop, because a graph can contain a cycle.
A binary tree is a special kind of a graph, that doesn't contain cycles, therefore there's no need to mark nodes as visited when you're doing traversal.
Also, usually binary trees are ordered in a way that the current node contains value X, its left sub-tree has nodes that have values less than X, and its right sub-tree has nodes that have values greater than X. This allows having searches that take logarithmic time, in your demonstrated code you don't seem to utilize that.
So, I think you don't have a good understanding of how binary trees work and you should research a little more, before implementing this functionality.

Remove recursively from a binary search tree

This is homework; please don't just give me code
I have two methods: remove(T data) and removeRec(Node<T> node, T data).
In its current state, it seems my code only removes the root node of the BST.
#Override
public T remove(T data) {
if (data == null) {
throw new IllegalArgumentException("Data is null");
}
if (root == null) {
throw new java.util.NoSuchElementException("BST is empty");
} else {
size--;
BSTNode<T> dummy = new BSTNode<T>(null);
return removeRec(root, data, dummy).getData(); //This is probably wrong too
}
}
/**
* Helper method to recursively search for, and remove the BSTNode with
* the given data in it
* #param node is the node we're currently at
* #param data is the data we're looking for
* #param temp I have no idea why
* #return node that was removed
*/
private BSTNode<T> removeRec(BSTNode<T> node, T data, BSTNode<T> temp) {
if (compare(data, node.getData()) < 0) {
temp.setLeft(removeRec(node.getLeft(), data, temp));
} else if (compare(data, node.getData()) > 0) {
temp.setRight(removeRec(node.getRight(), data, temp));
} else if (node.getLeft() != null && node.getRight() != null) {
temp.setData(findMin(node.getRight()).getData());
temp.setRight(removeRec(node.getRight(), data, temp));
} else {
if (node.getLeft() != null) {
temp = node.getLeft();
} else {
temp = node.getRight();
}
}
return temp;
}
private int compare(T a, T b) {
return a.compareTo(b);
}
My instructor has told me (as a hint) that I should see what passing in a third argument into the method, in this case, BSTNode<T> temp. I don't understand how that helps though, or how to utilize it. I don't see how using a third argument helps; and I can't find anything online as to why you'd do this either.
There are three main possibilities when you try to remove data from your Binary Search Tree:
data is less than the current node value: Call remove on the left subtree or throw a NoSuchElementException if it is null.
data is greater than the current node value: Call remove on the right subtree or throw a NoSuchElementException if it is null.
data is equal to the current node value.
1 and 2 are pretty straightforward, but 3 has four more cases to consider:
3.1. current node is a leaf: Both left and right subtrees are null. Just replace the reference to the current node in its parent by null.
3.2. current node has only the left child: You need to make the parent of the current node point to the left subtree, thus removing the current point. To do this, you can implement a function that will check if the current point was on the left or right subtree of the parent and replace it accordingly. Calling it would look like this:
replaceNodeInParent(node, node.getLeft(), parent);
3.3. current node has only the right child: Similar to 3.4, but using getRight() instead of getLeft().
3.4. current node has both the left and right children: You should maintain the property of the BST that all nodes on the left are less than the current node and all nodes on the right are greater than the current node. To do so, you should find the smallest value on the right, copy it to the current node, and delete it from the right subtree. Something like this:
BSTNode<T> successor = findMin(node.getRight());
node.setData(successor.getData());
removeRec(node.getRight(), successor.getData(), node);
It looks like your BSTNode doesn't hold a reference to the parent node. If so, I believe that's what the third argument for removeRec should be. You will need a reference to the parent every time you replace the current node, so you can set the parent left or right subtree as needed.
For further reading, you can check this article on Binary Search Trees from Wikipedia.

Traversing a Binary Tree Recursively

I am hopelessly lost when it comes to recursive functions. I am required to create a recursive function to traverse a binary tree and insert a new node in between specific values. Would i need to recopy my traverse function and modify it in every other function that i use it in? Would someone please evaluate the traverse function?
I think my traversing code is alright.
Node traverse (Node currentNode){
if (!currentNode.left.equals(null)){
traverse (currentNode.left);
return currentNode.left;
}
if (!currentNode.right.equals(null)){
traverse (currentNode.right);
return currentNode.right;
}
return currentNode;
}
When it comes to binary trees, there are several different types of traversals that can be done recursively. They're written in the order they're referenced then visited (L=Left child, V = visit that node, R = right child).
In-order traversal (LVR)
Reverse order traversal (RVL)
Preorder traversal (VLR)
Postorder traversal (LRV)
Your code appears to be performing the postorder traversal method, but you're getting a few things mixed up. First, the node is what you want to traverse; the data is what you want to visit. Second, you have no reason to return the node itself, in the way that this is implemented. Your code doesn't allow for a condition to say, 'I'm looking for this particular data, do you have it Mr. Node#0xdeadbeef?', which would be found with some sort of extra search parameter.
An academic BST traversal only prints the nodes itself. If you wanted to add a search functionality, it's only one more parameter, as well as an additional check for the right node.
Here's a snippet:
// Academic
public void traverse (Node root){ // Each child of a tree is a root of its subtree.
if (root.left != null){
traverse (root.left);
}
System.out.println(root.data);
if (root.right != null){
traverse (root.right);
}
}
// Search with a valid node returned, assuming int
public Node traverse (Node root, int data){ // What data are you looking for again?
if(root.data == data) {
return root;
}
if (root.left != null && data < root.data) {
return traverse (root.left, data);
}
if (root.right != null && data > root.data) {
return traverse (root.right, data);
}
return null;
}
It seems like you are traversing in the preorder methodology, but i am a little skeptical as to what exactly you wish to accomplish without actually comparing your current node with some base value that defines u have reached ur destination. I would suggest drawing out a simple tree and visualizing the steps. Then try to put that into code.
A recursive function returns the value of itself with a modified parameter, or a termination (exit) condition. eg, Factorial:
int factorial( int param ) {
if ( param > 1 ) {
return param * factorial( param -1 );
} else {
return 1;
}
}
In your code, you call a 'traverse' but then do nothing with the result...
When your recursive function ends, your final return will be first left child if it exists, else the first right child if it exists, else the root node.
Please give more detail as to why you need to traverse the tree (also, not sure what you meant by "copy the function and modify it in every other function", the whole idea of a function is to code-once-call-many)

Edit the nodes in a binary tree in Java

Okay. I have a binary tree, and this is what I want to do with it:
For each node in original tree:
If it's not a leaf, replace it with a leaf node.
Do a calculation on the original tree updated with the removed branch.
Revert the node back to how it was (so now the tree is the same as at the beginning).
The problem is this: I am traversing the tree using a stack. If I change the stack.pop() node to a leaf, this does NOT remove any branches in the original tree. It's the same reasoning behind why you can do:
int x=1
int y=x
y++
And x still equals 1. There's a technical term for this but I forgot it.
So how can I edit the nodes in an original tree and still traverse it?
This is basically what I'm doing to traverse the tree right now:
public void iterativePreorder(Node root) {
Stack nodes = new Stack();
nodes.push(root);
Node currentNode;
while (!nodes.isEmpty()) {
currentNode = nodes.pop();
Node right = currentNode.right();
if (right != null) {
nodes.push(right);
}
Node left = currentNode.left();
if (left != null) {
nodes.push(left);
}
//This is where you do operations on the currentNode
}
}
From what I can tell from your question, for every Node you want to calculate something about the tree as if that node was a leaf.
To do this there is no reason to actually make that node a leaf and then reattach it. Instead, your logic can simply remember which node to treat as a leaf for each computation.
Traverse the tree, and for each Node, let's call it outerCurrentNode, once again traverse the tree doing your calculation - but now for each Node, let's call it innerCurrentNode, test to see if outerCurrentNode == innerCurrentNode. If the test returns true, treat that innerCurrentNode as if it's a leaf, ignoring its children.
EDIT: Here's a mock up of what I'm suggesting (untested):
//entry point - called from directing code
public void iterativePreorder(Node root) {
iterativePreorderKernel(root, root);
}
//recursive method - keeps track of root in addition to current Node
private void iterativePreorderKernel(Node root, Node current) {
if (current.left() != null) {
iterativePreorderKernel(root, current.left());
}
if (current.right() != null) {
iterativePreorderKernel(root, current.right());
}
//for each Node in the tree, do calculations on the entire tree, pretending
//the current Node is a leaf
doCalculation(root, current);
}
//calculation method (also recursive) - takes a current Node, plus
//the Node to treat as a leaf
public void doCalculation(Node innerCurrent, Node pretendLeaf) {
//do calculation with inner current node
if (innerCurrent != pretendLeaf) {
if (innerCurrent.left() != null) {
doCalculation(innerCurrent.left(), pretendLeaf);
}
if (innerCurrent.right() != null) {
doCalculation(innerCurrent.right(), pretendLeaf);
}
}
}
I'm using recursion instead of a Stack, but either will work. iterativePreorder() does a traversal, calling doCalculation() for each Node, passing it in along with the root (to keep track of the entire tree). That method then does its own traversal, doing your calculation, but stopping short when it reaches the specially marked Node.

java alogrithm: find pre/next leaf node that meet special condition from any node in a tree

I need to write a function to find previous/next leaf node that meet special condition from any node in a singly rooted tree. (in the parent first order)
The API would be something like this:
Node findNextLeafNode(Node currentNode, Condition condition);
Node findPretLeafNode(Node currentNode, Condition condition);
where currentNode is any node in a tree, and Node is defined as:
interface Node{
/** #return the Node's parent or null if Node is root */
Node getParent();
/** #return true if node is root */
boolean isRoot();
/** #return non-null array of child nodes (zero length for leaf nodes) */
Node[] getChildren();
/** #return the number of child nodes. If node is leaf, value is 0 */
int getChildCount();
}
And the Condition interface defines the semantics of checking a constraint against a given Node.
interface Condition{
/** #return true if provided node meets the condition */
boolean check(Node node);
}
My question:
Is there an existing library or algorithm for such a common scenario? I am open to either stack based or recursive algorithms. Pseudocode, links to open source libraries, or if you care to share you own code, would be appreciated.
(If not, I need to spend time to invent the same wheel again and paste it here later for sharing.)
Thanks.
-----------------------------write a method to getNext()........
// currentNode must be descendant of root
public static Node getNextNode(Node currentNode, Node root)
{
// 1. if is has child, next is its first child
if (currentNode.getChildSize() > 0) {
return currentNode.getChildren()[0];
}
// 2. if it has no child, check if its is the last child of his parent
else {
// if it is root and has no children, return null
if (currentNode == root) {
return null;
}
// else should have parent which is or under root;
Node parent = currentNode.getParent();
int index = getIndex(currentNode);
if (!isLastofParent(currentNode)) {
// ----a. if not last, next is his parent's next
return currentNode.getParent().getChildren()[index + 1];
}
else {
// ----b. if it is the last one, return its parent's next right if there is. while until root
Node tmp = parent;
while (tmp != root) {
int parentIndex = getIndex(tmp);
if (!isLastofParent(tmp)) {
return tmp.getParent().getChildren()[parentIndex + 1];
}
tmp = tmp.getParent();
}
}
}
return null;
}
private static boolean isLastofParent(Node node)
{
if (getIndex(node) == node.getParent().getChildSize() - 1) {
return true;
}
return false;
}
private static int getIndex(Node currentNode)
{
Node parent = currentNode.getParent();
for (int i = 0; i < parent.getChildSize(); i++) {
if (parent.getChildren()[i] == currentNode) {
return i;
}
}
//TODO: error condition handling, will not happen if tree not change
return -1;
}
------------------------a full search is much easier............
public static Node getNextFailNode(Node currentNode, Node root, Condition condition)
{
boolean foundCurrentNode = false;
Stack<Node> stack = new Stack<Node>();
stack.push(root);
while (!stack.isEmpty()) {
Node tmp = stack.pop();
System.out.println("-popup---------" +tmp+ " ");
if (foundCurrentNode && checkCondition(tmp, condition)) {
return tmp;
}
if (tmp == currentNode) {
foundCurrentNode = true;
}
if (tmp.getChildSize() > 0) {
for (int i = tmp.getChildSize() - 1; i >= 0; i--) {
stack.push(tmp.getChildren()[i]);
}
}
}
return null;
}
This maybe way overblown for what you need, but it can support what you want:
There is a graph traversal language: Gremlin. Typically bolted on top of something like Neo4j, but any graph data structure (e.g. a singly rooted directed tree) can be wrapped to support the API. Take a look at Blueprints projects to find out how it is done.
[edit: for something less heavy]
Perhaps JGraphT is what you want. Also take a look at this question on SO. It is not an exact duplicate, but you should find it helpful.
Write an iterator for your tree that can be initialized from any node and uses pre/in/post-order traversal (Of course it should be bi-directional).
This is basically writing one simple algorithm that at least to me seem basic.
Once you have an iterator all you need is to iterate your way to the next node which is a leaf and the condition holds for it.
If you have trouble with any specific part just ask and I'll improve my answer.
Based on the fact that you already have defined your interfaces, and you say the graph-traversal libraries are too heavyweight, you probably should just write it yourself. It would be an absolutely trivial amount of code. (This page contains some code if you need help.)
(One suggestion for your API: don't put a boolean isRoot(); method on Node, that's a waste of bits unless you have a very good reason to do so. The code that builds the tree should just refer to the root node.)

Categories