Trying to add an element to BST. I have an idea of how to do it, but my implementation is destructive, and the original root is not preserved (so the tree basically becomes useless). The tree is based on lists, and this method is based on recursion. My real problem is preserving the original root. I'm using generics.
So far what I have:
public void addElement(E elem, Node<E> root) {
Create node with a value of elem, call it newNode
Case 1: Tree is empty
root = newNode();
return; //End of method.
Otherwise, keep searching the tree (by comparing the value of out node a with the root of the tree.
if (!root.hasLeft() && !root.hasRight) { //if the root in question has no children
if (elem < rootValue) { //Set the element as the left element
root.setLeft(newNode);
}
else { //Set the element as the right element.
root.setRight(newNode);
}
}
else {
if (E < root.getElem()) {
//This is where the value of our node is compared to the value of the root, which we passed in.
//(I know that we can't use the < and > operators with generics, but assume it works).
root = root.getLeft() //Left node is new root
addElement(elem, root); //Call the method again
}
else {
root = root.getRight(); //Right node is new root
addElement(elem, root) //Call method again
}
}
}
Forgive me if this is a duplicate/vague question, this is my first post on SO, and I'm kind of noob.
if (!root.hasLeft() && !root.hasRight) {
This logic is wrong. You're only considering "setting" the left child, if you have neither a left nor right child. This change should do it:
void addElement(elem, root)
{
if (elem < root.value) {
if(!root.hasLeft())
root.setLeft(newNode);
else
addElement(elem, root.getLeft());
}
else {
if(!root.hasRight())
root.setRight(newNode);
else
addElement(elem, root.getRight());
}
}
You should not be changing root of the class, just passing it into the next method call. This should preserve root.
By the way, I assume you have rootValue = root.value somewhere or somethign similar?
Related
This question also applies to various linked lists methods as well. So, when I have a method:
public void insert(String key)
{
if(top == null)
{
top = new Node(key);
}else {
Node newNode = new Node(key);
Node rover = top;
Node prev = top;
boolean wentLeft = true;
while(rover != null)
{
if (rover.getName().compareTo(key) < 0)
{
prev = rover;
rover = rover.getRight();
wentLeft = false;
}else {
wentLeft = true;
prev = rover;
rover = rover.getLeft();
}
}
if(wentLeft == true)
{
prev.setLeft(newNode);
}else {
prev.setRight(newNode);
}
}
nElems++;
}
How is the top of the Binary Search Tree and its children updated despite not being directly set anywhere in the method?
I know this likely has something to do with shallow copying and that like rover/prev are still referencing top in memory but I still don't really get it.
Even though I feel like I understand Linked Lists and Binary Search Trees on a conceptual level I don't feel comfortable moving forward with them without understanding this.
There are no copies being made. When you assign prev = top, that only creates another reference to the same object as top, not a copy.
The code works because nodes are inserted one by one.
When prev.setLeft/setRight is called, prev is already in the tree because it was inserted before. So prev is already in the tree, i. e. the parent of prev is top, or the parent of the parent of prev, you get the idea. Thus, when new_node becomes child of prev, it becomes part of the tree.
This is what makes linked lists and trees so useful. When you insert an element, you only have to make one connection.
I have the following code to insert into the binary tree:
public void insert(T item) {
root = insert(item, root);
}
private Node insert(T item, Node node) {
if(node == null){
return new Node(item, null, null);
} else {
if(item.compareTo(node.item) > 0) {
node.rightChild = insert(item, node.rightChild);
} else {
node.leftChild = insert(item, node.leftChild);
}
}
return node;
}
the code works fine, I have tested it
my question is, how come the root is never changed since in the public function I assigned the returned node from the private function to the root
Thank you!
The public insert is just an interface into the recursive method which rebuilds the tree as the stack unwinds ending where you started, at the root (root = ...). Except for the first insert, you go left or right until you insert at the leaf level. Without any balancing, you will have the same root (assuming no removals) for the lifetime of the tree. Therefore, the only time the root changes on insert is when it's empty.
Note: There's also a matter of what happens when a node is inserted with an existing value; do you discard it, allow duplicates, or swap the objects? That's an implementation detail.
I read your code again and your code is correct. The return value is always the root element because your frist function call is insert(item, root) and the return value is what you give.
I am trying to write a method which recursively deletes a node from a binary search tree. I understand the algorithm, but my code is currently returning an error. When I try to delete a leaf node, i.e. a node which has no children, it deletes that node but also the topmost node of the tree.
I already have methods which to find the head of a node, getValue(), as well as finding the left and right subtrees, getLeft() and getRight(). I also have the method isEmpty() which checks to see if a tree is empty.
This is my code currently, where x is the node to be deleted and a is a binary search tree:
public static Tree delete(int x, Tree a) {
if (a.isEmpty()) {
return new Tree();
} if (x>a.getValue()) {
return delete(x, a.getRight());
} else if (x<a.getValue()) {
return delete(x, a.getLeft());
} else {
if (a.getLeft().isEmpty()&&a.getRight().isEmpty()) {
return new Tree();
} if (a.getRight().isEmpty()) {
return delete(x, a.getLeft());
} if (a.getLeft().isEmpty()) {
return delete(x, a.getRight());
} else {
return new Tree(); //not yet completed
}
}
}
Can anyone give me any clues as to why this would be happening? Thanks in advance
Edit: Here is the code which eventually worked if anyone happens to stumble across this question
public static Tree delete(int x, Tree a) {
if (a.isEmpty()) {
return new Tree();
} if (x>a.getValue()) {
return new Tree(a.getValue(), a.getLeft(), delete(x, a.getRight()));
} else if (x<a.getValue()) {
return new Tree(a.getValue(), delete(x, a.getLeft()), a.getRight());
} else {
if (a.getLeft().isEmpty()&&a.getRight().isEmpty()) {
return new Tree();
} if (a.getRight().isEmpty()) {
return new Tree(a.getLeft().getValue(), delete(a.getLeft().getValue(), a.getLeft()), a.getRight());
} if (a.getLeft().isEmpty()) {
return new Tree(a.getRight().getValue(), a.getLeft(), delete(a.getRight().getValue(), a.getRight()));
} else {
return new Tree(max(a.getLeft()), delete(max(a.getLeft()), a.getLeft()), a.getRight());
}
}
}
This method returns an empty tree instead of setting left or right as empty. This is why you think it's deleting the top node. Also it doesn't look like it handles deleting the node itself, only child nodes.
You never actually delete anything. There are two ways to do this.
Making a structureal copy of the tree until the node to be deleted and then take one of the children and insert the other to the chosen child the result of the insert is the result of the tree.
Finding the parent of the node to be deleted and mutate the accessor to the node to be one of the children and then add the other child subtree to the parent tree. Basically here you have a tree class that handles insertion and which has a root. Deleting the root is a special case with rebinding instead of altering a node.
If you are making a backtracking algorithm where going back to a previous tree is needed #1 is the only choice and it will share as much structure with the previous version of the tree. If you want to iterate and update a data structure to reflect something where you never need th eprevious state #2 is the best choice.
I understand the algorithms but I am not sure how to put it into actual codes. Please help! And also please explain in details. I really want to understand this besides just copying down the answer. ;)
Here are my codes:
public boolean getLeftChild(){
Node insertNode = root;
while(insertNode!=null){
insertNode = insertNode.left;
}
return true;
}
public Boolean removeMin(){
Node insertNode = root;
Node parentNode =root;
if (insertNode.left ==null){
insertNode.right = parentNode;
insertNode = null;
}else if (getLeftChild() ==true && insertNode.right != null){
insertNode.left = null;
}else{
parentNode.left = insertNode.right;
}
return true;
}
First things first: For trees I highly recommend recursion.
Just one example:
getSmallestNode(Node node){
if(node.left != null){
return getSmallestNode(node.left)
}
return node;
}
For the deletion, there can be two cases if you want do delete the smallest (and therefore the "most left leaf" child) of a binary tree.
Case 1: The leaf has no child nodes, in that case just set the according entry in the parent to null (mostLeftChild.getParent().left = null)
Case 2: The leaf has a right child node (there can't be a left child node because that means there would be a smaller node and your currently selected node isn't the smallest) in that case you replace the current left node with the smallest node of the right subtree mostLeftChild.getParent().left = getSmallestFromSubtree(mostLeftChild.right)
So now to make that into code, it could look something like this (No guarantee that it really works)
public Node deleteSmallest(Node node){
// haven't reached leaf yet
if(node.left != null{
return deleteSmallest(node.left)
}
// case 1, no child nodes
if(node.right == null){
node.getParent().left = null;
} else { // case 2, right child node
node.getParent().left = deleteSmallest(node.right)
}
return node;
}
And you would call it with deleteSmallest(root)
My data structures class is working with trees. We are implementing a 3-ary tree, containing 2 values with a reference to a left, middle, and right node (left subtree is less than value 1, middle subtree is between value 1 and value 2, right subtree is greater than value 2). An interface has been provided for the Tree class, and the find, insert, and delete methods must be recursive. The client code which this will be tested against uses the insert method repeatedly to create the tree, and the root starts off as null.
I'm trying to insert values into the tree recursively by finding the parent node in a separate private method, then changing the returned node as appropriate. The problem currently is that the method returns the initial node, which is the root, and correctly creates a new node with the value because the root is null. However, the root remains null.
I'm pretty certain this is due to the way that references and values work in Java (similar to C# as described in this article by Jon Skeet); given the constraints, how should I change this to allow insertions into the tree? Below is the current insert method in the tree class, along with the similar private method.
public void insert(AnyType newData)
{
// If insert node is null, make a new node with newData as first key
TernaryNode<AnyType> insert_node = findNode(newData, root);
if (insert_node == null)
{
insert_node = new TernaryNode<AnyType>(newData);
}
else
{
// Get the key that is equal if the insert node is not null
if (insert_node.getKey1() == null)
{
insert_node.setKey1(newData);
}
else
{
insert_node.setKey2(newData);
}
}// end else
}// end insert
private TernaryNode<AnyType> findNode(AnyType item, TernaryNode<AnyType> node)
{
TernaryNode<AnyType> current_node = node;
if (current_node != null)
{
if (current_node.getKey1() != item &&
current_node.getKey2() != item)
{
// Comparator checks left
if (compare.compare(current_node.getKey1(), item) <= -1)
{
return findNode(item, current_node.left);
} // Comparator checks right
else if (compare.compare(current_node.getKey2(), item) >= 1)
{
return findNode(item, current_node.right);
}// Comparator checks middle
else
{
return findNode(item, current_node.middle);
}
}// end while
}// end if
// Return current node even if it is null
return current_node;
}// end findNode
Unless you're assigning something to the root member, it will never acquire a value. You probably need some sort of outer container for your tree, similarly to how an XML document (which is also a tree) has an outer Document object which is distinct from the actual document root node.
TernaryNode<AnyType> insert_node = findNode(newData, root);
if (insert_node == null)
{
insert_node = new TernaryNode<AnyType>(newData);
root = insert_node;
}