Properly deleting a node in a Ternary Search Tree - java

I want to delete a specific node using a key from a Ternary Search Tree. This works pretty well in most cases, but in some of my test sets, nodes that do not have a middle child also do not store values, which shouldn't happen.
I tried different methods I found online, but pretty much all of those few leave the tree in a dirty state, which makes searching a hassle, since you need to check if the leaf you found actually has a value, which shouldn't happen.
Here is my relevant code
private boolean hasChildren(Node x) {
return (x.left != null || x.mid != null || x.right != null);
}
private void reHang(Node x) {
if (hasChildren(x)) {
if (x.left != null) {
x.parent.mid = x.left;
x.left.right = x.right;
} else if (x.right != null) {
x.parent.mid = x.right;
}
}
}
private boolean remove(Node x, String key, int d) {
if (x == null) return false;
char c = key.charAt(d);
if (c < x.c) {
if (!remove(x.left, key, d)) {
x.left = null;
}
} else if (c > x.c) {
if (!remove(x.right, key, d)) {
x.right = null;
}
} else if (d < key.length() - 1) {
if (!remove(x.mid, key, d + 1)) {
x.mid = null;
if (x.val != null) return true;
}
} else {
x.val = null;
}
reHang(x);
return hasChildren(x);
}
private class Node
{
private Value val;
private char c;
private Node left, mid, right, parent;
}
Specifically, problems occur in this function I use for prefix lookups:
private Node getMidPath(Node x) {
if (x.left != null) return getMidPath(x.left);
if (x.mid == null) return x;
return getMidPath(x.mid);
}
Every Node that does not have a x.mid should have an x.val set, which is not always the case after remove, meaning I have dirty nodes.
Any help would be greatly appreciated.

You must see a ternary tree at was it is: Some nested Binary tree but witch each level have only on character as key instead of the whole string. Go down you binary trees until you string is exhausted. Here you will have two eventually references one to the actual data and and one two the actual subtree for longer string with same prefix. Now set the data to null. When the subtree reference is null remove the node. When now the entire subtree is empty continue with the subtree one character earlier. Here set subtree reference to null. Now is both references are null remove the node. When now the entire subtree is empty continue with the subtree one character earlier. And so on

Related

Insert into BST with recursion in java

New to Java. I learned BST tree insertion before with C++. But I try to replicate its recursive logic with Java like below:
public void tree_insert(Node x, int k) {
if (x == null)
x = new Node(k);
else if (k < x.val)
tree_insert(x.left, k);
else
tree_insert(x.right, k);
}
Suppose I have an empty tree
tree_insert(tree.root, 1);
But the root has not been changed.... I am guessing it may have to to with pass by reference in Java. But I am not exactly sure why it does not work. Some hint? Thanks.
What you are trying to do is assign a Node that has been passed by reference a new value. You already noted this and that is correct (I see that others stated this too).
How you would do this in java is by splitting up the recursion into two steps. EDIT: Not necessarily in java, but helper functions can be a good design to have in mind.
Introduce the insert function which null checks the root.
Private helper method that can generalise the insertion in the tree with recursive calls.
Here is an example:
public boolean insertBST(int value) {
if (root == null) {
root = new Node(value);
return true;
}
return insertBSTHelper(value, root);
}
private boolean insertBSTHelper(int value, Node node) {
if (node.value == value){
return false;
}
if (node.value > value){
if (node.left != null) {
return insertBSTHelper(value, node.left);
} else {
node.left = new Node(value);
return true;
}
} else {
if (node.right != null) {
return insertBSTHelper(value, node.right);
} else {
node.right = new Node(value);
return true;
}
}
}
Since there can only exist distinct elements in a BST, we check for these to ensure that we don't insert the same element twice.
Hope this helps!

Searching a Tree for a certain value

