I am trying to write binary search insert method but it gives the wrong answer. I couldn't find what is the reason. Here's my code:
public static Node insert(Node root,int data) {
Node insertedNode = new Node(data);
if(root == null){
root=insertedNode;
}
else {
Node node = root;
Node insertedNode = new Node(data);
while(root.left !=null && root.right !=null){
if(root.left.data>data){
root=root.left;
}
else {
root=root.right;
}
}
if (data > root.data) {
root.left = insertedNode;
}
else {
root.right=insertedNode;
}
}
}
The problem is very easy to detect. Look at your while:
while(root.left !=null && root.right !=null){
if(root.left.data>data){
root=root.left;
}
else {
root=root.right;
}
}
It will only seek to deeper levels if both left and right of root exists. So, let's suppose you try to add 2, 3, 4. You insert 2, which will become your root. Then, you try to add 3. Your while detects that it's not true that both of left and right of root are not null. So, it will add 3 to the right. So far, so good:
2
\
3
Now, you try to add 4. Your while checks whether root.left and root.right are not null. It's false, so it will be the right of the root, resulting in
2
\
4
instead of
2
\
3
\
4
Let's fix your while:
while((root != null) && (((root.data < data) && (root.left != null)) || ((root.data > data) && (root.right != null)))){
if(root.left.data>data){
root=root.left;
}
else {
root=root.right;
}
}
Related
This removes almost all of what is supposed to, except for the last item.
This is what I get back when I submit it:
Input: [thing, word, stuff, and, both, zoo, yes]
----------Expected size: 0 BST actual number of nodes: 1
Invalid tree after removing thing
Code Below:
#SuppressWarnings("unchecked")
public boolean remove(Object o) {
Node n = root;
while (n != null) {
int comp = n.value.compareTo(o);
if (comp == 0) {
size--;
remove(n);
return true;
} else if (comp > 0) {
n = n.left;
} else {
n = n.right;
}
}
return false;
}
private void remove(Node root) {
if (root.left == null && root.right == null) {
if (root.parent == null) {
root = null;
} else {
if (root.parent.left == root) {
root.parent.left = null;
} else {
root.parent.right = null;
}
}
} else if (root.left == null || root.right == null) {
Node child = root.left;
if (root.left == null) {
child = root.right;
}
if (root.parent == null) {
root = child;
} else if (root.parent.left == root) {
root.parent.left = child;
} else {
root.parent.right = child;
}
child.parent = root.parent;
} else {
Node successor = root.right;
if (successor.left == null) {
root.value = successor.value;
root.right = successor.right;
if (successor.right != null) {
successor.right.parent = root;
}
} else {
while (successor.left != null) {
successor = successor.left;
}
root.value = successor.value;
successor.parent.left = successor.right;
if (successor.right != null) {
successor.right.parent = successor.parent;
}
}
}
}
Removal of a node in a Binary-search-tree consists of the following steps:
Find the node
You need to make sure that you have a function which is used for searching in order to find the node to be removed.
Handle the node's subtree
If the node has less than two children, then the subtree can be trivially changed. If there is a child, then the current node will be replaced by its child. Otherwise, if there are two children of the node to be removed, then you will just need to replace the node to be removed with the rightmost node of the left subtree or the leftmost node of the right subtree of the element to be removed.
Ensure that if you have replaced your current node with something else, then the other node will not exist as a duplicate.
In order to achieve this you will need methods like:
- search
- find leftmost/rightmost node of subtree
- remove
Your current code is over-complicated. I would rewrite it using atomic methods.
To print a binary tree path with a leaf node value. When it backtracks, it should remove the '3' from the stack. How to modify the code to achieve? I can't find a place to pop the value from the stack.
// should print out "5 8 10", but it prints "5 3 8 10"
printPathWithStack(root, 5);
10
/ \
8 2
/ \ /
3 5 4
void printPathWithStack(Node root, int key)
{
Stack<Node> path = new Stack<Node>();
printPathWithStackHelper(root, key, path);
}
void printPathWithStackHelper(Node root, int key, Stack<Node> path)
{
if (root == null) {
return;
}
path.push(root);
if (root.data == key && root.left == null && root.right == null) {
while (!path.isEmpty()) {
System.out.print(path.pop().data + " ");
}
} else if (root.left == null && root.right == null){
path.pop();
}
printPathWithStackHelper(root.left, key, path);
printPathWithStackHelper(root.right, key, path);
}
Well, it's a bit strange to use the stack this way.
But for what it's worth, when backtracking you should simply discard all items where item.left or item.right is not equal the last retrieved item. This will give you the path to the root.
You can defer pushing into Stack until making recursive calls to left and right child.
if (root.data == key && root.left == null && root.right == null)
{
path.push(root);
while (!path.isEmpty())
{
System.out.print(path.pop().data + " ");
}
return;
}
else if (root.left == null && root.right == null)
{
return;
}
path.push(root);
printPathWithStackHelper(root.left, key, path);
printPathWithStackHelper(root.right, key, path);
Hope it addresses your problem!
P.S. Not tested the code fragment for general cases, hope you will do the required :)
I'm confused on why my removal method of leaves in a BST is not working. If I assign 0 to the data, its reflected in the tree, but when I assign null to the node, it's still able to be referenced in the BST traversal.
public void removeLeaves(){
removeLeaves(getRoot());
}
private void removeLeaves(IntTreeNode node) {
if (node == null)
return;
else if( node.left == null && node.right == null){
node.data = 0; //im finding the leave nodes correctly
node = null; //but its not removing them
}
else {
removeLeaves(node.left);
removeLeaves(node.right);
}
}
overallRoot
____[7]____
/ \
[3] [9]
/ \ / \
[0] [0] [0] [8]
\
[0]
Could somebody explain why this is not working as intended?
In your example tree , consider 9
9.left => null
9.right => address of 8
when you assign node.data = 0; , node has address of 8 so 0 will be reflected in the tree.
But when you do node =null, you are just changing the variable node. you are not doing any operation on address of 8.
I think what you are hoping to happen is by doing node = null is:
address of 8 = null
which is actually not possible, because you are just changing the variable node.
Say address of 8 is 0XABCD, so node = 0XABCD.
when you do node.data=0 as node has address 0XABCD, 0XABCD.data will be changed to 0. but when you do node = null, you are just assigning a new value to a variable node, you are not doing any operation on the original address 0XABCD.
What you actually have to do is
if(node.left!= null && node.left.left == null && node.left.right ==null)
node.left =null
if(node.right!= null && node.right.left == null && node.right.right ==null)
node.right =null
UPDATE
What you are trying to do is something like this:
Foo foo = new Foo();
Foo anotherFoo = foo;
anotherFoo.value = something; // both foo.value and anotherFoo.value will be changed to "something", because of the reference.
anotherFoo = null;
// here you are expecting foo also to be null which is not correct.
public void removeLeaves () {
if (getRoot() != null)
removeLeaves (getRoot());
}
private IntTreeNode removeLeaves (IntTreeNode node) {
if (getRoot().left == null && getRoot().right == null) {
setRoot(null);
} else {
if (node.left != null) {
if (node.left.left == null && node.left.right == null)
node.left = null;
else
removeLeaves(node.left);
}
if (node.right != null) {
if (node.right.right == null && node.right.left == null)
node.right = null;
else
removeLeaves(node.right);
}
}
return node;
}
This method is supposed to remove all leaves from a binary (no left and right branches) tree, but for some reason, it only removes one instance of a leaf from the binary tree. Why is that? I though the base case is responsible for severing the ties the parent node by setting parent.left or parent.right to null. If it isn't a leaf, it would recursively call until it hits a leaf.
Here is what I have so far:
private IntTreeNode overallRoot; // Beginning of the chain of nodes
// post: Removes All leaves from a tree
public void removeLeaves() {
if (overallRoot == null) { // If empty tree
return;
} else {
removeLeaves(overallRoot);
}
}
// helper for removeLeaves
private void removeLeaves(IntTreeNode root) {
if (root.left != null) { // tests left root
if (root.left.left == null && root.left.right == null) { // if next left node is leaf (base case)
root.left = null; // delete
} else if (root.left.left != null && root.left.right == null) { // If next right is empty
removeLeaves(root.left.left); // only check second left
} else if (root.left.right != null && root.left.left == null) { // If next left is empty
removeLeaves(root.left.right);
} else if (root.left.left != null && root.left.right != null) { // If next left/right isn't empty
removeLeaves(root.left.left);
removeLeaves(root.left.right);
}
}
if (root.right != null) {
if (root.right.left == null && root.right.right == null) { // if next left node is leaf (base case)
root.right = null; // delete
} else if (root.right.left != null && root.right.right == null) { // If next right is empty
removeLeaves(root.right.left); // only check second left
} else if (root.right.right != null && root.right.left == null) { // If next left is empty
removeLeaves(root.right.right);
} else if (root.right.left != null && root.right.right != null) { // If next left/right isn't empty
removeLeaves(root.right.left);
removeLeaves(root.right.right);
}
}
}
Here is the individual node class:
public class IntTreeNode {
public int data;
public IntTreeNode left;
public IntTreeNode right;
// constructs a leaf node with given data
public IntTreeNode(int data) {
this(data, null, null);
}
// constructs a branch node with given data, left subtree,
// right subtree
public IntTreeNode(int data, IntTreeNode left, IntTreeNode right) {
this.data = data;
this.left = left;
this.right = right;
}
}
Structural modification on trees is often cleaner when approached in a bottom-up manner:
public IntTreeNode removeLeaves(IntTreeNode root) {
if (root == null || root.isLeaf()) {
return null;
}
root.left = removeLeaves(root.left);
root.right = removeLeaves(root.right);
return root;
}
If in your recursive calls, instead of doing
removeLeaves(root.left.left);
you do
removeLeaves(root.left);
it should work. As Wallace points out in the comment, it looks like your're getting down two levels at a time. Also, the code could be reduced in the following way (the equivalent for the right tree)
if (root.left != null) { // tests left root
if (root.left.left == null && root.left.right == null) {
root.left = null; // delete
} else {
removeLeaves(root.left);
}
}
Take into account also that this do not solve the problem of a root being itself a leave!
It looks like you're looking too far ahead in each pass through the recursion. If the left has leaves, call removeLeaves(root.left). Do the same with the right. Then set left and right to null as needed.
I think this would do it:
public void removeLeaves(IntTreeNode root) {
if (root != null) {
removeLeaves(root.left);
removeLeaves(root.right);
root.left = null;
root.right = null;
}}
This will search the tree depth first and then remove the leaf nodes as encountered.
public class RemoveLeafNode {
public static void removeLeaves(Node root){
if(root!=null){
removeL(root.leftChild);
removeL(root.rightChild);
}
}
private static void removeL(Node node){
if(node==null){
return;
}
if(node.leftChild == null && node.rightChild == null){
node=null;//delete leaf
}
removeL(node.leftChild);
removeL(node.rightChild);
}
}
By using post-order traversal we can solve this problem (other traversals would also work).
struct BinaryTreeNode* removeLeaves(struct BinaryTreeNode* root) {
if (root != NULL)
{
if (root->left == NULL && root->right == NULL)
{
free(root);
return NULL;
}
else
{
root->left = removeLeaves(root->left);
root->right = removeLeaves(root->right);
}
}
return root;
}
Time Complexity: O(n). Where is number of nodes in tree.
I attempted to build a binary search tree builder method. However I think I am missing something. I tested my method with inOrderPrint method and a treeHeigh method. How my method works is that a root node is the first parameter. The second parameter is another TreeNode node. This parameter is a TreeNode and the method should rearrange itself to a binary search tree.
My inOrderPrint is giving me the correct printing which leads me to assume that my buildBST is working. However my treeHeight method is not giving me the correct output. I'm pretty sure my inOrderPrint and treeHeight methods are correctly created.
I believe there is some logic I am missing in my buildBST method but I cant seem to tell what it is.
I have root set as 14.
If I put TreeNodes with values 5,10,3,20,50,25,40,1,2, 18, 100,101, I get a sorted output of those numbers but with treeHeight, I get an output of 5 when I should be expecting 7.
Could someone tell me where I went wrong?
Binary Search Tree generator
code:
public static void buildBST(TreeNode root, TreeNode node) {
if (root == null) {
node = root;
} else {
// less than root
if (node.data < root.data) {
if (root.left == null) {
root.left = node;
} else {
buildBST(root.left, node);
}
}
// greater than root
if (node.data >= root.data) {
if (root.right == null) {
root.right = node;
} else {
buildBST(root.right, node);
}
}
}
}
inOrderPrint:
public static void inOrderPrint(TreeNode node) {
if (node == null) {
return;
} else {
inOrderPrint(node.left);
System.out.println(node.data);
inOrderPrint(node.right);
}
}
treeHeight:
public static int treeHeight(TreeNode node) {
if (node == null) {
return 0;
} else {
int Ldepth = treeHeight(node.left);
int Rdepth = treeHeight(node.right);
return Math.max(Ldepth, Rdepth) + 1;
}
}
14
/ \
5 20
/ /\
3 18 50
/ / \
1 25 100
\ \ \
2 40 101
Height is 5.
The height of the tree is most definitely 5. Easy to see using this little tool
http://algs4.cs.princeton.edu/GrowingTree/