I have 6 Red Black trees filled with different data, but the further down I go, the more my trees get mixed up. I've commented out all but two of them, here's my code for those two trees.
Scanner co2DateFile = new Scanner(new File("co2.csv"));
Scanner co2NumFile = new Scanner(new File("co2.csv"));
RedBlackBST co2DateKey = new RedBlackBST();
RedBlackBST co2NumKey = new RedBlackBST();
while (co2DateFile.hasNextLine()) {
String[] line3 = co2DateFile.nextLine().split(",");
if (line3[0].equals("World")) {
LocalDate date = parseDateString(line3[2]);
String stringDate = date.toString();
co2DateKey.root = co2DateKey.put(co2DateKey.root, stringDate, line3[3]);
}
}
while (co2NumFile.hasNextLine()) {
String[] line4 = co2NumFile.nextLine().split(",");
if (line4[0].equals("World")) {
co2NumKey.root = co2NumKey.put(co2NumKey.root, line4[3], line4[2]);
}
}
co2DateKey.inorder(co2DateKey.root);
I'm using the same file for both trees, but using different pieces of data for the keys and values. If I print co2DateKey inorder, then it prints the keys/values for co2DateKey and co2NumKey, but if I comment out the code for co2NumKey, then co2DateKey only prints its own keys/values. I'm not sure where they're getting crossed, so any help would be appreciated.
Here's my RedBlackBST class:
import java.util.Scanner;
import java.util.LinkedList;
import java.util.Queue;
import java.io.File;
import java.io.FileNotFoundException;
class Node
{
Node left;
Node right; // initializing Nodes and variables
String key;
String value;
String type;
boolean color; // true means color is red, false is black
Node(String key, String value)
{
this.key = key;
this.value = value;
left = null;
right = null;
color = true; // new nodes are always red
}
}
public class RedBlackBST {
public static Node root = null; // root initialized
public Node rotateLeft(Node myNode)
{
Node child = myNode.right;
Node childLeft = child.left; // assigning variables
child.left = myNode;
myNode.right = childLeft; // rotating nodes to the left
return child;
}
public Node rotateRight(Node myNode)
{
Node child = myNode.left; // assigning variables
Node childRight = child.right;
child.right = myNode; // rotating nodes to the right
myNode.left = childRight;
return child;
}
public void flipColors(Node x, Node y) // flipping colors of two given nodes
{
boolean temp = x.color; // uses temp to store color of first node
x.color = y.color; // first node takes second node's color
y.color = temp; // second node takes first node's color
}
public String get(String key) {
return get(root, key); // this function is called from main, which calls recursive get
}
private String get(Node x, String key) {
while (x != null) {
int cmp = key.compareTo(x.key); // compares current key with the one we are searching for
if (cmp < 0)
x = x.left;
else if (cmp > 0)
x = x.right; // recursively searches through tree until key is found
else
return x.value; // returns value associated with said key
}
return null;
}
public boolean getColor(String key) {
return getColor(root, key); // this function is called from main, which calls recursive getColor
}
private boolean getColor(Node x, String key) {
while (x != null) {
int cmp = key.compareTo(x.key); // same idea as get
if (cmp < 0)
x = x.left;
else if (cmp > 0) // recursively searches through tree to find key
x = x.right;
else
return x.color; // returns color of node associated with said key
}
return false;
}
public boolean isRed(Node myNode)
{
if (myNode == null) // checks color of node passed into function, returns true if red
return false;
return (myNode.color == true);
}
// insertion into Left Leaning Red Black Tree.
public Node put(Node myNode, String key, String value)
{
// inserting node, checks for violations to left leaning red black tree come next
if (myNode == null)
return new Node(key, value);
if (key.compareTo(myNode.key) < 0) // compares keys, recursive calls to find proper spot
myNode.left = put(myNode.left, key, value);
else if (key.compareTo(myNode.key) > 0)
myNode.right = put(myNode.right, key, value);
else if (key.equals(myNode.key) == true) // if key is already in tree, numeric value is replaced
myNode.value = value;
else
return myNode;
// case 1.
// when right child is Red but left child is
// Black or doesn't exist.
if (isRed(myNode.right) && !isRed(myNode.left))
{
myNode = rotateLeft(myNode); // left rotate the node to make it into valid structure.
flipColors(myNode, myNode.left); // swap the colors as the child node should always be red
}
// case 2
// when left child as well as left grand child are Red
if (isRed(myNode.left) && isRed(myNode.left.left))
{
myNode = rotateRight(myNode); // right rotate the current node to make it into a valid structure, then flip colors
flipColors(myNode, myNode.right);
}
// case 3
// when both left and right child are Red in color.
if (isRed(myNode.left) && isRed(myNode.right))
{
myNode.color = !myNode.color; // invert the color of node as well it's left and right child
myNode.left.color = false; // change the color to black
myNode.right.color = false;
}
return myNode;
}
public Iterable<String> keys(Node node, Queue<String> queue) { // uses inorder traversal to put keys in right order
if (node != null)
{
keys(node.left, queue);
queue.add(node.key); // adds each key to queue in correct order
keys(node.right, queue);
}
return queue; // returns queue after all keys have been added
}
public String highest(Node node) {
Node current = node;
while (current.right != null) {
current = current.right;
}
return current.key;
}
void inorder(Node node)
{
if (node != null)
{
inorder(node.left);
System.out.println(node.key + " " + node.value);
inorder(node.right);
}
}
Problem is here:
public static Node root = null; // root initialized
The root is declared static, which means it is shared between all instances of RedBlackBST. They all have the same root. Sure they will be mixed up.
Remove the static keyword.
Related
Okay, I've already written several methods related to my problem. Right now I have two methods that are written using recursion (addBSTRecursion (int element) and searchBSTRecursion (int element)). And now I need implement (iteratively) the BST search method (Pair<BinaryTreeNode, BinaryTreeNode> searchBST(int element)) returning the node containing the searched value and its predecessor.
if the searched element is not in the tree, the first element of the pair is null.
if the first element of the pair is a root (it has no predecessor), then the second element of the pair is null.
Here is my class Pair:
public class Pair<T1, T2> {
public T1 first;
public T2 second;
public Pair(T1 a, T2 b) {
first = a;
second = b;
}
}
This is how I managed to implement method (Pair<BinaryTreeNode, BinaryTreeNode> searchBST(int element)), but unfortunately it does not work as expected.
#Override
public Pair<BinaryTreeNode, BinaryTreeNode> searchBST(int element) {
int current = 0;
while (element != data) {
if (element < data) {
current = left.data;
} else {
current = right.data;
}
}
Pair pair = new Pair(element, current);
return pair;
}
To be honest, I don’t know yet how to correctly implement this method, I will be glad to any hints. And also at the bottom I add all my previous classes.
public abstract class BinaryTreeNode {
protected int data; // value stored in the node
protected BinaryTreeNode left, right; // left and right sub-trees
// constructor
public BinaryTreeNode(int data) {
this.data = data;
}
// recursively adds an item to the BST
// #param new data to be stored in the new node
public abstract void addBSTRecursion(int element);
// prints the tree
// for example, for a tree:
// 7
// 6 8
// 2 7 4 9
//
// write:
//
// 2
// 6
// 7
// 7
// 4
// 8
// 9
// method pseudocode
// if there is a left subtree then print the left one (recursive call)
// write out gaps (depending on level), write out data, go to new line
// if it is right, print the right one (recursive call)
// #param level the distance of the node from the root. We start from 0.
public abstract void print(int level);
// recursive searches the BST.
// returns true if it finds an element with the given value
// #param searched value searched
// #return true if the given value is in the tree, false otherwise
public abstract boolean searchBSTRecursion(int element);
// iterative lookup of values in the BST
// returns a pair: node containing the searched element and its predecessor.
// if the searched element is not in the tree, the first element of the pair is null.
// if the first element of the pair is a root (it has no predecessor), then the second element of the pair is null.
// #param searched value searched
// #return pair of nodes: the first is the node containing the value searched for, or null if not found;
// the second element of the pair is the parent of the node (or null if the value is at the root of the tree)
public abstract Pair < BinaryTreeNode, BinaryTreeNode > searchBST(int element);
}
public class Node extends BinaryTreeNode {
public Node(int data) {
super(data);
}
#Override
public void addBSTRecursion(int element) {
Node node = new Node(element);
if (element < data) {
if (left != null) {
left.addBSTRecursion(element);
} else {
left = node;
}
} else {
if (right != null) {
right.addBSTRecursion(element);
} else {
right = node;
}
}
}
#Override
public void print(int level) {
if (left != null) {
left.print(level + 4);
}
for (int i = 0; i < level; i++) {
System.out.print(" ");
}
System.out.print(data + "\n");
if (right != null) {
right.print(level + 4);
}
}
#Override
public boolean searchBSTRecursion(int element) {
if (element == data) {
return true;
} else if (element < data) {
if (left != null && left.searchBSTRecursion(element)) {
return true;
} else {
return false;
}
} else {
if (right != null && right.searchBSTRecursion(element)) {
return true;
} else {
return false;
}
}
}
#Override
public Pair<BinaryTreeNode, BinaryTreeNode> searchBST(int element) {
int current = 0;
while (element != data) {
if (element < data) {
current = left.data;
} else {
current = right.data;
}
}
Pair pair = new Pair(element, current);
return pair;
}
}
public class Main {
public static void main(String[] args) {
Node node = new Node(8);
node.addBSTRecursion(3);
node.addBSTRecursion(10);
node.addBSTRecursion(1);
node.addBSTRecursion(6);
node.addBSTRecursion(14);
node.addBSTRecursion(4);
node.addBSTRecursion(7);
node.addBSTRecursion(13);
node.print(0);
System.out.print(node.searchBSTRecursion(15));
}
}
Okay so I've been looking into this for days and everytime I think I've gotten it down I start writing code and I get to a point where I just can't figure out what exactly to do.
The tree isn't recursive, so I can follow everything really until I start trying to modify it so it uses lazy deletion instead of real deletion. (Right now it nulls out the node it deletes)
What I have managed to figure out:
I added a flag to the node class to set them as deleted
I've implemented a search method that works, it even seems to register if my nodes are deleted or not(lazily)
I know that the rest of the tree class should treat the nodes that are flagged as deleted such that they are not there.
What I don't know:
I've looked at MANY resources and some say all you need to do is set
the node's deleted flag to true. Does this mean that I don't have to
worry about the linking after their flag is set?
Is an appropriate way to do this very superficial? As in, just don't let the methods report that something is found if the flag is set to deleted even though the methods do find something?
In what method(s) should I change to use lazy deletion? Only the delete() method?
If I only change the delete method, how is this picked up by the other methods?
Does the search method look okay?
Here's the rest of the code so you can see what I'm using. I'm really frustrated because I honestly understand how to delete nodes completely way better then this stupid lazy deletion implementation. It's what they teach in the book! lol
Please help... :(
Search Method
So here's my search method:
public String search(E data){
Node<E> current = root;
String result = "";
while(current != null){
if(data.compareTo(current.e) < 0){
current = current.left;
}
else if (data.compareTo(current.e) > 0){
current = current.right;
}
else{
if (current.isDeleted == false){
return result += "Found node with matching data that is not deleted!";
}
else{
return result += "Found deleted data, not usable, continuing search\n";
}
}
}
return result += "Did not find non-deleted matching node!";
}
Tree Class
Tree Code (The real deletion method is commented out at the end so I could replace it with the lazy deletion):
package mybinarytreeexample;
public class MyBinaryTree> {
private Node<E> root = null;
public class Node<E> {
public boolean isDeleted = false;
public E e = null;
public Node<E> left = null;
public Node<E> right = null;
}
public boolean insert(E e) {
// if empty tree, insert a new node as the root node
// and assign the elementy to it
if (root == null) {
root = new Node();
root.e = e;
return true;
}
// otherwise, binary search until a null child pointer
// is found
Node<E> parent = null;
Node<E> child = root;
while (child != null) {
if (e.compareTo(child.e) < 0) {
parent = child;
child = child.left;
} else if (e.compareTo(child.e) > 0) {
parent = child;
child = child.right;
} else {
if(child.isDeleted){
child.isDeleted = false;
return true;
}
return false;
}
}
// if e < parent.e create a new node, link it to
// the binary tree and assign the element to it
if (e.compareTo(parent.e) < 0) {
parent.left = new Node();
parent.left.e = e;
} else {
parent.right = new Node();
parent.right.e = e;
}
return true;
}
public void inorder() {
System.out.print("inorder: ");
inorder(root);
System.out.println();
}
private void inorder(Node<E> current) {
if (current != null) {
inorder(current.left);
System.out.printf("%3s", current.e);
inorder(current.right);
}
}
public void preorder() {
System.out.print("preorder: ");
preorder(root);
System.out.println();
}
private void preorder(Node<E> current) {
if (current != null) {
System.out.printf("%3s", current.e);
preorder(current.left);
preorder(current.right);
}
}
public void postorder() {
System.out.print("postorder: ");
postorder(root);
System.out.println();
}
private void postorder(Node<E> current) {
if (current != null) {
postorder(current.left);
postorder(current.right);
System.out.printf("%3s", current.e);
}
}
public String search(E data){
Node<E> current = root;
String result = "";
while(current != null){
if(data.compareTo(current.e) < 0){
current = current.left;
}
else if (data.compareTo(current.e) > 0){
current = current.right;
}
else{
if (current.isDeleted == false){
return result += "Found node with matching data that is not deleted!";
}
else{
return result += "Found deleted data, not usable, continuing search\n";
}
}
}
return result += "Did not find non-deleted matching node!";
}
public boolean delete(E e) {
}
// an iterator allows elements to be modified, but can mess with
// the order if element not written with immutable key; it is better
// to use delete to remove and delete/insert to remove or replace a
// node
public java.util.Iterator<E> iterator() {
return new PreorderIterator();
}
private class PreorderIterator implements java.util.Iterator<E> {
private java.util.LinkedList<E> ll = new java.util.LinkedList();
private java.util.Iterator<E> pit= null;
// create a LinkedList object that uses a linked list of nodes that
// contain references to the elements of the nodes of the binary tree
// in preorder
public PreorderIterator() {
buildListInPreorder(root);
pit = ll.iterator();
}
private void buildListInPreorder(Node<E> current) {
if (current != null) {
ll.add(current.e);
buildListInPreorder(current.left);
buildListInPreorder(current.right);
}
}
// check to see if their is another node in the LinkedList
#Override
public boolean hasNext() {
return pit.hasNext();
}
// reference the next node in the LinkedList and return a
// reference to the element in the node of the binary tree
#Override
public E next() {
return pit.next();
}
#Override
public void remove() {
throw new UnsupportedOperationException("NO!");
}
}
}
// binary search until found or not in list
// boolean found = false;
// Node<E> parent = null;
// Node<E> child = root;
//
// while (child != null) {
// if (e.compareTo(child.e) < 0) {
// parent = child;
// child = child.left;
// } else if (e.compareTo(child.e) > 0) {
// parent = child;
// child = child.right;
// } else {
// found = true;
// break;
// }
// }
//
//
// if (found) {
// // if root only is the only node, set root to null
// if (child == root && root.left == null && root.right == null)
// root = null;
// // if leaf, remove
// else if (child.left == null && child.right == null) {
// if (parent.left == child)
// parent.left = null;
// else
// parent.right = null;
// } else
// // if the found node is not a leaf
// // and the found node only has a right child,
// // connect the parent of the found node (the one
// // to be deleted) to the right child of the
// // found node
// if (child.left == null) {
// if (parent.left == child)
// parent.left = child.right;
// else
// parent.right = child.right;
// } else {
// // if the found node has a left child,
// // the node in the left subtree with the largest element
// // (i. e. the right most node in the left subtree)
// // takes the place of the node to be deleted
// Node<E> parentLargest = child;
// Node<E> largest = child.left;
// while (largest.right != null) {
// parentLargest = largest;
// largest = largest.right;
// }
//
// // replace the lement in the found node with the element in
// // the right most node of the left subtree
// child.e = largest.e;
//
// // if the parent of the node of the largest element in the
// // left subtree is the found node, set the left pointer of the
// // found node to point to left child of its left child
// if (parentLargest == child)
// child.left = largest.left;
// else
// // otherwise, set the right child pointer of the parent of
// // largest element in the left subtreeto point to the left
// // subtree of the node of the largest element in the left
// // subtree
// parentLargest.right = largest.left;
// }
//
// } // end if found
//
// return found;
What changes is that your tree only grows in term of real space used, and never shrinks. This can be very useful if you choose a list as a data-structure to implement your tree, rather than the usual construct Node E {V value; E right; E; left}. I will come back on this later.
I've looked at MANY resources and some say all you need to do is set
the node's deleted flag to true. Does this mean that I don't have to
worry about the linking after their flag is set?
Yes, if by linking you mean node.left, node.right. Delete simply mark as deleted and that's it. It change nothing else, and it should not, because x.CompareTo(y) must be still working even if x or y are marked as deleted
Is an appropriate way to do this very superficial? As in, just don't
let the methods report that something is found if the flag is set to
deleted even though the methods do find something?
Well by definition of this method "something" means a node without the deleted flag. Anything with the deleted flag is "nothing" for the user of the tree.
what method(s) should I change to use lazy deletion? Only the delete()
method?
Of course not. You already changed the search method yourself. Let's take the isEmpty(). You should keep a counter of deleted nodes and one of total nodes. If they are equal the tree is empty. Otherwise the tree is not.
There is a small bug in your algorithm. When you insert and find out that you land on a deleted node, you just unmark that node. You must also set the value of the node. After all compareTo doesnt insure all fields are strictly equal, just that the objects are equivalent.
if(child.isDeleted){
child.isDeleted = false;
child.e = e; <---- missing
return true;
}
There might be others.
Side Note:
As said before one instance where this method is useful is a tree backed by an list (let's say array list). With this method the children of element at position i are at position 2*i+1 and 2*i+2. Usually when you delete a node p with children, you replace that node with the leftmost node q of the right subtree (or rightmost node in the left subtree). Here you can just mark p as deleted and swap the value of the deleted node and leftmost. Your array stays intact in memory
I am trying to implement a priority queue, using a triply linked data structure. I want to understand how to implement sink and swim operations, because when you use an array, you can just compute the index of that array and that's it. Which doesn't make sense when you use a triply-linked DS.
Also I want to understand how to correctly insert something in the right place, because when you use an array, you can just insert in the end and do a swim operation, which puts everything in the right place, how exactly do I compute that "end" in a linked DS?
Another problem would be removing the element with the biggest priority. To do that, for an array implementation, we just swap the last element with the first (the root) one and then, after removing the last element, we sink down the first one.
(This is a task from Sedgewick).
I posted this in case someone gets stuck doing this exercise from Sedgewick, because he doesn’t provide a solution for it.
I have written an implementation for maximum oriented priority queue, which can be modified according for any priority.
What I do is assign a size to each subtree of the binary tree, which can be defined recursively as size(x.left) + size(x.right) + 1. I do this do be able to find the last node inserted, to be able to insert and delete maximum in the right order.
How sink() works:
Same as in the implementation with an array. We just compare x.left with x.right and see which one is bigger and swap the data in x and max(x.left, x.right), moving down until we bump into a node, whose data is <= x.data or a node that doesn’t have any children.
How swim() works:
Here I just go up by doing x = x.parent, and swapping the data in x and x.parent, until x.parent == null, or x.data <= x.parent.
How max() works:
It just returns root.data.
How delMax() works:
I keep the last inserted node in a separate field, called lastInserted. So, I first swap root.data with lastInserted.data. Then I remove lastInserted by unhooking a reference to it, from its parent. Then I reset the lastInserted field to a node that was inserted before. Also we must not forget to decrease the size of every node on the path from root to the deleted node by 1. Then I sink the root data down.
How insert() works:
I make a new root, if the priority queue is empty. If it’s not empty, I check the sizes of x.left and x.right, if x.left is bigger in size than x.right, I recursively call insert for x.right, else I recursively call insert for x.left. When a null node is reached I return new Node(data, 1). After all the recursive calls are done, I increase the size of all the nodes on the path from root to the newly inserted node.
Here are the pictures for insert():
And here's my java code:
public class LinkedPQ<Key extends Comparable<Key>>{
private class Node{
int N;
Key data;
Node parent, left, right;
public Node(Key data, int N){
this.data = data; this.N = N;
}
}
// fields
private Node root;
private Node lastInserted;
//helper methods
private int size(Node x){
if(x == null) return 0;
return x.N;
}
private void swim(Node x){
if(x == null) return;
if(x.parent == null) return; // we're at root
int cmp = x.data.compareTo(x.parent.data);
if(cmp > 0){
swapNodeData(x, x.parent);
swim(x.parent);
}
}
private void sink(Node x){
if(x == null) return;
Node swapNode;
if(x.left == null && x.right == null){
return;
}
else if(x.left == null){
swapNode = x.right;
int cmp = x.data.compareTo(swapNode.data);
if(cmp < 0)
swapNodeData(swapNode, x);
} else if(x.right == null){
swapNode = x.left;
int cmp = x.data.compareTo(swapNode.data);
if(cmp < 0)
swapNodeData(swapNode, x);
} else{
int cmp = x.left.data.compareTo(x.right.data);
if(cmp >= 0){
swapNode = x.left;
} else{
swapNode = x.right;
}
int cmpParChild = x.data.compareTo(swapNode.data);
if(cmpParChild < 0) {
swapNodeData(swapNode, x);
sink(swapNode);
}
}
}
private void swapNodeData(Node x, Node y){
Key temp = x.data;
x.data = y.data;
y.data = temp;
}
private Node insert(Node x, Key data){
if(x == null){
lastInserted = new Node(data, 1);
return lastInserted;
}
// compare left and right sizes see where to go
int leftSize = size(x.left);
int rightSize = size(x.right);
if(leftSize <= rightSize){
// go to left
Node inserted = insert(x.left, data);
x.left = inserted;
inserted.parent = x;
} else{
// go to right
Node inserted = insert(x.right, data);
x.right = inserted;
inserted.parent = x;
}
x.N = size(x.left) + size(x.right) + 1;
return x;
}
private Node resetLastInserted(Node x){
if(x == null) return null;
if(x.left == null && x.right == null) return x;
if(size(x.right) < size(x.left))return resetLastInserted(x.left);
else return resetLastInserted(x.right);
}
// public methods
public void insert(Key data){
root = insert(root, data);
swim(lastInserted);
}
public Key max(){
if(root == null) return null;
return root.data;
}
public Key delMax(){
if(size() == 1){
Key ret = root.data;
root = null;
return ret;
}
swapNodeData(root, lastInserted);
Node lastInsParent = lastInserted.parent;
Key lastInsData = lastInserted.data;
if(lastInserted == lastInsParent.left){
lastInsParent.left = null;
} else{
lastInsParent.right = null;
}
Node traverser = lastInserted;
while(traverser != null){
traverser.N--;
traverser = traverser.parent;
}
lastInserted = resetLastInserted(root);
sink(root);
return lastInsData;
}
public int size(){
return size(root);
}
public boolean isEmpty(){
return size() == 0;
}
}
I'm doing a homework assignment in Java where I have to create an unsorted binary tree with a String as the data value. I then have to write a function that replaces a Node and any duplicate Nodes that match an old description with a new object that contains a new description.
Here is the code that I am working with, including the test case that causes an infinite loop:
public class Node {
private String desc;
private Node leftNode = null;
private Node rightNode = null;
private int height;
public Node(String desc) {
this.desc = desc;
height = 0; // assumes that a leaf node has a height of 0
}
public String getDesc() {
return desc;
}
public Node getLeftNode() {
return leftNode;
}
public Node getRightNode() {
return rightNode;
}
public void setLeftNode(Node node) {
++height;
leftNode = node;
}
public void setRightNode(Node node) {
++height;
rightNode = node;
}
public int getHeight() {
return height;
}
public int addNode(Node node) {
if(leftNode == null) {
setLeftNode(node);
return 1;
}
if(rightNode == null) {
setRightNode(node);
return 1;
}
if(leftNode.getHeight() <= rightNode.getHeight()) {
leftNode.addNode(node);
++height;
} else {
rightNode.addNode(node);
++height;
}
return 0;
}
public static void displayTree(Node root) {
if(root != null) {
displayTree(root.getLeftNode());
System.out.println(root.getDesc());
displayTree(root.getRightNode());
}
}
public static Node findNode(Node current, String desc) {
Node result = null;
if(current == null) {
return null;
}
if(current.getDesc().equals(desc)) {
return current;
}
if(current.getLeftNode() != null) {
result = findNode(current.getLeftNode(), desc);
}
if(result == null) {
result = findNode(current.getRightNode(), desc);
}
return result;
}
public static void replaceNode(Node root, String oldDesc, String newDesc) {
if(oldDesc == null || newDesc == null) {
System.out.println("Invalid string entered");
return;
}
boolean replacedAllNodes = false;
while(replacedAllNodes == false) {
Node replace = findNode(root, oldDesc);
if(replace == null) { // No more nodes to replace
replacedAllNodes = true;
return;
}
replace = new Node(newDesc);
root.addNode(replace);
}
return;
}
public static void main(String[] args) {
Node root = new Node("test1");
Node test_2 = new Node("test2");
Node test_3 = new Node("test3");
Node test_4 = new Node("test4");
Node test_5 = new Node("test5");
Node test_6 = new Node("test6");
root.addNode(test_2);
root.addNode(test_3);
root.addNode(test_4);
root.addNode(test_5);
root.addNode(test_6);
displayTree(root);
replaceNode(root, "test4", "hey");
System.out.println("-------");
displayTree(root);
}
}
After testing the findNode method, and seeing that it returns the correct object, I realized that the infinite loop was being caused by my replaceNode method. I'm just not really sure how it is causing it.
I got it to work with one case by removing the while loop, but obviously that won't work for duplicates, so I'm wondering how I could remove the node with oldDesc and replace it with a new object that contains newDesc when there could be multiple objects with matching oldDesc data.
you are never changing root or oldDesc in your while loop
while(replacedAllNodes == false) {
Node replace = findNode(root, oldDesc);
if(replace == null) { // No more nodes to replace
replacedAllNodes = true;
return;
}
replace = new Node(newDesc);
root.addNode(replace);
}
If you watch
public static Node findNode(Node current, String desc) {
Node result = null;
if(current == null) {
return null;
}
if(current.getDesc().equals(desc)) {
return current;
}
if(current.getLeftNode() != null) {
result = findNode(current.getLeftNode(), desc);
}
if(result == null) {
result = findNode(current.getRightNode(), desc);
}
return result;
}
If the if(current.getDesc().equals(desc)) condition matches, replace will always be root so you are stuck in your while loop
Update:
If you dont necessarily have to replace the whole node, you could just update the description for your node at the end of your while loop.
instead of
replace = new Node(newDesc);
root.addNode(replace);
do something like:
root.setDesc(newDesc);
(of course you would have to create a setDesc() method first)
If you have to replace the whole object, you have to go like this:
Instead of
replace = new Node(newDesc);
root.addNode(replace);
do something like this:
replace = new Node(newDesc);
replace.setLeftNode(root.getLeftNode);
replace.setRightNode(root.getRightNode);
Plus you have to link the node that pointed to root so it points to replace like one of the following examples (depends on which side your root was of course):
nodeThatPointedToRoot.setLeftNode(replace);
nodeThatPointedToRoot.setRightNode(replace);
well looking at your code, you are not replacing a node you are just adding a new node to the edge of the tree and the old node would still be there so the loop will go forever and you can add a temp variable with an auto increment feature and to indicate the level of the node you are reaching to replace and you'll find it's just doing it again and again, instead of doing all this process how about just replacing the description inside that node ?
I'm trying to write code for a binary search tree, the first method I'm working on is the add (insert) method. The root seems to insert properly, but I'm getting null pointer exception when adding the second node. I'll indicate the exact problem spot in my code with comments.
If you can see how to fix the bugs, or let me know if my overall logic is flawed it would be incredibly helpful.-- I will mention that this is for school, so I'm not looking to make a really impressive model...most of my layout choices simply reflect the way we've been working in class. Also, method names were selected by the teacher and should stay the same. Feel free to edit the formatting, had a little trouble.
BINARY TREE CLASS
public class BinarySearchTree
{
private static Node root;
public BinarySearchTree()
{
root = null;
}
public static void Add (Node newNode)
{
Node k = root;
if (root == null)//-----------------IF TREE IS EMPTY -----------------
{
root = newNode;
}
else // -------TREE IS NOT EMPTY --------
{
if (newNode.value > k.value) //-------NEW NODE IS LARGER THAN ROOT---------
{
boolean searching = true;
while(searching) // SEARCH UNTIL K HAS A LARGER VALUE
{ //***CODE FAILS HERE****
if(k.value > newNode.value || k == null)
{
searching = false;
}
else {k = k.rightChild; }
}
if ( k == null) { k = newNode;}
else if (k.leftChild == null){ k.leftChild = newNode;}
else
{
Node temp = k.leftChild;
k.leftChild = newNode;
newNode = k.leftChild;
if(temp.value > newNode.value )
{
newNode.rightChild = temp;
}
else
{
newNode.leftChild = temp;
}
}
}
if (newNode.value < k.value) //-----IF NEW NODE IS SMALLER THAN ROOT---
{
boolean searching = true;
while(searching) // ----SEARCH UNTIL K HAS SMALLER VALUE
{// **** CODE WILL PROBABLY FAIL HERE TOO ***
if(k.value < newNode.value || k == null) {searching = false;}
else {k = k.leftChild;}
}
if ( k == null) { k = newNode;}
else if (k.rightChild == null){ k.rightChild = newNode;}
else
{
Node temp = k.rightChild;
k.rightChild = newNode;
newNode = k.rightChild;
if(temp.value > newNode.value )
{
newNode.rightChild = temp;
}
else
{
newNode.leftChild = temp;
}
}
}
}} // sorry having formatting issues
}
NODE CLASS
public class Node
{
int value;
Node leftChild;
Node rightChild;
public Node (int VALUE)
{
value = VALUE;
}
}
TEST APPLICATION
public class TestIT
{
public static void main(String[] args)
{
BinarySearchTree tree1 = new BinarySearchTree();
Node five = new Node(5);
Node six = new Node(6);
tree1.Add(five);
tree1.Add(six);
System.out.println("five value: " + five.value);
System.out.println("five right: " + five.rightChild.value);
}
}
The conditional statement is checked from left to right, so you need to check whether k is null before you check whether k.value > newNode.value because if k is null, then it doesn't have a value.