I need help searching a binary tree with int data(not necessarily binary search tree) and see if an element is in the tree. If it is in the tree return the reference and if it is not found return null. This is the code I have so far.
Node search(TreeNode root, int key){
if(root == null){
return null;
}
search(root.left, key);
search(root.right, key);
if(root.right.data === key || root.left.data == key){
return root;
}else{
return null;
}
}
You call search(root.left, key);. That is great. Except that if the element you are searching for is indeed in the left branch of the current Node, nothing happens. The method keeps executing, no matter what the recursive call has reported. You need to keep that data and handle it appropriately.
Therefore you should do something like this:
Node search(TreeNode root, int key){
if (root == null)
return null;
if (root.data == key)
return root;
Node n;
n = search(root.left, key);
if (n != null)
return n;
n = search(root.right, key);
if (n != null)
return n;
return null;
}

Java binary search tree - incorrectly working insert method

I've a binary search tree homework in Java where I was given complete Tree and Node classes and a SearchTree class in which I'm to complete the search and insert methods. The search is supposed to return the value of the node corresponding the searched key.
Here is the Tree class and here the Node class. My search and insert methods are below.
It seems I'm getting close, but test insert of key 0 and value 2 into Tree[Node[0,1,null,null]] results in Tree[Node[0,1,null,null] rather than the correct Tree[Node[0,2,null,null]]. What am I not understanding here?
public static Object search(Tree tree, int key) {
Node x = tree.getRoot();
while (x != null) {
if (key == x.getKey()) {
return x.getValue();
}
if (key < x.getKey()) {
x = x.getLeft();
} else {
x = x.getRight();
}
}
return null;
}
public static void insert(Tree tree, int key, Object value) {
if (tree.getRoot() == null) {
tree.setRoot(new Node(key, value));
}
Node juuri = tree.getRoot();
while (juuri != null) {
if (key == juuri.getKey()) {
return;
} else if (key < juuri.getKey()) {
if (juuri.getLeft() == null) {
juuri.setLeft(new Node(key, value));
return;
} else {
juuri = juuri.getLeft();
}
} else {
if (juuri.getRight() == null) {
juuri.setRight(new Node(key, value));
return;
} else {
juuri = juuri.getRight();
}
}
}
}
Well the issue I am seeing is that key values in your tree are unique. In this if statement you leave your insert method without adding a node if you see that the key is already in the tree.
if (key == juuri.getKey()) {
return;
}
In your example (if I understand it right) 0 is already in the tree so nothing changes when inserting 0 again. Based on your example, I am assuming you want to do an update on a node if the key is the same. So this code would do it.
if (key == juuri.getKey()) {
juuri.setValue(value);
return;
}

How do I calculate the number of "only child"-nodes in a binary tree?

