I'm having some trouble with my code.
This function's purpose is to traverse through a binary tree and edit it such that branches from a certain point are replaced by new ones housed under the "newNode". Currently, it returns the same value for the tree that it started with (so the current = newNode doesn't actually edit the original tree).
Can anyone explain why this is? Thanks.
public static Node editTree(Node current, Node newNode, String value) {
if (current == null) {
return null;
}
if (current.value.equals(value)) {
current = newNode;
return current;
}
if (!current.isLeaf()) {
editTree(current.getLeft(), newNode, value);
editTree(current.getRight(), newNode, value);
return current;
}
return current;
}
This has to be accomplished in such a way that a tree (the original tree) is first traversed until a certain value is found. Then the node that houses the value is entirely replaced with a new node, which contains its own value and its own left and right nodes. A global variable Node is then set to be equal to the value of the newly edited tree, which is then used to reset the original trees value. The reason it can't be done any other way is because I can't set the values of the left and right nodes in the node class, since it's not permitted.
In the line current = newNode; you are just changing the reference of the current variable in your method. It won't affect the original tree. You need to set newNode as a value to the previous node.
For more information, see Is Java “pass-by-reference” or “pass-by-value”?
Assigning a new value to current will have no effect outside of the method. I think you should use the return value:
public static Node editTree(Node current, Node newNode, String value) {
if (current == null) {
return null;
}
if (current.value.equals(value)) {
return newNode;
}
if (!current.isLeaf()) {
current.setLeft(editTree(current.getLeft(), newNode, value));
current.setRight(editTree(current.getRight(), newNode, value));
}
return current;
}
UPDATE: Complete code, and test results
public class Node {
public final String value;
private Node left;
private Node right;
Node(String value, Node left, Node right) {
this.value = value;
this.left = left;
this.right = right;
}
public Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
public boolean isLeaf() {
return left == null && right == null;
}
#Override
public String toString() {
return "Node{" + "value=" + value + ", left=" + left + ", right=" + right + '}';
}
}
Test method:
public static void main(String[] args) {
Node tree = new Node("b",
new Node("a", null, null), new Node("c", null, null));
System.out.println(tree);
tree = editTree(tree, new Node("d", null, null), "c");
System.out.println(tree);
}
Results:
Node{value=b, left=Node{value=a, left=null, right=null}, right=Node{value=c, left=null, right=null}}
Node{value=b, left=Node{value=a, left=null, right=null}, right=Node{value=d, left=null, right=null}}
Related
I am trying to create a class iNode that implements an Iterator to traverse a Binary Search Tree. The Iterator searches in a PreOrder traversal and can pick from any node in a tree, this node has the value of the int value.
I am familiar with using Stacks on BSTs, but am having a bit of trouble with the Iterator's hasNext() and next() methods.
I understand that logically, hasNext must check the current iNode and see if it has children. Then while that is true, the next() function will iterate through the tree starting with the "root" or value, then favoring the left children, and finally the right children. I believe that this is a simple matter of syntax and would greatly appreciate a few tips.
Expected behavior:
should return an Iterable (type Integer) of [8,3,5,6,4,2]
import java.util.Iterator;
import java.util.NoSuchElementException;
public class iNode implements Iterable<Integer> {
public final Integer value;
public final iNode left, right;
public iNode(Integer value) {
this.value = value;
this.right = null;
this.left = null;
// a node with no children / root
}
public iNode(Integer value, iNode left, iNode right) {
this.value = value;
this.left = left;
this.right = right;
// with children
}
#Override
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
private iNode next = new iNode(value, left, right);
#Override
public boolean hasNext() {
// should return false when the current node has no children
return next != null;
}
#Override
public Integer next() {
if (!hasNext()) {
throw new NoSuchElementException("limit reached");
}
return next.value;
}
};
}
}
private static void printPreOrder(Node root) {
if(root == null) {
return;
}
System.out.println(root.value + "->");
printPreOrder(root.left);
printPreOrder(root.right);
}
Let recursion handle this . Just write a base case where the node is null.
private static void printPreOrder(Node root, List<Integer> list) {
if(root == null) {
return;
}
list.add(root.value);
printPreOrder(root.left);
printPreOrder(root.right);
}
Iterator<Integer> itr = list.iterator();
while(itr.hasNext()){
int ele = itr.next();
// print element
}
if you want to store them and then use a iterator to iterate the list.
You can still use a Stack when using an iterator. Iterators are supposed to have state so that they know at which point they are at.
// to record how deep in the tree we are at
// this stores the next nodes to visit
// obviously, start with the current node, "this"
private final Deque<iNode> stack = new ArrayDeque<>(List.of(iNode.this));
#Override
public boolean hasNext() {
return !stack.isEmpty(); // has next, iff there are next nodes to visit
}
#Override
public Integer next() {
// pop will throw NSEE if the stack is empty anyway,
// so you don't need to explicitly throw one,
// unless you want a custom message of course
iNode node = stack.pop(); // we are going to return the value of this later
// the next node to visit is the left node, then the right node
// so we should push the right node first, then the left node,
// which causes the left node to be popped *first*
if (node.right != null) stack.push(node.right);
if (node.left != null) stack.push(node.left);
return node.value;
}
Example usage:
var tree = new iNode(
8, new iNode(
3, new iNode(5), new iNode(6)
), new iNode(
4, null, new iNode(2)
)
);
for (var i : tree) {
System.out.println(i);
}
/*
8
3
5
6
4
2
*/
I have a binary tree like the picture below, I want to implement a method called findNode to return the node holding the value entered as a parameter.
For example: findNode(8)=8, findNode(13)=13.
I tried to modify this code but it didn't working :
class Node {
Node left, right;
int value;
public Node findNode(int value) {
Node focusNode = root;
if (focusNode == null) {
return null;
}
while (focusNode.value != value) {
// If we should search to the left
if (value < focusNode.value) {
// Shift the focus Node to the left child
focusNode = focusNode.left;
} else {
// Shift the focus Node to the right child
focusNode = focusNode.right;
}
return focusNode;
}
}
}
See if this helps. You can't default to left or right but need to check them explicitly. The null situation is taken care of by the while loop.
public Node findNode(int value) {
Node focusNode = root;
while (focusNode != null) {
// If we should search to the left
if (value < focusNode.value) {
// Shift the focus Node to the left child
focusNode = focusNode.left;
} else if (value > focusNode.value) {
// Shift the focus Node to the right child
focusNode = focusNode.right;
} else {
// Found!!
return focusNode;
}
}
return null;
}
Here's a cleaner approach:
class Node {
Node left, right;
int value;
public static Node findNode(Node current, int value) {
if (current == null)
return null;
if (current.value == value)
return current;
if (current.value < value)
return findNode(current.left, value);
else
return findNode(current.right, value);
}
}
your root is either not defined or null every time.
below code would work as expected.
class Node
{
int value;
Node left, right;
public Node(int item)
{
value = item;
left = right = null;
}
}
public class BinaryTree {
Node root;
public Node findNode(int value) {
Node focusNode = root;
if (focusNode == null){
return null;
}
while (focusNode.value!= value) {
// If we should search to the left
if (value< focusNode.value) {
// Shift the focus Node to the left child
focusNode = focusNode.left;
} else {
// Shift the focus Node to the right child
focusNode = focusNode.right;
}
}
return focusNode;
}
I have written a code to insert an element in a binary tree in java. Here are the functions to do the same:
public void insert(int data)
{
root = insert(root, data);
}
private Node insert(Node node, int data)
{
if (node == null)
node = new Node(data);
else
{
if (node.getRight() == null)
node.right = insert(node.right, data);
else
node.left = insert(node.left, data);
}
return node;
}
However when I traverse the tree, the answer I get is wrong. Here are the traversal functions (preorder):
public void preorder()
{
preorder(root);
}
private void preorder(Node r)
{
if (r != null)
{
System.out.print(r.getData() +" ");
preorder(r.getLeft());
preorder(r.getRight());
}
}
Okay so as suggested here's the definition for the Node class:
public class Node {
public int data;
public Node left, right;
/* Constructor */
public Node() {
left = null;
right = null;
data = 0;
}
/* Constructor */
public Node(int d, Node l, Node r) {
data = d;
left = l;
right = r;
}
//Constructor
public Node(int d) {
data = d;
}
/* Function to set link to next Node */
public void setLeft(Node l) {
left = l;
}
/* Function to set link to previous Node */
public void setRight(Node r) {
right = r;
}
/* Function to set data to current Node */
public void setData(int d) {
data = d;
}
/* Function to get link to next node */
public Node getLeft() {
return left;
}
/* Function to get link to previous node */
public Node getRight() {
return right;
}
/* Function to get data from current Node */
public int getData() {
return data;
}
}
I have re-checked the algorithm for traversal many times, and it's working perfectly. I believe the problem is in the insertion algorithm. Any suggestions?
If I understood correctly, you want to fill your binary tree in "layers". E.g. you want to put something into depth 4 only if depth 3 is "full binary tree".
Then the problem is whole logic of your insert algorithm that is DFS-based. In other words it inserts elements deeper and deeper on the one side instead of building full binary tree on both sides.
If you look closer to your insert algorithm you will see that once you skip "right" subtree, you will never return to it - even if the "left" subtree is already full binary tree. That leads to the tree that will be growing deeper and deeper on the left side but not growing on the right side.
Speaking in programming language. You do:
(node.right != null) && (node.left != null) => insert (node.left)
but you can't do this (start inserting node.left). What if node.left has both children and node.right has no children? You will attempt to insert to the left even you should do it in node.right.
So what you really need to do insertion BFS-based. That means you will traverse the tree for insertion "in layers". Queue should be your new friend here:-) (not the stack/recursion):
public void insert(int data) {
if (root == null) {
root = new Node(data);
return;
}
Queue<Node> nodesToProcess = new LinkedList<>();
nodesToProcess.add(root);
while (true) {
Node actualNode = nodesToProcess.poll();
// Left child has precedence over right one
if (actualNode.left == null) {
actualNode.left = new Node(data);
return;
}
if (actualNode.right == null) {
actualNode.right = new Node(data);
return;
}
// I have both children set, I will process them later if needed
nodesToProcess.add(actualNode.left);
nodesToProcess.add(actualNode.right);
}
}
Your method returns given node, but your method has to return inserted node which is node.right or node.left
I am in the process of creating a binary tree for a project I've been working on where I insert people into a binary tree by name (the tree iterates through each character to determine which is bigger when inserting). Is there a way to make my tree search through the tree to find a person who match the name given to the program. This is my code so far
lass Node {
private String person;
private Node left;
private Node right;
public Node(String person) {
this.person = person;
left = null;
right = null;
}
//setters
protected void setLeft(Node left) {
this.left = left;
}
protected void setRight(Node right) {
this.right = right;
}
//getters
protected String getPerson() {
return person;
}
protected Node getLeft() {
return left;
}
protected Node getRight() {
return right;
}
}
public class BinaryTree {
private static Node root;
public BinaryTree() {
root = null;
}
public void insert(String person) {
root = insert(person, root);
}
//Check if node is leaf
public static boolean isLeaf() {
if(root.getLeft() == null && root.getRight() == null)
return false;
else
return true;
}
// Search tree for entered value
public static void searchTree(String search, Node tNode) {
// Not sure what to put into the part to make the method search through people in the tree
}
private Node insert(String person, Node tree) {
if(tree == null)
tree = new Node(person);
else {
int count = 1;
int x = 0;
while(person.toLowerCase().charAt(x) == tree.getPerson().toLowerCase().charAt(x) && count != tree.getPerson().length()) {
count = count + 1;
x = x + 1;
}
if(person.toLowerCase().charAt(x) != tree.getPerson().toLowerCase().charAt(x)) {
if(person.toLowerCase().charAt(x) < tree.getPerson().toLowerCase().charAt(x))
tree.setLeft(insert(person, tree.getLeft()));
else
tree.setRight(insert(person, tree.getRight()));
} else {
tree.setRight(insert(person, tree.getRight()));
}
}
return tree;
}
Can you please suggest how I should create a method to search through the tree
I Would suggest you to do these steps. These steps will give you a start.
Start from root and compare the Name to be searched with root using compareToIgnoreCase().
Depending upon the result move left or right.
Continue till either node becomes null or you find a match.
If you're trying to implement a binary search tree, you need to change the code in your setters to determine whether to add a person to the left or right node (by comparing the strings lexicographically) every time those methods are called. If the tree is not ordered, you'd have to search every node. When it's ordered, you'll be able to search in log n time.
I got an insert method and a search method, and I was thinking of a way to loop through the binary search tree and use a method like get nodes then search for it on the other binary search tree and if it comes true then I insert it that element, but the problem is I can't come up with a way to get the nodes based on index because its different than linkedList for example and can't think of a way to get the nodes to begin with; to sum up, I actually don't the proper way to start to solve that question.
public class BinarySearchTree extends BinaryTree {
//default constructor
//Postcondition: root = null;
public BinarySearchTree() {
super();
}
//copy constructor
public BinarySearchTree(BinarySearchTree otherTree) {
super(otherTree);
}
public class BinaryTree {
//Definition of the node
protected class BinaryTreeNode {
DataElement info;
BinaryTreeNode llink;
public DataElement getInfo() {
return info;
}
public BinaryTreeNode getLlink() {
return llink;
}
public BinaryTreeNode getRlink() {
return rlink;
}
BinaryTreeNode rlink;
}
protected BinaryTreeNode root;
//default constructor
//Postcondition: root = null;
public BinaryTree() {
root = null;
}
//copy constructor
public BinaryTree(BinaryTree otherTree) {
if (otherTree.root == null) //otherTree is empty
{
root = null;
} else {
root = copy(otherTree.root);
}
}
public BinaryTreeNode getRoot() {
return root;
}
public boolean search(DataElement searchItem) {
BinaryTreeNode current;
boolean found = false;
current = root;
while (current != null && !found) {
if (current.info.equals(searchItem)) {
found = true;
} else if (current.info.compareTo(searchItem) > 0) {
current = current.llink;
} else {
current = current.rlink;
}
}
return found;
}
public int countEven() {
return countEven(root);
}
public void insert(DataElement insertItem) {
BinaryTreeNode current;
BinaryTreeNode trailCurrent = null;
BinaryTreeNode newNode;
newNode = new BinaryTreeNode();
newNode.info = insertItem.getCopy();
newNode.llink = null;
newNode.rlink = null;
if (root == null) {
root = newNode;
} else {
current = root;
while (current != null) {
trailCurrent = current;
if (current.info.equals(insertItem)) {
System.out.println("The insert item is already in" + "the list -- duplicates are" + "not allowed.");
return;
} else if (current.info.compareTo(insertItem) > 0) {
current = current.llink;
} else {
current = current.rlink;
}
}
if (trailCurrent.info.compareTo(insertItem) > 0) {
trailCurrent.llink = newNode;
} else {
trailCurrent.rlink = newNode;
}
}
}
Traverse down to the left end of one tree, compare it with the root node of the other tree. If found equal, insert it into your third tree. If unequal, then check if it's less than or greater than the root of second tree. If less than, then traverse to the left child of the second tree and call your search method again, else, traverse to the right child of the second tree and call your search method again. Then repeat the whole process with the right node of the opposing starting node of first tree that you chose and call the search method again. Keep moving up the first tree as you repeat the process.
Here's a sample code(keeping in mind you have not provided any details about your trees whatsoever):
void search(Node node1, Node root2){
if(root2 == null)
return;
if(node1.data == root2.data){
//copy to your third tree
return;
}
else{
if(node1.data < root2.data){
root2 = root2.left;
search(node1, root2);
}
else{
root2 = root2.right;
search(node1, root2);
}
}
}
void common(Node root1, Node root2){
if(root1 != null){
common(root1.left, root2);
search(root1, root2);
common(root1.right, root2);
}
}
I'm assuming you need to modify the BinarySearchTree class, so the following is written with that assumption.
You can traverse the tree by first calling getRoot() which will return the root of the tree (a BinaryTreeNode) then access the nodes' left and right children by calling getLLink() and getRLink(), respectively. From each node you can get its value via getInfo that you can search for in the other tree (by calling the search() method on the second tree).
Note: as it is, you can only call methods on the nodes from within methods of BinarySearchTree as access to BinaryTreeNode is restricted to BinaryTree and classes deriving from it (for which BinarySearchTree qualifies)