i had to implement a binary tree pictured on this file
together with the class Diagramm and binary tree for orientation.
So following the text and the Pictures i have to implement a constructor, a get- and insert method for this binary tree.
public class BinaryTree {
private Node root = null;
private static class Node {
private Integer key;
private String value;
private Node left = null;
private Node right = null;
public Node(Integer key, String value) {
this.key = key;
this.value = value;
}
}
public boolean insert(Integer key, String value) {
if (root == null) {
root = new Node(key, value);
return true;
} else {
return insert(root, key, value);
}
}
private boolean insert(Node node, Integer key, String value) {
if (key.equals(node.key)) {
// duplicate
return false;
} else if (key < node.key) {
if (node.left == null) {
node.left = new Node(key, value);
return true;
} else {
return insert(node.left, key, value);
}
} else if (key > node.key) {
if (node.right == null) {
node.right = new Node(key, value);
return true;
} else {
return insert(node.right, key, value);
}
}
return false;
}
// not tested, crass assumptions, public domain
public String get(Integer key) {
return get(root, key); // start search from the root.
}
public String get(Node node, Integer key) {
String result = null; // Assume key is not found
if (node.key.equals(key)) { // Key matches? This is the result.
return node.value;
} else {
if (key < node.key && node.left != null) { // key is lower than
// current node,
// and there is a left
// branch, keep
// search from there.
result = get(node.left, key);
} else if (key > node.key && node.right != null) { // key is greater
// than current
// node,
// and there is
// a left
// branch,
// keep search
// from there.
// The key >
// node.key is
// arguably
// redundant.
result = get(node.right, key);
}
}
return result;
}
How can i implement a correct main function for testing? And on top i have to visualize the binary tree with help of graphviz and adding a method in the node class which creates a string for the dot-code. How does it work with Eclipses?
The get method will start at a specific node within the tree, and check whether that node itself meets the criteria. If it does, it returns the value. If not, it will defer to the appropriate branch and continue searching.
// not tested, crass assumptions, public domain
public String get(Integer key) {
return get(root, key); // start search from the root.
}
public String get(Node node, Integer key) {
String result = null; // Assume key is not found
if (node.key.equals(key)) { // Key matches? This is the result.
return node.value;
} else {
if (key < node.key && node.left != null) { // key is lower than current node,
// and there is a left branch, keep
// search from there.
result = get(node.left, key);
} else if (key > node.key && node.right != null) { // key is greater than current node,
// and there is a left branch,
// keep search from there.
// The key > node.key is arguably
// redundant.
result = get(node.right, key);
}
}
return result;
}
If you choose procedural approach, right way to do things will be that:
public class BinaryTree {
private Node root = null;
private static class Node {
private Integer key;
private String value;
private Node left = null;
private Node right = null;
public Node(Integer key, String value) {
this.key = key;
this.value = value;
}
}
public boolean insert(Integer key, String value) {
if (root == null) {
root = new Node(key, value);
return true;
} else {
return insert(root, key, value);
}
}
private boolean insert(Node node, Integer key, String value) {
if (key.equals(node.key)) {
// duplicate
return false;
} else if (key < node.key) {
if (node.left == null) {
node.left = new Node(key, value);
return true;
} else {
return insert(node.left, key, value);
}
} else if (key > node.key) {
if (node.right == null) {
node.right = new Node(key, value);
return true;
} else {
return insert(node.right, key, value);
}
}
return false;
}
}
Now compare it to OOP approach and choose, which one you like more:
public class BinaryTree {
private Node root = null;
private static class Node {
private Integer key;
private String value;
private Node left = null;
private Node right = null;
public Node(Integer key, String value) {
this.key = key;
this.value = value;
}
private boolean insert(Integer key, String value) {
if (key.equals(this.key)) {
// duplicate
return false;
} else if (key < this.key) {
if (left == null) {
left = new Node(key, value);
return true;
} else {
return left.insert(key, value);
}
} else if (key > this.key) {
if (right == null) {
right = new Node(key, value);
return true;
} else {
return right.insert(key, value);
}
}
return false;
}
}
public boolean insert(Integer key, String value) {
if (root == null) {
root = new Node(key, value);
return true;
} else {
return root.insert(key, value);
}
}
}
Solution is simple. For insert operation:
If there is no root in the tree yet, create one.
Otherwise add a new value to the root node.
Inserting a value to some node (starting from root one):
If node's key equals to the inserted key => we have a duplicate and won't proceed any further.
If inserted key is lesser than node's key, do:
If there is no left subtree, create a new node and assign it as a left child.
If there is already a left subtree, recursively add new (key, value) to it.
If inserted key is greater than node's key, do: (by analogy with #2)
Related
I am making a boolean method that Deletes an element from the binary tree,
Returns true if the element is deleted successfully
, and Returns false if the element is not in the tree. The issue that I am having is that for some reason it is not deleting the node sometimes. I just want to know if I am doing anything wrong, thanks in advance.
here is my code:
public boolean delete(E e) {
BSTDelete<E> d = new BSTDelete<E>();
boolean deleted = d.delete(e, root);
if (deleted)
size -= 1;
return deleted;
}
public class BSTDelete<E extends Comparable<E>> {
public boolean delete(E e, TreeNode<E> root) {
if (root == null) {
return false;
}
if (e == root.element) {
if (root.right == null && root.left == null) {
root = null;
} else if (root.right == null) {
root = root.left;
} else if (root.left == null) {
root = root.right;
} else
root.element = minValue(root.left);
delete(root.element, root.left);
// Delete the inorder successor
} else if (e.compareTo(root.element) < 0) {
delete(e, root.left);
} else {
delete(e, root.right);
}
return true;
}
E minValue(TreeNode<E> root) {
E minv = root.element;
while (root.right != null) {
minv = root.right.element;
root = root.right;
}
return minv;
}
}
here is a test that keeps failing. The second assertEquals says that i.next() is "Beatrice" and not "Carl"
BST <String>b = new BST<String>();
b.insert("Arthur");
b.insert("Beatrice");
b.insert("Carl");
b.insert("Dagmar");
b.delete("Beatrice");
Iterator <String> i = b.iterator();
assertEquals(i.next(), "Arthur");
assertEquals(i.next(), "Carl");
assertEquals(i.next(), "Dagmar");
}
and here is my BSTInorderIterator class:
public class BSTInorderIterator<E extends Comparable<E>> implements
java.util.Iterator<E> {
int current = 0;
ArrayList<E> list = new ArrayList<E>();
private TreeNode<E> root;
public BSTInorderIterator(TreeNode<E> root) {
list = new ArrayList<E>();
inorder(root);
}
/** Inorder traversal from the root */
public void inorder() {
inorder(root);
}
/** Inorder traversal from a subtree */
public void inorder(TreeNode<E> root) {
if (root.left != null)
inorder(root.left);
list.add(root.element);
if (root.right != null)
inorder(root.right);
}
#Override
/** More elements for traversing? */
public boolean hasNext() {
return current < list.size();
}
#Override
/** Get the current element and move to the next */
public E next() {
return list.get(current++);
}
#Override
/** Remove the current element */
public void remove() {
// to do: make this work correctly
}
The delete method inside the class BSTDelete is a recursive method, however you're never returning the recursive method calls. Therefore your delete method will only ever return false when you call it with a like d.delete(e, root) where root is null.
For example even though delete(e, root.left) might return false because root.left is null your original method call will return true since you don't return the result of delete(e, root.left).
To fix this add return when you're calling the method recursively, this might only be a partial fix to your issue:
public boolean delete(E e, TreeNode<E> root) {
if (root == null) {
return false;
}
if (e == root.element) {
if (root.right == null && root.left == null) {
root = null;
} else if (root.right == null) {
root = root.left;
} else if (root.left == null) {
root = root.right;
} else
root.element = minValue(root.left);
return delete(root.element, root.left);
// Delete the inorder successor
} else if (e.compareTo(root.element) < 0) {
return delete(e, root.left);
} else {
return delete(e, root.right);
}
return true;
}
This question is how do I create a new node correctly to implement the insert method? I am using eclipse IDE to write this code, but I am stuck.
public KeyValueDSBinarySearchTree(Class<K> keyType,
Class<V> valueType,
DSComparator<K> keyComparator) {
ObjectTools.paramNullCheck(keyType, "keyType");
ObjectTools.paramNullCheck(valueType, "valueType");
ObjectTools.paramNullCheck(keyComparator, "keyComparator");
rootNode = null;
count = 0;
levelCount = 0;
lastReplacedPair = null;
lastDeletedPair = null;
}
#Override
public DSKeyValuePair<K, V> insert(K key, V value) {
DSKeyValuePair<K, V> node;
if (rootNode == null) {
count++;
return node;
}
if (key.compareTo(node.getKey())<0) {
rootNode.left = insert(key, value);
}
else {
rootNode.right = insert(key, value);
}
return node;
}
My try (gave me a NullPointerException):
public Karte giveFirst(BinarySearchTree<Karte> t){
if(t.getLeftTree() != null) {
return giveFirst(t.getLeftTree());
}else{
return t.getContent();
}
}
Complete Binary Search Tree Code:
package Model;
private class BSTNode<CT extends ComparableContent<CT>> {
private CT content;
private BinarySearchTree<CT> left, right;
public BSTNode(CT pContent) {
this.content = pContent;
left = new BinarySearchTree<CT>();
right = new BinarySearchTree<CT>();
}
}
private BSTNode<ContentType> node;
public BinarySearchTree() {
this.node = null;
}
public void insert(ContentType pContent) {
if (pContent != null) {
if (isEmpty()) {
this.node = new BSTNode<ContentType>(pContent);
} else if (pContent.isLess(this.node.content)) {
this.node.left.insert(pContent);
} else if(pContent.isGreater(this.node.content)) {
this.node.right.insert(pContent);
}
}
}
public BinarySearchTree<ContentType> getLeftTree() {
if (this.isEmpty()) {
return null;
} else {
return this.node.left;
}
}
public ContentType getContent() {
if (this.isEmpty()) {
return null;
} else {
return this.node.content;
}
}
public BinarySearchTree<ContentType> getRightTree() {
if (this.isEmpty()) {
return null;
} else {
return this.node.right;
}
}
public void remove(ContentType pContent) {
if (isEmpty()) {
return;
}
if (pContent.isLess(node.content)) {
node.left.remove(pContent);
} else if (pContent.isGreater(node.content)) {
node.right.remove(pContent);
} else {
if (node.left.isEmpty()) {
if (node.right.isEmpty()) {
node = null;
} else {
node = getNodeOfRightSuccessor();
}
} else if (node.right.isEmpty()) {
node = getNodeOfLeftSuccessor();
} else {
if (getNodeOfRightSuccessor().left.isEmpty()) {
node.content = getNodeOfRightSuccessor().content;
node.right = getNodeOfRightSuccessor().right;
} else {
BinarySearchTree<ContentType> previous = node.right
.ancestorOfSmallRight();
BinarySearchTree<ContentType> smallest = previous.node.left;
this.node.content = smallest.node.content;
previous.remove(smallest.node.content);
}
}
}
}
public ContentType search(ContentType pContent) {
if (this.isEmpty() || pContent == null) {
return null;
} else {
ContentType content = this.getContent();
if (pContent.isLess(content)) {
return this.getLeftTree().search(pContent);
} else if (pContent.isGreater(content)) {
return this.getRightTree().search(pContent);
} else if (pContent.isEqual(content)) {
return content;
} else {
return null;
}
}
}
private BinarySearchTree<ContentType> ancestorOfSmallRight() {
if (getNodeOfLeftSuccessor().left.isEmpty()) {
return this;
} else {
return node.left.ancestorOfSmallRight();
}
}
private BSTNode<ContentType> getNodeOfLeftSuccessor() {
return node.left.node;
}
private BSTNode<ContentType> getNodeOfRightSuccessor() {
return node.right.node;
}
}
How can I change/rewrite my code for it to work?
Think what would happen when you reach the left most leaf node.
Its left tree will be null which means you will break out of the while loop. You are returning null after this and so any attempt to access the state of the return value will throw an exception.
You must return this node when it has no more left children as that will be the smallest element in the tree
Also, I don't know why you have BinarySearchTree and BSTNode. A BSTNode should be good enough to construct a tree. Please go through some tutorial/lessons for a better understanding.
How to get the first element when going through a binary search tree with inorder?
Keep going left till you can't go left anymore... If a node has a left child, go for it. Keep doing this till you get to a node that does not have a left child. When you are there, you know you are in the left-most part of the tree. Following code snippet shows an idea of how this can be achieved given the root of a BST.
public BSTNode getSmallest(BSTNode root) {
if(root.left != null)
return getSmallest(root.left);
return root;
}
I'm having an issue with implementing this BinarySearchTree listed below. For some context, I'm creating a binary search tree based off of an interface that requires generics and a comparable key.I think that there is a logic error in the code that is stumping me and it's in the insert method in the BinarySearchTree, but I'm not 100% sure.
Below is the class for my Node, which is used in my BST.
public class MyNodeClass<Key extends Comparable<Key>, Value>{
private Key key;
private Value value;
private MyNodeClass<Key,Value> left = null;
private MyNodeClass<Key,Value> right = null;
public MyNodeClass(Key key, Value val)
{
this.key = key;
this.value = val;
}
public void setKey(Key key){
this.key = key;
}
public void setValue(Value value){
this.value = value;
}
public Key getKey(){
return this.key;
}
public Value getValue(){
return this.value;
}
public void setLeft(MyNodeClass<Key, Value> l){
this.left = l;
}
public void setRight(MyNodeClass<Key, Value> r){
this.right = r;
}
public MyNodeClass<Key,Value> getLeft(){return this.left;}
public MyNodeClass<Key,Value> getRight(){return this.right;}
public int compareTo(Key that){
return(this.getKey().compareTo(that));
}
}
public class MyBinarySearchTree<Key extends Comparable<Key>, Value> implements BinarySearchTree<Key,Value> {
private MyNodeClass<Key, Value> root;
public MyBinarySearchTree(){
root = null;
}
#Override
public boolean isEmpty() {
return root == null;
}
#Override
public Value insert(Key key, Value val) {
MyNodeClass<Key,Value> newNode = new MyNodeClass<Key,Value>(key,val);
newNode.setKey(key);
newNode.setValue(val);
if(root==null){
root = newNode;
return(newNode.getValue());
}
else{
MyNodeClass<Key,Value> current = newNode;
MyNodeClass<Key,Value> parent;
while(true){
{
parent = current;
if(current.compareTo(key) == 1)
{
current = current.getLeft();
if(current == null)
{
parent.setLeft(newNode);
return parent.getLeft().getValue();
}
}
else if(current.compareTo(key) == -1){
current = current.getRight();
if(current == null)
{
parent.setRight(newNode);
return parent.getRight().getValue();
}
}
else{
if(current.compareTo(key) == 0){
current.setKey(key);
current.setValue(val);
return current.getValue();
}
}
}
}
}
}
#Override
public Value find(Key key) {
MyNodeClass<Key, Value> current = root;
while (current.compareTo(key) != 0)
{
if (current.compareTo(key) == 1)
{
current = current.getLeft();
} else {
current = current.getRight();
}
if(current == null)
return null;
}
return current.getValue();
}
#Override
public Value delete(Key key) {
MyNodeClass<Key,Value> current = root;
MyNodeClass<Key,Value> parent = root;
boolean isLeftChild = true;
while(current.compareTo(key) != 0) {
parent = current;
if (current.compareTo(key) == 1) {
isLeftChild = true;
current = current.getLeft();
} else {
isLeftChild = false;
current = current.getRight();
}
if(current == null)
return null;
}
if(current.getLeft() == null && current.getRight() == null) {
if (current == root) {
root = null;
} else if (isLeftChild) {
parent.setLeft(null);
} else{
parent.setRight(null);
}
return current.getValue();
}
else if(current.getRight() == null)
{
if(current == root) {
root = current.getLeft();
}
else if(isLeftChild) {
parent.setLeft(current.getLeft());
}
else{
parent.setRight(current.getLeft());
}
return current.getValue();
}
else if(current.getLeft() == null)
{
if(current == root)
root = current.getRight();
else if(isLeftChild)
parent.setLeft(current.getRight());
else
parent.setRight(current.getRight());
return current.getValue();
}
else
{
MyNodeClass<Key,Value> successor = getSuccessor(current);
if(current == root)
root = successor;
else if(isLeftChild)
parent.setLeft(successor);
else
parent.setRight(successor);
successor.setLeft(current.getLeft());
return current.getValue();
}
}
#Override
public String stringLevelOrder() {
return(LevelOrder(root));
}
private MyNodeClass<Key,Value> getSuccessor(MyNodeClass<Key,Value> deleteNode)
{
MyNodeClass<Key,Value> successorParent = deleteNode;
MyNodeClass<Key,Value> successor = deleteNode;
MyNodeClass<Key,Value> current = deleteNode.getRight();
while(current != null)
{
successorParent = successor;
successor = current;
current = current.getLeft();
}
if(successor != deleteNode.getRight())
{
successorParent.setLeft(successor.getRight());
successor.setRight(deleteNode.getRight());
}
return successor;
}
public static void main(String[] args)
{
MyBinarySearchTree<Double, MyStudent> BST = new MyBinarySearchTree<Double, MyStudent>();
MyStudent myStud1 = new MyStudent();
MyStudent myStud2 = new MyStudent();
MyStudent myStud3 = new MyStudent();
MyStudent myStud4 = new MyStudent();
MyStudent myStud5 = new MyStudent();
myStud1.init("Clarise", 1.1);
myStud2.init("Christopher", 1.2);
myStud3.init("John", 1.3);
myStud4.init("Chloe", 1.4);
myStud5.init("Goo", 1.5);
System.out.println(BST.insert(myStud1.getGPA(), myStud1));
System.out.println(BST.insert(myStud2.getGPA(), myStud2));
System.out.println(BST.insert(myStud3.getGPA(), myStud3));
System.out.println(BST.insert(myStud4.getGPA(), myStud4));
System.out.println(BST.insert(myStud5.getGPA(), myStud5));
System.out.println("Delete Key 1.0: " +BST.delete(1.3));
System.out.println("Delete Key 1.4: " +BST.delete(1.4));
System.out.println("Is Empty?: " +BST.isEmpty());
System.out.print("Find 3.9: "+ BST.find(3.9));
}
}
The result of the main is the following:
{Clarise:1.1}
{Christopher:1.2}
{John:1.3}
{Chloe:1.4}
{Goo:1.5}
Delete Key 1.0: null
Delete Key 1.4 null
Is Empty?: false
Find 3.9: null
I'm not entirely sure what the issue is and I've had some help from others, however they can't find the problem. Hoping that someone else can see something that we don't see.
In your insert method, after you've checked that root is not null, you are inserting newNode into the newNode instead of inserting it into the root.
This:
MyNodeClass<Key,Value> current = newNode;
MyNodeClass<Key,Value> parent;
Should be:
MyNodeClass<Key,Value> current = root;
MyNodeClass<Key,Value> parent;
P.S. any kind of testing would show you the problem with your insert within a minute. You could write a size() method and see that your inserts are not working, you could write a toString() method and see the state of the tree, finally you could debug.
MyNodeClass<Key,Value> current = newNode;
There is problem here.
If a tree is not empty, then your "current" should begin at root node. What you done is insert "newNode" to "newNode".
Change the code to be:
MyNodeClass<Key,Value> current = root;
I wanted to try and implement my own BST as an exercise, but I am stuck on the node removal. I cannot figure out why it doesn't work in some cases. I took the algorithm from a book, but when I test it with random elements, there are cases in which it does not remove the element, or even messes up their order so they are no longer sorted. What am I doing wrong and what would be a better way to accomplish this?
NOTE: All of the println() statements in the methods are there only for debugging purposes
class TreeNode<T extends Comparable<T>> {
T data;
TreeNode<T> left;
TreeNode<T> right;
TreeNode<T> parent;
TreeNode(T data) {
this.data = data;
}
boolean hasBothChildren() {
return hasLeftChild() && hasRightChild();
}
boolean hasChildren() {
return hasLeftChild() || hasRightChild();
}
boolean hasLeftChild() {
return left != null;
}
boolean hasRightChild() {
return right != null;
}
boolean isLeftChild() {
return this.parent.left == this;
}
boolean isRightChild() {
return this.parent.right == this;
}
}
public class BinaryTreeSet<T extends Comparable<T>> {
private TreeNode<T> root;
private void makeRoot(T element) {
TreeNode<T> node = new TreeNode<T>(element);
root = node;
}
private TreeNode<T> find(T element) {
TreeNode<T> marker = root;
TreeNode<T> found = null;
while (found == null && marker != null) {
int comparator = (marker.data.compareTo(element));
if (comparator > 0)
marker = marker.left;
else if (comparator < 0)
marker = marker.right;
else
found = marker;
}
return found;
}
private TreeNode<T> max(TreeNode<T> root) {
TreeNode<T> currentMax = root;
while (currentMax.hasRightChild()) {
currentMax = currentMax.right;
}
return currentMax;
}
// returns the inorder predecessor of node
private TreeNode<T> predecessor(TreeNode<T> node) {
return max(node.left);
}
// removes a given node with 0 or 1 children
private void removeNode(TreeNode<T> node) {
if (!node.hasChildren()) {
System.out.println("node with no children");
if (node.isLeftChild())
node.parent.left = null;
else
node.parent.right = null;
}
else {
System.out.println("node with 1 child");
if (node.isRightChild()) {
if (node.hasLeftChild())
node.parent.right = node.left;
else if (node.hasRightChild())
node.parent.right = node.right;
}
else if (node.isLeftChild()) {
if (node.hasLeftChild())
node.parent.left = node.left;
else if (node.hasRightChild())
node.parent.left = node.right;
}
}
node = null;
}
public BinaryTreeSet() {
root = null;
}
public void addElement(T element) {
if (root == null)
makeRoot(element);
else {
TreeNode<T> marker = root;
TreeNode<T> node = new TreeNode<T>(element);
boolean done = false;
while(!done) {
int comparator = marker.data.compareTo(element);
if (comparator > 0) {
if (marker.hasLeftChild())
marker = marker.left;
else {
marker.left = node;
done = true;
}
}
else if (comparator < 0) {
if (marker.hasRightChild())
marker = marker.right;
else {
marker.right = node;
done = true;
}
}
else
return;
node.parent = marker;
}
}
}
public boolean contains(T element) {
boolean found = (find(element) == null)? false : true;
return found;
}
public boolean removeElement(T element) {
TreeNode<T> node = find(element);
if (node == null)
return false;
// removal of a node with no children
if (!node.hasChildren()) {
if (node.isLeftChild()) {
node.parent.left = null;
}
else if (node.isRightChild()) {
node.parent.right = null;
}
}
// removal of a node with both children
else if (node.hasBothChildren()) {
TreeNode<T> pred = predecessor(node);
T temp = pred.data;
pred.data = node.data;
node.data = temp;
removeNode(pred);
}
// removal of a node with only 1 child
else {
if (node.isRightChild()) {
if (node.hasLeftChild())
node.parent.right = node.left;
else if (node.hasRightChild())
node.parent.right = node.right;
}
else if (node.isLeftChild()) {
if (node.hasLeftChild())
node.parent.left = node.left;
else if (node.hasRightChild())
node.parent.left = node.right;
}
}
node = null;
System.out.println("item removed: " + !contains(element));
return true;
}
}
please add following Method into BinaryTreeSet Class and call it,
which will show you current element list with Left/Right prefix.
boolean rootOncePrint = true;
public void printAllTree(TreeNode<T> startNode){
if(startNode == null) return;
//System.out.println(startNode.data);
if(rootOncePrint){
System.out.println("Root : " + startNode.data);
rootOncePrint = false;
}
if(startNode.hasChildren()){
if(startNode.hasLeftChild()){
printAllTree(startNode.left);
}
if(startNode.hasRightChild()){
printAllTree(startNode.right);
}
}
if(startNode != root){
T parentValue = startNode.parent.data;
T dataValue = startNode.data;
System.out.println(startNode.data + ((parentValue.compareTo(dataValue) > 0)?"L":"R"));
}
}
After Add this code, try to add/remove element into BinaryTreeSet so
you will get to know what's going on.
Found the bug that was causing me headaches. The problem was in the cases where I remove nodes with 0 or 1 child. I was not updating their parent nodes, so that messed up with the code. So, instead of, for example
if (node.hasLeftChild())
node.parent.right = node.left;
I should have written
if (node.hasLeftChild()) {
node.parent.left = node.left;
node.left.parent = node.parent;
}
in all cases where I deal with a single child. Also, I forgot to update the root, when the root is the target of the removeElement() function.
However, as it currently stands, I feel I have a lot of repetition in the code. I am yet to come up with a more elegant solution.
EDIT: There are other minor bugs as well, mainly in the isRightChild() and isLeftChild() functions, resulting in NullPointerException if the node in question does not have a parent.