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.
Related
The problem I'm having trouble with is this.
Each node is represented by two bits x1 and x2. If the node has a left
child, x1 is 1. If not, x1 is 0. Similarly for the case of a right
child, x2 can be either 1 or 0. With this rule, we can represent a
binary tree under a bit sequence formed by a preorder traversal. For
example, from "11010011001000", we can construct the following tree.
Write a recursive function that can take a certain bit sequence given
by a preorder traversal and construct a binary tree.
Now, I've been getting information from a similar question, Construct tree with pre-order traversal given, but it seems so different because in this case you have to consider both x1 and x2 for a single node... I've been thinking this for hours but I can't come up with a good logic using recursion. Any help would be appreciated. Thanks!
Before reaching 50 reputation I am putting this declaimer in the first line of my answers:
I want to make a brief response in comment instead, but I don't have enough reputation so I am making a full answer, hopefully my ill-formed answers would still help.
DFS is perfect for this task -- That's basically what pre-order traversal is doing:
def DFS(node):
if(node == NULL) return
sequence += notNull(node.l)
sequence += notNull(node.r)
DFS(node.l)
DFS(node.r)
^^^ This is how your sequence is constructed.
Fortunately the inverse is quite straight forward:
def inverseDFS(node):
if(node == NULL) return
node.l = new Node() if(readBuffer(sequence) == '1') else NULL
node.r = new Node() if(readBuffer(sequence) == '1') else NULL
inverseDFS(node.l)
inverseDFS(node.r)
^^^ Only line 2 and 3 is modified, now instead of determining the next character of the sequence by the existance of child, we can determine the existance of child based on the next character read, as this is an iff relationship.
Here is a more sophisicated C++ code, and yes, I know my coding style may disgust some others.
/* Author haleyk10198 */
/* FOR ACM-ICPC WF*/
#include <bits/stdc++.h>
using namespace std;
struct Node{
static int nodeCnt;
int id;
Node *l, *r;
Node(){
l = r = nullptr;
this->id = nodeCnt++;
}
friend ostream& operator<<(ostream&, const Node);
}*root = new Node();
ostream& operator<<(ostream &out, const Node node){
cout << "Node id: " << node.id
<< " | left child is " << (node.l? node.l->id: -1)
<< " | right child is " << (node.r? node.r->id: -1) << endl;
}
int Node::nodeCnt, strStreamPos = 0;
string str;
void dfs(Node *node){
if(not node)
return;
if(str[strStreamPos++] == '1')
node->l = new Node();
if(str[strStreamPos++] == '1')
node->r = new Node();
cout << *node << endl;
dfs(node->l);
dfs(node->r);
}
int main(){
cin >> str;
dfs(root);
return 0;
}
A solution could be just to traverse your tree in preorder meanwhile reading from your sequence (two values and remove them) and adding node where is necessary.
Given that you have this Node:
class Node {
int value;
public Node left;
public Node right;
}
You can create a tree like this:
private static void createTree(Node root) {
if(string.isEmpty() || root == null) {
return;
}
if(string.charAt(0) == '1') {
root.left = new Node();
}
if(string.charAt(1) == '1') {
root.right = new Node();
}
string = string.substring(2);
createTree(root.left);
createTree(root.right);
}
Where string is just a global variable: static String string = "11010011001000";
You can call the method like this:
Node root = new Node();
createTree(root);
root will be the actual root of your tree.
Your question looks likes this one:
http://www.geeksforgeeks.org/construct-a-special-tree-from-given-preorder-traversal/
I modified the given code a little to meet the specific requirements of your case. I neglected the given order of nodes (letters) in your question and just focused on the structure of the tree. The time complexity is O(N) as expected. Everything seems clear so I did not give further information. If you have any question, don't hesitate to leave comment.
public class BinaryTree {
class Node {
char data;
Node left, right;
Node(char item) {
data = item;
left = right = null;
}
}
class Index {
int index = 0;
}
Node root;
Index i = new Index();
Node constructTreeUtil(String bitSequence, Index index_ptr, int n, Node temp) {
int index = index_ptr.index;
String bits = bitSequence.substring(index * 2, index * 2 + 2);
if (index == n)
return null;
temp = new Node((char) (index + 65));
(index_ptr.index)++;
if (bits.charAt(0) == '1')
temp.left = constructTreeUtil(bitSequence, index_ptr, n, temp.left);
if (bits.charAt(1) == '1')
temp.right = constructTreeUtil(bitSequence, index_ptr, n, temp.right);
return temp;
}
Node constructTree(String bitSequence, int n, Node node) {
int index = 0;
return constructTreeUtil(bitSequence, i, n, node);
}
public static void inorder(Node node) {
if (node == null) return;
System.out.println(node.data + "=> ");
if (node.left != null)
System.out.println("Left node: " + node.left.data);
if (node.right != null)
System.out.println("Right node: " + node.right.data);
System.out.println();
inorder(node.left);
inorder(node.right);
}
public static void main(String args[]) {
BinaryTree tree = new BinaryTree();
// Bit sequence
String bitSequence = "11010011001000";
// Number of nodes
int n = bitSequence.length() / 2;
// Tree construction
Node node = tree.constructTree(bitSequence, n, tree.root);
// Print tree nodes inorder
inorder(node);
}
}
As for my question: I have a Node class:
public class Node<E> {
private E value;
private Node<E> left;
private Node<E> right;
public Node(E value) {
this.value = value;
this.left = null;
this.right = null;
}
and this class has two methods which calculate the depth of the node (binary tree). The method totaldepth() I wrote myself and it gives an incorrect answer, for which I need your help debugging. The method maxDepth(Node node) gives the correct answer and was used as reference material by me. Could you help me debug totalDepth method as to me it looks the same as maxDepthby the result.
incorrect code:
public int totalDepth() {
// initialize variabele depth
int depth = 0;
// reached leaf return 0
if (right == null && left == null) {
return 0;
}
// not yet reached leaf, continue deeper
else {
int leftdepth = 0;
int rightdepth = 0;
// left node is not null continue going left
if (left != null) {
leftdepth = left.totalDepth();
}
// right node is not null continue going right
if (right != null) {
rightdepth = right.totalDepth();
}
if (leftdepth > rightdepth) {
// 1 is needed because each call to totalDepth raises depth by 1
depth = leftdepth + 1;
}
else {
depth = rightdepth + 1;
}
}
return depth;
}
correct code:
public int maxDepth(Node node) {
if (node == null) {
return (0);
}
else {
// compute the depth of each subtree
int leftDepth = maxDepth(node.left);
int rightDepth = maxDepth(node.right);
// use the larger one
if (leftDepth > rightDepth)
return (leftDepth + 1);
else
return (rightDepth + 1);
}
}
Also I'm just starting to learn how to code so forgive me for all the inefficient things I'm doing. Thanks in advance for helping me!
Your totalDepth method will not work, because you have a tree, and you don't actually know, how many elements you have from the left and the right. Balanced this tree or not. So, only way to walk throw the tree, is to use Breadth-first search or Depth-first search algorithm, and they are based of recursion function like maxDepth(Node node) method.
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;
}
}
}
Many answers on the net for 'finding Least Common Ancestor in binary tree' and its supplementary question 'find distance between 2 nodes' have 4 issues:
Does not consider duplicates
Does not consider if input node is invalid/absent/not in tree
Use extra / aux storage
Not truncating the traversal although answer is obtained.
I coded this sample to overcome all handicaps. but since I did not find 'a single' answer in this direction, I would appreciate if my code has a significant disadvantage which I am missing. Maybe there is none. Additional eyeballs appreciated.
public int distance(int n1, int n2) {
LCAData lcaData = new LCAData(null, 0, 0);
int distance = foundDistance (root, lcaData, n1, n2, new HashSet<Integer>());
if (lcaData.lca != null) {
return distance;
} else {
throw new IllegalArgumentException("The tree does not contain either one or more of input data. ");
}
}
private static class LCAData {
TreeNode lca;
int count;
public LCAData(TreeNode parent, int count) {
this.lca = parent;
this.count = count;
}
}
private int foundDistance (TreeNode node, LCAData lcaData, int n1, int n2, Set<Integer> set) {
assert set != null;
if (node == null) {
return 0;
}
// when both were found
if (lcaData.count == 2) {
return 0;
}
// when only one of them is found
if ((node.item == n1 || node.item == n2) && lcaData.count == 1) {
// second element to be found is not a duplicate node of the tree.
if (!set.contains(node.item)) {
lcaData.count++;
return 1;
}
}
int foundInCurrent = 0;
// when nothing was found (count == 0), or a duplicate tree node was found (count == 1)
if (node.item == n1 || node.item == n2) {
if (!set.contains(node.item)) {
set.add(node.item);
lcaData.count++;
}
// replace the old found node with new found node, in case of duplicate. this makes distance the shortest.
foundInCurrent = 1;
}
int foundInLeft = foundDistance(node.left, lcaData, n1, n2, set);
int foundInRight = foundDistance(node.right, lcaData, n1, n2, set);
// second node was child of current, or both nodes were children of current
if (((foundInLeft > 0 && foundInRight > 0) ||
(foundInCurrent == 1 && foundInRight > 0) ||
(foundInCurrent == 1 && foundInLeft > 0)) &&
lcaData.lca == null) {
// least common ancestor has been obtained
lcaData.lca = node;
return foundInLeft + foundInRight;
}
// first node to match is the current node. none of its children are part of second node.
if (foundInCurrent == 1) {
return foundInCurrent;
}
// ancestor has been obtained, aka distance has been found. simply return the distance obtained
if (lcaData.lca != null) {
return foundInLeft + foundInRight;
}
// one of the children of current node was a possible match.
return (foundInLeft + foundInRight) > 0 ? (foundInLeft + foundInRight) + 1 : (foundInLeft + foundInRight);
}
The algorithm appears to be (without pulling it apart entirely) to exhaustively traverse the entire tree until a node is found where there is one node found on the left and one on the right. And creating an additional set as you go.
The problem here seems to be that your algorithm is very inefficient. That may fit your requirements, if this particular operation is almost never carried out. But normally you could do better.
In a school assignment I'm supposed to complete a method that should return an array of
node elements in ascendig order. The nodes are assembled in a binary search tree, so to sort them correct, I got a tip to create a recursive method to do the job.
The problem is that this doesn't even yield all the elements in the collection according to the test output (java.lang.AssertionError: toArray() does not return all the elements in the collection.)
I couldn't come up with any other way to deal with the array, and I'm not quite sure if the recursion even works. Any help is much appreciated.
Below is my code:
public class BinarySearchTree<E extends Comparable<E>> implements
IfiCollection<E> {
Node root;
Node current;
int size = 0;
int i = 0;
public class Node {
E obj;
Node left, right;
public Node(E e) {
obj = e;
}
} // END class Node
[...]
public E[] toArray(E[] a) {
Node n = root;
a = sort(n, a);
return a;
}
public E[] sort(Node n, E[] a) { //, int idx, E[] a) {
if (n.left != null) {
current = n.left;
sort(current, a);
}
a[i] = current.obj;
i++;
if (n.right != null) {
current = n.right;
sort(current, a);
}
return a;
} // END public Node sort
[...]
} // END class BinarySearchTree
Test output:
java.lang.AssertionError: toArray() does not return all the elements in the collection.: TestPerson("Bender").compareTo(TestPerson("Fry")) == 0 expected:true but was:false
at inf1010.assignment.IfiCollectionTest.assertCompareToEquals(IfiCollectionTest.java:74)
at inf1010.assignment.IfiCollectionTest.assertCompareToEquals(IfiCollectionTest.java:83)
at inf1010.assignment.IfiCollectionTest.assertCompareToEqualsNoOrder(IfiCollectionTest.java:100)
at inf1010.assignment.IfiCollectionTest.toArray(IfiCollectionTest.java:202)
protected void assertCompareToEquals(TestPerson actual,
TestPerson expected, String msg) {
assertTrue(actual.compareTo(expected) == 0, String.format( // l:74
"%s: %s.compareTo(%s) == 0", msg, actual, expected));
}
[...]
protected void assertCompareToEquals(TestPerson[] actual,
TestPerson[] expected, String msg) {
for (int i = 0; i < actual.length; i++) {
TestPerson a = actual[i];
TestPerson e = expected[i];
assertCompareToEquals(a, e, msg); // l:83
}
}
[...]
protected void assertCompareToEqualsNoOrder(TestPerson[] actual,
TestPerson[] expected, String msg) {
assertEquals(actual.length, expected.length, msg);
TestPerson[] actualElements = new TestPerson[actual.length];
System.arraycopy(actual, 0, actualElements, 0, actual.length);
TestPerson[] expectedElements = new TestPerson[expected.length];
System.arraycopy(expected, 0, expectedElements, 0, expected.length);
Arrays.sort(expectedElements);
Arrays.sort(actualElements);
assertCompareToEquals(actualElements, expectedElements, msg); // l:100
}
[...]
#Test(dependsOnGroups = { "collection-core" },
description="Tests if method toArray yields all the elements inserted in the collection in sorted order with smallest item first.")
public void toArray() {
TestPerson[] actualElements = c.toArray(new TestPerson[c.size()]);
for (int i = 0; i < actualElements.length; i++) {
assertNotNull(actualElements[i],
"toArray() - array element at index " + i + " is null");
}
TestPerson[] expectedElements = allElementsAsArray();
assertCompareToEqualsNoOrder(actualElements, expectedElements, // l:202
"toArray() does not return all the elements in the collection.");
Arrays.sort(expectedElements);
assertCompareToEquals(actualElements, expectedElements,
"toArray() does not return the elements in sorted order with "
+ "the smallest elements first.");
TestPerson[] inArr = new TestPerson[NAMES.length + 1];
inArr[NAMES.length] = new TestPerson("TEMP");
actualElements = c.toArray(inArr);
assertNull(actualElements[NAMES.length],
"The the element in the array immediately following the "
+ "end of the list is not set to null");
}
I don't know if I should post more of the test code, it's quite extensive, and it might be a little too much for one post?
Ok, I think the problem is your use of the "global" variable current. The way it is set, doesn't make much sense. You don't need to anyway, because the "current" Node is the one that is provided in the parameters.
Also you should consider renaming your function. You aren't sorting anything here, just collecting the contents of the tree, so a name such as collect would be more suitable.
public E[] toArray(E[] a) {
Node n = root;
a = collect(n, a);
return a;
}
public E[] collect(Node n, E[] a) {
if (n.left != null) {
// If there is a left (smaller) value, we go there first
collect(n.left, a);
}
// Once we've got all left (smaller) values we can
// collect the value of out current Node.
a[i] = n.obj;
i++;
if (n.right != null) {
// And if there is a right (larger) value we get it next
collect(n.right, a);
}
return a;
}
(Disclaimer: I haven't tested this)
Alternative implementation without the global index:
public E[] toArray(E[] a) {
Node n = root;
collect(n, a, 0);
return a;
}
public int collect(Node n, E[] a, int i) {
if (n.left != null) {
// If there is a left (smaller) value, we go there first
i = collect(n.left, a, i);
}
// Once we've got all left (smaller) values we can
// collect the value of out current Node.
a[i] = n.obj;
i++;
if (n.right != null) {
// And if there is a right (larger) value we get it next
i = collect(n.right, a, i);
}
return i;
}
I see you have the code
if (n.left != null) {
current = n.left;
sort(current, a);
}
but I can't seem to find at which point you set current back at the current node so that when you do
a[i] = current.obj;
you get the correct result. That's probably why you're not getting all the results. In any case I don't see (at least from the code fragments you have posted) why current needs to be a class variable and not just declared in the sort method. In general you shouldn't be using class variables if you don't really need them.
Edit:
You can either set current back to the node you are processing after calling sort on the left child like this
current = n;
a[i] = current.obj;
i++;
Or not use current at all in which case you'd have something like
if (n.left != null)
sort(n.left, a);
a[i] = n.obj;
i++;
if (n.right != null)
sort(n.right, a);
I think where you are confused is that if you check out how a binary search tree works, is that it is always sorted. You start at your root node, and then as you insert a new node, it inserts it into the appropriate position (i.e. to the left or the right) depending on the values. So you should not have to call sort to begin with. So I would start there, and read up on binary search trees. For example wikipedia has a decent article.
Update: Ignore my comment you should not need to do that either. Say you insert 8, 3, 7, 9, 12, 2, 10, 1 into the tree in that order. It should end up looking like this:
8
/ \
3 9
/ \ \
2 7 12
/ /
1 10
If you look at it that means to get them in order, start at the root, then if it has a node to the left got to the left, if not, return itself, and go to the right if it has a value. Repeating this for each node you encounter.
http://cs.armstrong.edu/liang/intro8e/html/BinaryTree.html
The easiest way to do what you are looking for is to traverse the tree inorder and append to an ArrayList. To get the array you can call the .toArray() method of the arrayList.
If you can't use an arraylist, declare an index and an array outside the inordertraversal and increment, you will need to know how many elements are in the tree to declare your array.
pseudo code:
variables:
arraysize = root.count()
E[] inOrderNodeArray = new E[arraysize]
int index = 0
inorder traversal:
void inorder(Node n) {
if (n) {
inorder(n.left)
inOrderNodeArray[index] = n
index++
inorder(n.right)
}
}