So I got an assignment of creating a BST in Java and so far it has all went well. However I got a question about the remove method. As I have implemented, if I remove node X, all of node X's subtrees will also be deleted. And I just wondered if this is a common implementation, or should I rearrange the nodes if I delete one? I am also to make a AVL tree out of this class, so I will need a trinodeRestructering method. I guess This would need some modification aswell if I go in and deletenodes?
Thiis is how my remove method works:
private TreeNode remove(TreeNode currN, int dataToRemove) {
if (dataToRemove < currN.getData()) {
if (currN.getLeft() != null) {
if (currN.getLeft().getData() == dataToRemove) {
currN.setLeft(null);
} else {
remove(currN.getLeft(), dataToRemove);
}
}
} else if (dataToRemove > currN.getData()) {
if (currN.getRight() != null) {
if (currN.getRight().getData() == dataToRemove) {
currN.setRight(null);
} else {
remove(currN.getRight(), dataToRemove);
}
}
}
return currN;
}
//visual representation
/--------85
/--------25
/--------20
10
********************************************************************
*******removed 20******
10
*******************************************************************
Added tree for post:
/--------85
/--------25
\--------24
/--------20
| /--------13
\--------12
| \--------11
10(root)
Here is some swapping I tried, it looks like really crappy, hard to read code:
if (dataToRemove < currN.getData()) {
if (currN.getLeft() != null) {
if (currN.getLeft().getData() == dataToRemove) {
//Om inga barn, sätt noden till null.
if(currN.getLeft().getLeft() == null && currN.getLeft().getRight() == null){
currN.setLeft(null);
}//Om noden enbart har höger barn
else if(currN.getLeft().getLeft() == null){
TreeNode old = currN.getLeft().getRight();// Gamla höger
currN.setLeft(currN.getLeft().getLeft()); //
currN.getLeft().getRight().setRight((old)); //
}//Om noden enbart har vänster barn.
else if(currN.getLeft().getRight() == null){
TreeNode old = currN.getLeft().getRight();// Gamla vänster
currN.setLeft(currN.getLeft().getLeft()); //
currN.getLeft().getLeft().setRight((old)); //
}//om två barn
else{
TreeNode oldRight = currN.getLeft().getRight();// null
currN.setLeft(currN.getLeft().getLeft()); //sätt current left till 11
currN.getLeft().setRight((oldRight)); // current left, right till 13
}
} else {
remove(currN.getLeft(), dataToRemove);
}
}
yeah there is a known implementation for that , when you want to delete node in the binary search tree you swap it with the right most leaf of its left subtree, or the left most leaf of its right subtree then delete that leaf.
For the AVL you will have to keep track in you recursive operations of the balance condition , whenever that balance condition is violated you will need to do some kind of rotation depending on the structure of this violation , if you do some research you will find a decent amount of resources explaining the exact algorithms for this.
Related
The answer needs to be iterative, not recursive and the trees don't have to have the same structure, only the same numbers. I think I need to use a vertex traversal, but I am not sure how to implement that without using recursion.
This is what I had, but it doesn't pass the given tests. Also, I can't use any helper functions.
Node leftTree = t1;
Node rightTree = t2;
if(t1 == null && t2 == null)
return true;
else if (t1 != null && t2 == null)
return false;
else if (t1 == null && t2 != null)
return false;
else
{
if(leftTree.key == rightTree.key && problem1(leftTree.left, rightTree.left) == true
&& problem1(leftTree.right, rightTree.right) == true)
return true;
}
return false;
The recursion, where you compare left with left and right with right, will not work, because you can have the same keys but in a different topology. You need to visit the nodes in-order in the two trees in parallel.
One way of going through a tree without using recursion or extra memory is via a Morris traversal, where you temporarily put a tree in the rightmost position of its left subtree, and "return" from the recursion by following the right pointer there.
Here is an implementation in C, because I have one lying around. In Java it won't be that different. The rightmost_to() function returns the rightmost node in the left child of the current node, or the current node itself. You use it put the current node in the right child there, so when you get down to that point, going right emulates returning from the recursion.
void morris(stree *t)
{
struct node *curr = *t;
while (curr) {
if (!curr->left) {
printf("%d\n", curr->value);
curr = curr->right;
} else {
stree pred = *rightmost_to(&curr->left, curr);
assert(pred->right == 0 || pred->right == curr);
if (pred->right == 0) {
pred->right = curr;
curr = curr->left;
} else {
printf("%d\n", curr->value);
pred->right = 0;
curr = curr->right;
}
}
}
}
You will visit each node in order, without recursion, and without using extra memory. Whenever you recurse, you put the node you are in at the rightmost position, so you automatically come back to it. You can recognise that you are seeing the node for the second time because you find it when searching for the rightmost. Then you restore the tree instead of going left once more.
If you need to compare two trees, have two current nodes, and you should be fine. It does use an extra function, rightmost_to(), but it is a simple loop that you can easily embed without any issues. It is a line or two if you do that.
If you are allowed to put a parent pointer in the nodes, I think you can also traverse the trees without using extra memory doing something like this:
#define left_child(t) \
((t)->parent && (t)->parent->left == (t))
void parent_traverse(stree t)
{
enum { DOWN, UP } state = DOWN;
while (t) {
switch (state) {
case DOWN:
// Recurse as far left as we can...
while (t->left) { t = t->left; }
// Emit the leaf we find there
printf("(,%d,", t->value); // VISIT
// Then go right, if we can, or up if we can't.
if (t->right) { t = t->right; }
else { state = UP; }
break;
case UP:
if (!t->parent) return; // we have returned to the root...
if (left_child(t)) {
// Returning from a left child, we emit the parent
t = t->parent;
printf(",%d,", t->value); // VISIT
// Then we go right if we can't, or continue up
// (t is already the parent) if we cannot.
if (t->right) { t = t->right; state = DOWN; }
} else {
// Returning from a right child just means going up
t = t->parent;
}
break;
}
}
}
Sorry, it is C again, but just look at how t is updated to its left, right or parent node as we run through the tree. I cut that out of some code I have, and I might have copied it wrong, but you should get the idea. You can keep track of which direction you are moving, and essentially move along the "edge" of the tree, down left edges, under them and up, then down to the right, turn, and move up, and so on. If you have the state for both trees, you should be able to do that traversal in parallel in the two. Everwhere the code "visits" a node, you will compare the two nodes.
I don't know how useful this is, but it is at least a couple of ways that you can compare two trees with only constant extra memory usage and no recursion.
Of course, if it is a simple assignment and the time complexity doesn't matter, run through one tree and look up in the other in O(n log n) (balanced) or O(n^2). :)
As of right now, I'm trying to get a intuitive understanding of recursion by also working on using the Stack object in Java. On GeeksForGeeks, they have practice problems on traversal methods on a binary tree. Currently I'm on PreOrder and while I've figured out the recursive solution, the iterative solution is proving to be quite troublesome to come up with. When I pulled up the actual answer to the problem, I found that my code is practically identical to the solution code. I've been going back and forth for a while trying to figure out why my Iterative solution for a PreOrder traversal is incorrect compared to the actual solution but thought that maybe I need a third set of more experienced eyes to tell me why I'm wrong.
Here's the url to the problem and the online compiler: https://practice.geeksforgeeks.org/problems/preorder-traversal/1
Here's my code:
void preorder(Node root)
{
// Your code goes here
if(root == null) return;
Stack<Node> stack = new Stack<Node>();
stack.push(root);
while(!stack.isEmpty()) {
Node cur = stack.pop();
System.out.print(cur.data + " ");
if(cur.left != null) {
stack.push(cur.left);
}
if(cur.right != null) {
stack.push(cur.right);
}
}
}
Here's the solution code:
void preorder(Node root) {
// Base Case
if (root == null) {
return;
}
// Create an empty stack and push root to it
Stack<Node> nodeStack = new Stack<Node>();
nodeStack.push(root);
/* Pop all items one by one. Do following for every popped item
a) print it
b) push its right child
c) push its left child
Note that right child is pushed first so that left is processed first
*/
while (nodeStack.empty() == false) {
// Pop the top item from stack and print it
Node mynode = nodeStack.peek();
System.out.print(mynode.data + " ");
nodeStack.pop();
// Push right and left children of the popped node to stack
if (mynode.right != null) {
nodeStack.push(mynode.right);
}
if (mynode.left != null) {
nodeStack.push(mynode.left);
}
}
}
Preorder traversal for a binary tree is Visit,Left and Right.
Your code is not similar to solution's code.
You need to push right child first to the stack and then the left child to bring left child on top of the stack and then visit that child. Hence, modify your code as shown below-
void preorder(Node root)
{
// Your code goes here
if(root == null) return;
Stack<Node> stack = new Stack<Node>();
stack.push(root);
while(!stack.isEmpty()) {
Node cur = stack.pop();
System.out.print(cur.data + " ");
if(cur.right != null) {
stack.push(cur.right);
}
if(cur.left != null) {
stack.push(cur.left);
}
}
}
I am checking if a tree is a binary search tree. I see what the known solution is. Prior to me looking it up, I came up with the following attempt based off of post order traversal. I have traced it by hand, and seems to make sense. But, it is incorrect. Can anyone help me understand why?
class Node {
int data;
Node left;
Node right;
}
boolean checkBST(Node root) {
// Empty tree
if (root == null) {
return true;
}
// Sub trees are BST
boolean valid = checkBST(root.left) && checkBST(root.right);
// Greater than left
if (root.left != null) {
valid = valid && root.data > root.left.data;
}
// Less than right
if (root.right != null) {
valid = valid && root.data < root.right.data;
}
return valid;
}
Your code will fail for this basic test case,as it returns true for following:
50
/
3
/ \
1 100
The problem is your code is only comparing the node with its immediate children and not with the entire subtree. It return true for subtree rooted at 3 and
because 3 < 50, your code finally returns true, which is wrong.
I know this is pretty straight forward code but wondering how exactly the internal working is.
public static int getHeight(TreeNode root) {
if (root == null) {
return 0;
}
System.out.print(getHeight(root.left) +"\t");
return Math.max(getHeight(root.left), getHeight(root.right)) + 1;
}
For my understanding, I added print statement but it results the following.
printing root.left() prints this: 0 0 0 1 0 0 0
printing root.right() prints this: 0 0 2 0 0 3 0 0 2 0 0 0 1 0
Following is the Tree created in the main program:
TreeNode parent = new TreeNode(10);
parent.insertInOrder(2);
parent.insertInOrder(13);
parent.insertInOrder(5);
parent.insertInOrder(6);
parent.insertInOrder(15);
parent.insertInOrder(6);
How is this printing the above result and how is it working. If anyone can explain me with the above example, it would really help me.
I know how traversals work and how to print the tree but I really want to understand the above output. If anyone can help then it would be great.
void setLeftChild(TreeNode left)
{
this.left = left;
if(left == null)
{
left.parent = this;
}
}
void setRightChild(TreeNode right)
{
this.right = right;
if(right == null)
{
right.parent = this;
}
}
void insertInOrder(int d)
{
if(d <= data)
{
if(left == null)
{
setLeftChild(new TreeNode(d));
}
else
{
left.insertInOrder(d);
}
}
else{
if(right == null)
{
setRightChild(new TreeNode(d));
}
else{
right.insertInOrder(d);
}
}
size++;
}
You should create a function that outputs information about the tree. For example, this function does a preorder traversal, showing information about each node:
public static void ShowTree(TreeNode root, TreeNode parent, depth)
{
if (root == null) return;
// output 'depth' spaces.
// The indentation will help show the structure of the tree.
// output node value, and parent (if parent not null)
// Traverse the left node
ShowTree(root.left, root, depth+1);
// Traverse the right node
ShowTree(root.right, root, depth+1);
}
Call that function with ShowTree(tree, null, 0). The resulting output will show the structure of the tree, and you can determine if the tree is balanced. It's a useful thing to have when you're developing tree code because you can do an insert, for example, then call ShowTree to see if the insert worked as expected.
Update
The code's output is a little strange because your print statement results in a recursive call. So every node below the current node ends up getting printed multiple times.
I think you want to do this:
int leftHeight = getHeight(root.left);
int rightHeight = getHeight(root.right);
// now output output leftHeight or rightHeight, or both
return Math.max(leftHeight, rightHeight) + 1;
That way you won't get the multiple recursive calls that produce the strange output.
More info
The reason you're seeing those extra recursive calls is because you're calling getHeight(root.left) twice. Let's say your tree looks like this:
root
/
child
/
grandchild
So you call getHeight(root). Then:
getHeight(child) is called in your print statement
getHeight(grandchild) is called in your print statement
getHeight(null) is called in your print statement
getHeight(grandchild) prints 0
getHeight(null) is called twice (once for the left node and once for the right node) in the return statement
getHeight(grandchild) returns 1
getHeight(child) prints 1
getHeight(grandchild) is called in the return statement
getHeight(null) is called in your print statement
getHeight(grandchild) prints 0
getHeight(grandchild) returns 1
getHeight(null) (the right node) is called in the return statement
...
You see where the problem is? getHeight(grandchild) is called again! Every time your print statement calls getHeight, it has to walk every descendant node. So the height of every node is output multiple times. The deeper the node is in the tree, the more often it will be output.
The change I suggested in my update above prevents that by ensuring that no node is visited more than once.
I tried to answer the following 2 question, they are from a Java course test, but it is a little confusing because of the recursive that I'm probably need to use.
The first one is a method that receive a root of a binary tree and returns the maximum value on tree. (example in figure A).
This question (and the second) says only complete in the missing lines:
public static int maxInTree (Node root)
{
if (root == null)
return 0;
if ((root.getLeftSon() == null) && (root.getRightSon() == null))
______________________ // I think that here: *return 1*;
if (root.getLeftSon() == null)
return _________________
if (___________ == null) // I think that here: *root.getRightSon()*
_______________________________-
return max______________________________
}
The second question says: do the same as the first question BUT for a sorted binary search tree.
public static int maxInSearchTree (Node r)
{
if (r == null)
return 0;
if (r.getRightSon() == null)
__________________________
return _______________________________
}
You can assume there is a method to pullout the father: getNumber().
thnx !!
I assume that getNumber() gives the value (not the father).
public static int maxInTree (Node root)
{
if (root == null)
return 0;
if ((root.getLeftSon() == null) && (root.getRightSon() == null))
return root.getNumber();
if (root.getLeftSon() == null)
return max(root.getNumber(), maxInTree(root.getRightSon()));
if (root.getRightSon() == null)
return max(root.getNumber(), maxInTree(root.getLeftSon()));
return max(root.getNumber(),
max(maxInTree(root.getLeftSon()),maxInTree(root.getRightSon())));
}
public static int maxInSearchTree (Node r)
{
if (r == null)
return 0;
if (r.getRightSon() == null)
return r.getNumber();
return maxInSearchTree(r.getRightSon());
}
You should think about the layout of the tree as well as the result that is desired.
Some hints:
if there is no root, return whatever is appropriate
if there is no child, return the current node's (root of a subtree) value
if there is a child, recurse into it
if the tree is sorted, the right child's value should always be greater than the node's and the left child's
if the tree is not sorted, you need to compare each node's value and remember the highest one (max(...))
Not a full answer, since Thomas covered a lot of what I would have said already. However, a few additional hints:
The left and right child nodes of your root node are themselves the root nodes of the left and right sub-trees. With that considered, to get the maximum value of your left and right sub-trees, you need to call your recursive maxInTree(Node node) method with the left or right child as your argument.
If your unordered tree only has a left OR right sub-tree, then the maximum value is the greater of the root nodes value and the maximum value in the left or right sub-tree.