NOTICE: this is homework-related, but I'm not tagging it as such because the 'homework' tag is marked as obselete (?)
Using the following class that implements a binary tree...
class TreeNode
{
private Object value;
private TreeNode left, right;
public TreeNode(Object initValue)
{
value = initValue;
left = null;
right = null;
}
public TreeNode(Object initValue, TreeNode initLeft, TreeNode initRight)
{
value = initValue;
left = initLeft;
right = initRight;
}
public Object getValue()
{
return value;
}
public TreeNode getLeft()
{
return left;
}
public TreeNode getRight()
{
return right;
}
public void setValue(Object theNewValue)
{
value = theNewValue;
}
public void setLeft(TreeNode theNewLeft)
{
left = theNewLeft;
}
public void setRight(TreeNode theNewRight)
{
right = theNewRight;
}
}
I need to calculate the number of nodes in the binary tree that are "only children," this being defined as a node that doesn't have another node stemming from its parent.
This is what I have so far:
public static int countOnlys(TreeNode t)
{
if(t == null)
return 0;
if(isAnOnlyChild(t))
return 1;
return countOnlys(t.getLeft()) + countOnlys(t.getRight());
}
I don't know how to implement the boolean method isAnOnlyChild(TreeNode t)
Could someone please help me?
You are pretty close and have the traversal looking good but in your Treenode you do not have a link between a child and its parent. So You can not tell from say a left child if a sibling (right child) exists.
You could have a parent Treenode (along with left and right) so you could check how many children a given node's parent has. Or as ajp15243 suggested, instead use a method that checks how many children a given node has.
Some pseudo code of the latter:
//we still need to check if that only child has its own children
if hasOnlyChild(t)
return 1 + checkOnlys(left) + checkOnlys(right)
else
return checkOnlys(left) + checkOnlys(right)
As you have already noticed, one solution is to count number of parents that have only one child. This should work:
public static int countOnlys(TreeNode t)
{
if(t == null || numberOfChildren(t)==0){
return 0;
}
if(numberOfChildren(t)==1){
return 1+ countOnlys(t.getLeft()) + countOnlys(t.getRight());
}
if(numberOfChildren(t)==2 ){
return countOnlys(t.getLeft()) + countOnlys(t.getRight());
}
return 0;
}
public static int numberOfChildren (TreeNode t){
int count = 0;
if(t.getLeft() != null ) count++;
if(t.getRight() != null) count++;
return count;
}
A parent has an only child if exactly one of the children is non-null (which implies that exactly one of its children is null):
((t.getLeft() == null || t.getRight() == null)) && !(t.getLeft() == null && t.getRight() == null)
You don't test, however, the node when you visit it as the recursive code traverses the tree. (This is similar to the Visitor pattern.) What you do is test for an only child when you are sitting on the parent. It's actually a logical exclusive-or test because one and only one of the children needs to be non-null to detect that this node has an only child.
So the algorithm is to
visit each node in the tree.
count it, if the node has only one child
That's it. The rest is plumbing.
public static int onlyChild(TreeNode t){
int res = 0;
if( t != null){
// ^ means XOR
if(t.getLeft() == null ^ t.getRight() == null){
res = 1;
}
res += onlyChild(t.getLeft()) + onlyChild(t.getRight()));
}
return res;
}
whenever you traverse a binary tree, think recursively. this should work.
public static int countOnlys(TreeNode t)
{
if(t == null)
return 0;
if (t.getLeft()==null&&t.getRight()==null)
return 1;
return countOnlys(t.getLeft())+countOnlys(t.getRight());
}
public int countNode(Node root) {
if(root == null)
return 0;
if(root.leftChild == null && root.rightChild == null)
return 0;
if(root.leftChild == null || root.rightChild == null)
return 1 + countNode(root.leftChild) + countNode(root.rightChild);
else
return countNode(root.leftChild) + countNode(root.rightChild);
}

Counting the nodes in a binary search tree

