my question is how to transform this method from the trie class into a method of the node class that doesn't use the node as a parameter, I know that I have to make a first method on the tree like this:
public void remove(String key)
{
root = root.remove(key, 0);
}
But I don't know how to make the transformation of the method into the node class.
This is the method of the tree that I want to transform into a node method without using root as parameter of the method:
static TrieNode remove(TrieNode root, String key, int depth)
{
// If tree is empty
if (root == null)
return null;
// If last character of key is being processed
if (depth == key.length()) {
// This node is no more end of word after
// removal of given key
if (root.isEndOfWord)
root.isEndOfWord = false;
// If given is not prefix of any other word
if (isEmpty(root)) {
root = null;
}
return root;
}
// If not last character, recur for the child
// obtained using ASCII value
int index = key.charAt(depth) - 'a';
root.children[index] =
remove(root.children[index], key, depth + 1);
// If root does not have any child (its only child got
// deleted), and it is not end of another word.
if (isEmpty(root) && root.isEndOfWord == false){
root = null;
}
return root;
}
public TrieNode remove(String key, int depth)
{
// If last character of key is being processed
if (depth == key.length()) {
// This node is no more end of word after
// removal of given key
if (this.isEndOfWord)
this.isEndOfWord = false;
// If given is not prefix of any other word
if (isEmpty(this)) {
return null;
}
return this;
}
// If not last character, recur for the child
// obtained using ASCII value
int index = key.charAt(depth) - 'a';
this.children[index] =
this.children[index].remove(key, depth + 1);
// If root does not have any child (its only child got
// deleted), and it is not end of another word.
if (isEmpty(this) && this.isEndOfWord == false){
return null;
}
return this;
}
Related
In my program, I have initialized a binary tree and I want to search if a node exists in that binary tree. If it does exist, then I will print the subtree of that node and the level it was found. I am able to perform my search method but I am not sure how to print the subtree of that node found and its level.
For example, this is my binary tree [K=3 L=[K=1 R=[K=2]] R=[K=5 L=[K=4]]. If I search for node 1, then it will return the node (not null) since it exists in my binary tree.
Problem: I need to print only the subtree of the node and the level where it was found: [K=1 R=[K=2]], level=1.
Here is my source code for reference:
Main Class
// instantiate BST object
BST<Character> bst = new BST<>();
// insert values to bst1
String str = "31254";
char[] letter = str.toCharArray();
for (int i = 0; i < letter.length; i++) {
Character c = letter[i];
bst1.insert(c);
}
// print bst
System.out.println("\nht=" + bst1.height + " " + bst1.toString() + "\n");
// search values in bst1
String str2 = "016483";
char[] letter2 = str2.toCharArray();
for (int i = 0; i < letter2.length; i++) {
Character c = letter2[i];
if (bst1.search(c) != null) { // if found, print the node (w/ subtree) and its level
// ** part that should print the subtree and its level
}
else {
System.out.println(c + " is not found.");
}
}
BST Class - where my search method is declared
public class BST<T extends Comparable<T>> extends BT<T> {
// insert() method
// search method
public BTNode<T> search(T k) {// my method
BTNode<T> n = root;
while (n != null) {
if (n.info.compareTo(k) == 0) {
return n;
}
else {
if (n.info.compareTo(k) > 0) {
n = n.left;
}
else {
n = n.right;
}
}
}
return null;
}
}
Thanks in advance!
I did not modify your code. Instead, I used an imaginary class Node that I've written. Also, I have written all of them as half pseudo half java code.
Suppose your node has only one int type variable and two children.
class Node{
int data;
Node left;
Node right;
}
You have a printExistingSubTree method in your BST class that does the what you exactly ask for:
printExistingSubTree(Node node, int key):
if (find(node.left, key, 0) != -1)
then
printTree(node.left)
print(find(node.left, key, 0))
if (find(node.right, key, 0) != -1)
then printTree(node.right)
printTree(node.right)
print(find(node.right, key, 0))
You have a find method in your BST class that does find the index:
int find(Node node,int key, int level)
if(node.data is equal to the key)
then return level
int left = -1;
if(node.leftChild is not null)
then left = find(node.left, key, level+1)
if(left != -1)
return left
int right = -1;
if(node.rightChild is not null)
then right = find(node.right, key, level+1)
return right
Then, to print, you should decide how you want to traverse the subtree.
You have a printTree method in your BST class that prints the subtree in postorder:
void printTree(Node node){
if (node == null)
return;
printTree(node.left);
printTree(node.right);
print(node.data + " ");
}
Note: I did not understand your whole code. Therefore, I have just written the answer of your question in the pseudo code format. I think, you can write your own code from that.
Note2: There may be some typos&wrong namings. PLease do not lynch. Just write in the comments and I'll correct.
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.
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 making a binary search tree which is sorted by String key. Each node consists of an unordered linked list of information that is associated to a key. The tree is inorder (alphabetical).
I have completed most of the program, but having trouble with the remove method.
Essentially it has to be recursive. The method has to remove a node that has the given key, such that if "Architecture" was the String given, I must traverse through the tree and remove the corresponding node with "Architecture" as its key.
I am having trouble because I have to remove a String. Other assignments have used integers where I have to remove the highest or lowest value. However, I am not removing a node with the highest or lowest String value, but a node that equals to a specified String.
All I'm asking is how to go about this method. You don't have to provide any actual code if you choose not to, but some pointers or advise would be nice.
Thank you.
//My attempt:
//Removes node with corresponding k
public void remove(String k) {
rootNode = remove(rootNode, k);
}
//Recursive method:
private KeyNode remove(KeyNode x, String k) {
if (x == null) {
return x;
}
//int comparison with compareTo
//if less than 0, left node = remove(left node, k)
//if greater than 0, right node = remove(right node, k)
//if left node and right node are both null, return null
//if left node is null, return left node
//if right node is null, return right node
//return
}
you could do something like this
public rootNode remove (String k, rootNode n) {
if (n == null)
return null;
if (k.compareTo(n.key)<0)
remove (k, n.leftChild);
else if (k.compareTo(n.key)>0)
remove (k, n.rightChild);
else {
if (n.leftChild != null && n.rightChild != null) {
/* n has two children, find max from left then
* switch it with n and remove n */
}
else if(n.leftChild != null) {
/* n has a left child only then left child replaces n
* and n is deleted */
}
else if(n.rightChild != null) {
/* n has a right child only then right child replaces n
* and n is deleted*/
}
else {
n = null;
}
}
}
I'm trying to populate a binary search tree using an insert(), however when every I 'print' the contents of my BST, I only get the last item that was inserted into the BST. What do I need to fix to make sure all of my value are retaining in the BST?
From debuggin, I think that my problem is that my public void insert() is setting the new value to root evertime it is called. I don't know how to fix it?
Here is my BST CLass:
public class BinarySearchTree<T extends Comparable<T>> {
private class BinarySearchTreeNode<E>{
public BinarySearchTreeNode<E> left, right;
private E data;
private BinarySearchTreeNode (E data) {
this.data = data;
}
}
private BinarySearchTreeNode<T> root;
public boolean isEmpty() {
return root == null;
}
private BinarySearchTreeNode<T> insert(T value, BinarySearchTreeNode<T> ptr) {
if (ptr == null){
ptr = new BinarySearchTreeNode<>(value);
return ptr;
}
int compare = value.compareTo(ptr.data); //when ptr != null, this line and below should execute for each bstStrings.inster(x)
/* pass the value (s1...sN) when compared to (ptr.data) to compare
* when value and ptr.data == 0 re
*/
if (compare == 0) {
return ptr;
}
if (compare < 0) {
while (ptr.left != null){
ptr = ptr.left;
if (ptr.left == null) {//found insertion point
BinarySearchTreeNode<T> node = new BinarySearchTreeNode<>(value);
ptr = ptr.left;
ptr = node;
return ptr;
}
}
}
else {
return insert(value, ptr.left);
}
if (compare > 0) {
if (ptr.right == null) {
BinarySearchTreeNode<T> node = new BinarySearchTreeNode<>(value);
ptr = ptr.right;
ptr = node;
return ptr;
}
}
else {
return insert(value, ptr.right);
}
return ptr;
}
public void insert(T value) {
root = insert(value, root); //****Where I believe the problem is******
}
private void printTree(BinarySearchTreeNode<T>node){
if(node != null){
printTree(node.left);
System.out.println(" " + node.data);
printTree(node.right);
}
}
public void printTree(){
printTree(root);
System.out.println();
}
}
For added context here is my Main() where I am calling the insert() and trying to insert strings into the BST:
public class Main {
public static void main(String[] args) {
BinarySearchTree<String> bstStrings = new BinarySearchTree<String>();
String s = "Hello";
String s1 = "World";
String s2 = "This Morning";
String s3 = "It's";
bstStrings.insert(s);
bstStrings.insert(s1);
bstStrings.insert(s2);
bstStrings.insert(s3); //the only inserted value that is printed below
bstStrings.printTree();
System.out.println();
System.out.println("You should have values above this line!");
}
}
Lastly my console output:
It's
You should have values above this line!
Some hints:
I don't see any recursive calls inside insert. How would you traverse the BST without appropriate recursive calls (into the left or right subtree of the current node based on the value)? I do see some commented out code that looks like it would perform those calls. Why are they commented out?
You're returning the newly inserted node, which you're then setting as root. This will set the root to point to the new node every time. I don't think that's what you want.
If you're trying to handle the special case where the tree is empty, all you need to do is check to see if root is null, then set the new node to that.
There really is no need to return ptr. Since your BST maintains a reference to root, you always have a reference to the root of the tree. Every time you insert, you start with the root and then recursively traverse the tree until you find a suitable place to insert the new node. If you really must return the reference, then you most certainly should not be setting root to that new node!
Here is some pseudocode to help you out:
// Recursive function that inserts a value into a BST
function insert(node, value):
//Handles the case where you have no nodes in the tree, so root is null
if node is null:
node = new Node(value)
// If the value is lesser than the current node's value, we need to insert it
// somewhere in the right subtree
else if value < node.value:
if node.right is null:
// This node doesn't have a right child, so let's insert the new node here
node.right = new Node(value)
else:
// This node has a right child, so let's go further into this subtree to
// find the right place to insert the new node
insert(node.right, value)
// If the value is greater than the current node's value, we need to insert it
// somewhere in the left subtree
else if value > node.value:
if node.left is null:
// This node doesn't have a left child, so let's insert the new node here
node.left = new Node(value)
else:
// This node has a left child, so let's go further into this subtree to
// find the right place to insert the new node
insert(node.left, value)
else:
// A node with this value already exists so let's print out an erro
error("Node with that value already exists")
end function