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;
}
}
}
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.
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;
}
As a homework assignment I'm suppose to return the position of the second to last occurrence of a letter--to know what letter to check it is passed as a Char type parameter. What I'm searching through is a self-coded linked list. It also has to be done recursively, which I've been struggling to fully understand. Here's what I've worked out so far.
Note: If a letter appears either 0 or 1 time, return -1.
E.g.
["ababcdefb"].positionOfSecondToLastOccurrence('b') == 3
static class Node {
public Node (char item, Node next) { this.item = item; this.next = next; }
public char item;
public Node next;
}
Node first;
public int positionOfSecondToLastOccurrence (char letter) {
if (first == null)
return -1;
return positionOfSecondToLastOccurrenceHelper(letter, first, 0);
}
private int positionOfSecondToLastOccurrenceHelper(char c, Node n, int pos) {
if (n.next == null)
return n.item;
return pos += compare(n.item, positionHelper(c, n.next, pos));
}
private int compare(char c, int p) {
int result = 0;
if (c == p)
return result += 1;
return 0;
}
I understand why this isn't working; I'm returning a result of 1 and then comparing it to n.item when going back to the previous function call, which will never be true. What I don't know is how to make this work. Any guidance would be awesome.
You are using a singly-linked list, which means you can only traverse it in one direction, namely forward, i.e. from the first node to the last node.
The algorithm is then to traverse the list from first node to last node and compare each node's item with the item you are searching for. Also you need two variables that will hold the index in the list of both the last (i.e. ultimate) and the second last (i.e. penultimate) occurrences of the item you are searching for. Both these variables should have initial values of -1 (minus one).
When you hit the first occurrence of the searched for item, update the ultimate index variable. When you hit the next occurrence, set the penultimate index to the ultimate index and then update the ultimate index.
Repeat for every subsequent occurrence of the searched for item, i.e. set the penultimate index to the ultimate index and then set the ultimate index to the index of the current node in the list. Hence if the searched for item occurs only once in the list, or does not occur at all, the penultimate index will be -1.
When writing a recursive method, the first thing you need is some condition that will terminate the recursion. If the condition is true, return an appropriate value. If the condition is false, change the method arguments and recall the same method with the modified arguments. The terminating condition in your case is a null node.
Since a list is not an array, you also need to track the index of the current node, so as to be able to return it from your recursive method.
Here is my implementation. I created a LinkList class which contains a list of your Node class. The LinkList class allows me to initially create a linked list. I also added method toString() to both Node and LinkList classes to help visualize what the list looks like. The main() method serves as a test of the recursive method. The first invocation of the recursive method uses the first node in the list, whose index is 0 (zero).
public class Penultim {
public static void main(String[] args) {
LinkList list = new LinkList();
list.append('a');
list.append('b');
list.append('a');
list.append('b');
list.append('c');
list.append('d');
list.append('e');
list.append('f');
list.append('b');
System.out.println(list);
System.out.println(list.getPenultimateOccurrenceIndex('b', list.getHead(), 0, -1, -1));
}
}
class Node {
private char item;
private Node next;
public Node(char item, Node next) {
this.item = item;
this.next = next;
}
public char getItem() {
return item;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
public String toString() {
return item + "->";
}
}
class LinkList {
private Node head;
public void append(char item) {
if (head == null) {
head = new Node(item, null);
}
else if (head.getNext() == null) {
head.setNext(new Node(item, null));
}
else {
Node node = head.getNext();
while (node != null) {
if (node.getNext() == null) {
node.setNext(new Node(item, null));
break;
}
node = node.getNext();
}
}
}
public Node getHead() {
return head;
}
public int getPenultimateOccurrenceIndex(char item,
Node node,
int ndx,
int penultimate,
int ultimate) {
if (node == null) {
return penultimate;
}
else {
if (node.getItem() == item) {
if (ultimate >= 0) {
penultimate = ultimate;
}
ultimate = ndx;
}
return getPenultimateOccurrenceIndex(item,
node.getNext(),
ndx + 1,
penultimate,
ultimate);
}
}
public String toString() {
StringBuilder sb = new StringBuilder();
Node node = head;
while (node != null) {
sb.append(node);
node = node.getNext();
}
return sb.toString();
}
}
The output when running the above code is
a->b->a->b->c->d->e->f->b->
3
I’d do this in smaller steps. I’d start by writing a positionOfLastOccurrence(char letter). Writing this as a recursive method should teach you some of the technique that you will also need for positionOfSecondToLastOccurrence().
Next much of the challenge is in a good design of the helper method or methods. I think that I’d write a positionOfLastOccurrenceBeforePosition(int pos, char letter) that should return the position of the last occurrence of letter strictly before position pos. So given your example list, ababcdefb, positionOfLastOccurrenceBeforePosition(0, 'b') would return -1, positionOfLastOccurrenceBeforePosition(2, 'b') would yield 1 and positionOfLastOccurrenceBeforePosition(100, 'b') would give 8. This method too should be recursive, I believe, since this will the one doing the actual work in the end.
Now finding the second last occurrence is a matter of first finding the last occurrence and then finding the last occurrence before that one.
I'm looking at two solutions to find the first common ancestor of two nodes in a binary tree (not necessarily a binary search tree). I've been told the second solution provides a better worst-case run time, but I can't figure out why. Can someone please enlighten me?
Solution 1:
Find the depth of each of the two nodes: p,q
Calculate the delta of their depths
Set a pointer at the shallower node a pointer a the deeper node
Move the deeper node pointer up by the delta so we can start traversing from the same height
Recursively visit the part nodes of both pointers until we arrive at the same node which is out the first common ancestor
import com.foo.graphstrees.BinaryTreeNodeWithParent;
/*
Find the first common ancestor to 2 nodes in a binary tree.
*/
public class FirstCommonAncestorFinder {
public BinaryTreeNodeWithParent find(BinaryTreeNodeWithParent p, BinaryTreeNodeWithParent q) {
int delta = depth(p) - depth(q);
BinaryTreeNodeWithParent first = delta > 0 ? q: p; // use shallower node
BinaryTreeNodeWithParent second = delta > 0 ? p: q; //use deeper
second = goUp(second, delta); // move up so they are level, if 1 node is deeper in the tree than the other, their common ancestor obviously cannot be below the shallower node, so we start them off at the same height in the tree
//keep going up the tree, once first == second, stop
while(!first.equals(second) && first !=null && second !=null) {
first = first.getParent();
second = second.getParent();
}
return first == null || second == null ? null : first;
}
private int depth(BinaryTreeNodeWithParent n) {
int depth = 0;
while (n != null) {
n = n.getParent();
depth++;
}
return depth;
}
private BinaryTreeNodeWithParent goUp(BinaryTreeNodeWithParent node, int delta) {
while (delta > 0 && node != null) {
node = node.getParent();
delta--;
}
return node;
}
}
Solution 2:
Verify both nodes (p,q) exist in the tree starting at the root node
Verify that q is not a child of p and p is not a child of q by traversing their subtrees
Recursively examine subtrees of successive parent nodes of p until q is found
import com.foo.graphstrees.BinaryTreeNodeWithParent;
public class FirstCommonAncestorImproved {
public BinaryTreeNodeWithParent find(BinaryTreeNodeWithParent root,
BinaryTreeNodeWithParent a,
BinaryTreeNodeWithParent b) {
if (!covers(root, a) || !covers(root, b)) {
return null;
} else if (covers(a, b)) {
return a;
} else if (covers(b, a)) {
return b;
}
var sibling = getSibling(a);
var parent = a.getParent();
while (!covers(sibling, b)) {
sibling = getSibling(parent);
parent = parent.getParent();
}
return parent;
}
private BinaryTreeNodeWithParent getSibling(BinaryTreeNodeWithParent node) {
if (node == null || node.getParent() == null) return null;
var parent = node.getParent();
return node.equals(parent.getLeft()) ? node.getRight() : node.getLeft();
}
private boolean covers(BinaryTreeNodeWithParent root,
BinaryTreeNodeWithParent node) {
if (root == null) return false;
if (root.equals(node)) return true;
return covers(root.getLeft(), node) || covers(root.getRight(), node);
}
}
It depends on the structure of the problem.
If the starting nodes are deep in a big tree, and the ancestor is close by, then the first algorithm will still need to traverse the entire path to the root to find the depths. The second will succeed by inspecting only a small subtree.
On the other hand, if the nodes are deep and the common ancestor is very near the root, then the first will only traverse two paths to the root, while the second may explore the entire tree.
Note that as is often the case you can get an asymptotically faster algorithm by trading space for speed. Maintain a set of nodes. Traverse upward in alternating steps from both starting nodes, adding to the set until you find one that's already there. That's the common ancestor. Given the set operations are O(1), this algorithm is O(k) where k is the path length from the common ancestor to the most distant start node. You can't do better.
Set<Node> visited = new HashSet<>();
while (a != null && b != null) {
if (visited.contains(a)) return a;
if (visited.contains(b)) return b;
visited.add(a);
visited.add(b);
a = a.parent();
b = b.parent();
}
while (a != null) {
if (visited.contains(a)) return a;
a = a.parent();
}
while (b != null) {
if (visited.contains(b)) return b;
b = b.parent();
}
return null;
I am struggling to figure out how to code a recursive algorithm to count the number of leaves in a Binary Tree (not a complete tree). I get as far as traversing to the far most left leaf and don't know what to return from there. I am trying to get the count by loading the leaves into a list and getting the size of that list. This is probably a bad way to go about the count.
public int countLeaves ( ) {
List< Node<E> > leafList = new ArrayList< Node<E> >();
//BinaryTree<Node<E>> treeList = new BinaryTree(root);
if(root.left != null)
{
root = root.left;
countLeaves();
}
if(root.right != null)
{
root = root.right;
countLeaves();
}
if(root.left == null && root.right == null)
{
leafList.add(root);
}
return();
}
Elaborating on #dasblinkenlight idea. You want to recursively call a countleaves on root node & pass back the # to caller. Something on the following lines.
public int countLeaves() {
return countLeaves(root);
}
/**
* Recursively count all nodes
*/
private static int countLeaves (Node<E> node) {
if(node==null)
return 0;
if(node.left ==null && node.right == null)
return 1;
else {
return countLeaves(node.left) + countLeaves(node.right);
}
}
Edit: It appears, a similar problem was previously asked counting number of leaf nodes in binary tree
The problem with your implementation is that it does not restore the value of member variable root back to the state that it had prior to entering the method. You could do it by storing the value in a local variable, i.e.
Node<E> oldRoot = root;
... // your method goes here
root = oldRoot;
However, a better approach is to take Node<E> as an argument, rather than relying on a shared variable:
public int countLeaves() {
return countLeaves(root);
}
private static int countLeaves (Node<E> node) {
... // Do counting here
}