I need to create a recursive method that takes as a parameter the root node of a binary search tree. This recursive method will then return the int value of the total number of nodes in the entire binary search tree.
This is what I have so far:
public class BinarySearchTree<E> extends AbstractSet<E>
{
protected Entry<E> root;
//called by the main method
public int nodes()
{
return nodes(root);
}
//nodes() will count and return the nodes in the binary search tree
private int nodes(Entry<E> current)
{
if(current.element != null)
{
if(current.left == null && current.right == null)
{
if(current.element == root.element)
return 1;
deleteEntry(current);
return 1 + nodes(current.parent);
}
else if(current.left != null && current.right == null)
return nodes(current.left);
else if(current.left == null && current.right != null)
return nodes(current.right);
else if(current.left != null && current.right != null)
return nodes(current.left) + nodes(current.right);
} else return 1;
return 0;
}
The main method calls nodes like so:
System.out.println ("\nThis section finds the number of nodes "
+ "in the tree");
System.out.println ("The BST has " + bst.nodes() + " nodes");
So I was running the search by traveling in order, once I'd get to a node with no children I would delete the current node and return to the parent node and continue. I ran a debug of the method I have above and the program crashes with a NullPointerException() when it finally counts and removes all the nodes on the left and right side of the root node and tries to return 1.
This is for my lab, the method MUST be recursive.
I'm very lost at this point, does anyone know what I'm doing wrong?
You are making this way too complicated. The basic idea of object oriented programming is that you trust objects to do the jobs they know the answers to. So if I'm a parent, I can count myself, and I let my children count themselves, and so forth.
private int nodes(Entry<E> current) {
// if it's null, it doesn't exist, return 0
if (current == null) return 0;
// count myself + my left child + my right child
return 1 + nodes(current.left) + nodes(current.right);
}
You have several issues:
You're deleting nodes as you count them? Is nodes() supposed to clear the tree?
You're treating root==null, root!=null&left==null&&right==null, root!=null&left!=null&right==null, etc as separate cases. They're not. You have three cases, which are not entirely exclusive:
If the current node is not null, add one to the count. (This should always be the case. The only case where it might be false is if the current node == root, and we can detect and sidestep that beforehand.)
If the current node has a left child, add the left child's count.
If the current node has a right child, add the right child's count.
You're traversing back up the tree for some ungodly reason. Looks like it has something to do with deleting nodes...?
But the biggest thing in my opinion is, you're not giving enough autonomy to the Entrys. :P
A node can count its own children. Trust it to.
class Entry<E> {
...
int count() {
int result = 1;
if (left != null) result += left.count();
if (right != null) result += right.count();
return result;
}
}
public int nodes() {
return (root == null) ? 0 : root.count();
}
If your teacher is incompetent, and insists on some node-counting function outside a node, you can do the same thing you were trying to do:
private int nodes(Entry<E> current) {
int result = 1;
if (current.left) result += nodes(current.left);
if (current.right) result += nodes(current.right);
return result;
}
public int nodes() {
return (root == null) ? 0 : nodes(root);
}
But that teacher should be fired, in my opinion. The Entry class is the real tree; BinarySearchTree is really just a container for a reference to the root.
Also notice, i don't give a damn about the parents. If we start counting from the root, and each node counts its children, which count their children, etc etc... then all nodes will be accounted for.
public int countNodes(Node root){
// empty trees always have zero nodes
if( root == null ){
return 0;
}
// a node with no leafes has exactly one node
// note from editor: this pice of code is a micro optimization
// and not necessary for the function to work correctly!
if( root.left == null && root.right == null ){
return 1;
}
// all other nodes count the nodes from their left and right subtree
// as well as themselves
return countNodes( root.left ) + countNodes( root.right ) + 1;
}
After you delete current in: deleteEntry(current);, you use current.parent in return 1 + nodes(current.parent);
May be this's the reason of throwing NullPointerException..
Hey I have a very clean counting implemented for a binary tree:
public class Binary<T> where T: IComparable<T>
{
private Node _root;
public int Count => _root.Count;
public void Insert(T item)
{
Node newNode = new Node(item);
if (_root == null)
_root = newNode;
else
{
Node prevNode = _root;
Node treeNode = _root;
while (treeNode != null)
{
prevNode = treeNode;
treeNode = newNode.Item.CompareTo(treeNode.Item) < 1 ? treeNode.Left : treeNode.Right;
}
newNode.Parent = prevNode;
if (newNode.Item.CompareTo(prevNode.Item) < 1)
prevNode.Left = newNode;
else
prevNode.Right = newNode;
}
}
public class Node
{
public T Item;
public Node Parent;
public Node Left;
public Node Right;
public Node(T item, Node parent = null, Node left = null, Node right = null)
{
Item = item;
Parent = parent;
Left = left;
Right = right;
}
public int Count
{
get
{
int count = 1;
count += Left?.Count ?? 0;
count += Right?.Count ?? 0;
return count;
}
}
}
}
Maybe this helps you to understand how to implement a class for a simple binary tree with a count.
This implementation accesses the count through a count in the corresponding node in the tree.
Let me now if you are not familiar with the markup of .NET 4.6

Categories

Resources