I'm learning sourcecode of remove() in treemap. But there is something i can't understand.
//....................ignore major codes,left these
private void deleteEntry(Entry<K,V> p) {
if (p.left != null && p.right != null) {
Entry<K,V> s = successor(p);
p.key = s.key;
p.value = s.value;
p = s;
}
}
static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {`enter code here`
if (t == null)
return null;
else if (t.right != null) {
Entry<K,V> p = t.right;
while (p.left != null)
p = p.left;
return p;
} else {
Entry<K,V> p = t.parent;
Entry<K,V> ch = t;
while (p != null && ch == p.right) {
ch = p;
p = p.parent;
}
return p;
}
}
I felt confused in deleteEntry function, p has 2 kids. P.left and P.right all
aren't null.
but why dose it judge that t.right is not empty in successor function?
I mean that it's absoulte fact. And because t.right must be
not null. Codes never be excuted in else master in successor function.
Who call tell me where is my problem? Thank you ,guys.
If you look at TreeMap.java , you will get to know that successor is getting called from many places, delete() is just one such place.
Related
Heya I'm working on Binary tree and stuck on how to remove node from binary tree.I asked it from my instructor and did some googling but they wasn't helpful. My instructor said there is a 3 conditions to remove node from tree.
1.If node is leaf
2.If node has both child
3.If node has only one child
Here's code I wrote:
public void remove(Object theElement) {
BinaryTreeNode currentNode = this.root;
ArrayStack temp = new ArrayStack();
while(currentNode != null) {
if(currentNode.getLeftChild() == null
&& currentNode.getRightChild() == null
&& currentNode.getElement().equals(theElement)) {
currentNode = null;
break;
}
else if(currentNode.getLeftChild() != null
&& currentNode.getRightChild() == null
&& currentNode.getElement().equals(theElement)) {
BinaryTreeNode p = currentNode;
BinaryTreeNode c = currentNode.leftChild;
while(c != null) {
p = c;
c = c.rightChild;
}
p.rightChild = null;
System.out.println("Done removing node with left child");
break;
}
else if(currentNode.getLeftChild() == null
&& currentNode.getRightChild() != null
&& currentNode.getElement().equals(theElement)) {
BinaryTreeNode p = currentNode;
BinaryTreeNode c = currentNode.rightChild;
while(c != null) {
p = c;
c = c.rightChild;
}
p.rightChild = null;
System.out.println("Done removing node with right child");
break;
}
else if(currentNode.getLeftChild() != null
&& currentNode.getRightChild() != null
&& currentNode.getElement().equals(theElement)){
BinaryTreeNode p = currentNode;
BinaryTreeNode c = currentNode.rightChild;
while(c != null) {
p = c;
c = c.rightChild;
}
p.rightChild = null;
System.out.println("Done removing node with left and right child");
break;
}
else {
if(currentNode.getLeftChild() != null)
temp.push(currentNode.getLeftChild());
if(currentNode.getRightChild() != null)
temp.push(currentNode.getRightChild());
}
if(!temp.empty()) {
currentNode = (BinaryTreeNode)temp.pop();
}
else break;
}
}
I could find the node that is to be removed, but can't remove it. Please help :)
There are many ways to accomplish the above. Once way is to use recursion. Below is an example (not tested, just to demonstrate the concept).
package org.test.junk;
public class BTreeNode {
protected BTreeNode right;
protected BTreeNode left;
public void add(BTreeNode node, NodePosition nodePosition) {
switch(nodePosition) {
case left:{this.left=node;break;}
case right:{this.right=node;break;}
}//switch closing
}//add closing
public void remove(NodePosition nodePosition) {
switch(nodePosition) {
case left:{remove(left);break;}
case right:{remove(right);break;}
}//switch closing
}//remove closing
public void remove(BTreeNode node) {
if(node==null)return;
if(node.equals(right)) {
if(this.right!=null) {
this.right.remove(NodePosition.right);
this.right.remove(NodePosition.left);
this.right=null;
}//if closing
}//if closing
else if(node.equals(left)) {
if(this.left!=null) {
this.left.remove(NodePosition.right);
this.left.remove(NodePosition.left);
this.left=null;
}//if closing
}//else if closing
else return;
}//remove closing
public static enum NodePosition{
right,left;
}//enum closing
}//class closing
The idea is that if a parent node is called to remove its children (either left or right) will first call the child to remove all of its children recursively, conceptually.
So I have two implementation of a method that searches a custom linked list with name as input and either gets the mark associated with the name if the name is found or returns -1.
public int getMark (String name) {
Node p = head;
while ((p != null) && !(p.getName().equals(name)){
p = p.getNext();
}
if (p == null){
return - 1;
}
else
{
return p.getMark();
}
}
OR
public int getMark(String name){
Node p = head;
if(head == null)
{
return -1;
break;
}
while(p != null)
{
if(p.getName().equals(name)
{
return p.getMark();
}
else
{
return -1;
}
p = p.getNext();
}
}
They both do the job but I want to know which solution is better. I personally find the first solution confusing and not logically sound.
Your first code is not seems better as if any of your node may be null then it will return -1 and not check further,
Also your second logic is little bit complex it should be as below which can perform better.
public int getMark(String name){
Node p = head;
if(head == null)
{
return -1;
}
while(p != null)
{
if(p.getName().equals(name)
{
return p.getMark();
}
p = p.getNext();
}
return -1;
}
Your second version won't work unless the head contains the correct one and the first version seems a bit too much. Have a look at this: It's faster and (in my opinion) more readable
public int getMark (String name) {
Node p = head;
//Check if head is the correct one
if (name.equals(p.getName())){
return p.getMark();
}
while (hasNext(p)){
p = p.getNext();
if (name.equals(p.getName())){
return p.getMark();
}
}
//Ending up here means we didn't find it
return -1;
}
private boolean hasNext(Node p){
return p.getNext() != null;
}
Note that I'm assuming head and 'name' are not null, otherwise this won't work of course
This would be my approach as it's concise and readable (in my opinion). Pretty much a variation of your first implementation. Arguably you could return -1 if the head is null.
public int getMark(String name) {
Node p = head;
while (p != null && !p.getName().equals(name)) {
p = p.next;
}
return p != null ? p.getMark() : -1;
}
I'm getting a Stack overflow error for the following method at the recursive call. I think I need to make it iterative in order for it to work. How would I write the following method iteratively?
Node myMethod(String foo, Node p) {
if(p == null) {
p = new Node(foo);
p.link = spot;
spot = p;
p.calc[bar] = 1;
return p;
} else if(foo.equals(p.origin)) {
p.calc[bar] = p.calc[bar] + 1;
return p;
} else {
while (p.next == null & foo.equals(p.origin)){
p = p.next;
}
p.next = myMethod(foo, p.next);
return p;
}
}
p is a Node class that has String foo, String origin, Node link, Node next, and int Array calc[]. bar is an int. spot is a random node.
This is what I have tried so far
Node myMethod(String foo, Node p) {
if(p == null) {
p = new Node(foo);
p.link = spot;
spot = p;
p.calc[bar] = 1;
return p;
} else if(foo.equals(p.origin)) {
p.calc[bar] = p.calc[bar] + 1;
return p;
} else {
while (p.next == null & foo.equals(p.origin)){
p = p.next;
}
//instead of doing recursion on: p.next = myMethod(foo, p.next);. I tried the following:
if (p.next == null){
p.next = new Node(foo);
p.next.link = spot;
spot = p.next;
p.next.calc[bar] = 1;
} else if (foo.equals(p.next.origin)){
p.next.calc[bar] = p.next.calc[bar] + 1;
} else {
while (p.next.next == null & foo.equals(p.next.origin)){
p.next = p.next.next;
}
}
}
return p;
}
Although your iterative-try probably could be written better, this is a good try. However, look here:
else {
while (p.next == null & foo.equals(p.origin)){ //HERE! Check the while argument.
p = p.next;
} //instead of doing recursion on: p.next = myMethod(foo, p.next);. I tried the following:
…
The while loop will stop if p.next is null or foo does not equal p.origin. Now the basic approach would be to serve three cases here:
what to do when p.next != null (first while condition)
what to do when !foo.equals(p.origin) (second while condition) //you did not write it.
what to do when p.next != null && !foo.equals(p.origin)
If your while conditions are correct (ones you want them to be), you need to serve all cases for which the while loop may have stopped and that should be end of your algorithm. If it is not, rethink your while loop condition.
I'm still not entirely shure what you are trying to do and this code looks like bad programming style but maybe it will do what you need.
Node myMethod(String foo, Node p) {
while(p != null) {
if(foo.equals(p.origin)) {
p.calc[bar] = p.calc[bar] + 1;
break;
}
p = p.next;
}
if(p == null) {
p = new Node(foo);
p.link = spot;
spot = p;
p.calc[bar] = 1;
}
return p;
}
I've spent hours trying to figure it out. I've checked and the delete function does find the node, but when I try to delete it by setting it as null or equal to a child node it doesn't change the tree at all when I print it out for a second time. Can anyone help me figure out what I've done wrong or at least guide me to what I need to do to fix it?
class BST {
Node root;
void BST () {
root = new Node("B");
insert (root, "A");
insert (root, "D");
insert (root, "C");
inOrder (root);
System.out.println (" ");
delete (root, "D");
//root.LEFT = null;
inOrder (root);
}
void insert (Node n, String newKEY) {
if (n.KEY.compareTo(newKEY) > 0) {
if (n.LEFT == null) n.LEFT = new Node(newKEY);
else if (n.LEFT != null && n.LEFT.KEY.compareTo(newKEY) < 0) n.LEFT = new Node(n.LEFT, newKEY, null);
else insert (n.LEFT, newKEY);
}
if (n.KEY.compareTo(newKEY) < 0) {
if (n.RIGHT == null) n.RIGHT = new Node(newKEY);
else if (n.RIGHT != null && n.RIGHT.KEY.compareTo(newKEY) > 0) n.RIGHT = new Node(null, newKEY, n.RIGHT);
else insert (n.RIGHT, newKEY);
}
else if (n.KEY.compareTo(newKEY) == 0) n.C++;
}
void delete (Node n, String s) {
// Visit, check if proper node, if so then delete
if (n.KEY.compareTo(s) == 0) {
System.out.println (n.KEY);
// Deleting a node with no children
if (n.LEFT == null && n.RIGHT == null) n = null;
// Deleting a node with only left child
else if (n.RIGHT == null) n = n.LEFT;
// Deleting a node with only right child
else if (n.LEFT == null) n = n.RIGHT;
// Deleting a node with two children
else deleteNode_Two_Children (n, s);
}
// Left
else if (n.KEY.compareTo(s) > 0) delete (n.LEFT, s);
// Right
else if (n.KEY.compareTo(s) < 0) delete (n.RIGHT, s);
}
boolean find (Node n, String s) {
if (n.KEY.compareTo(s) > 0) {
if (n.LEFT == null) return false;
else if (n.LEFT != null && n.LEFT.KEY.compareTo(s) < 0) return false;
else find (n.LEFT, s);
}
if (n.KEY.compareTo(s) < 0) {
if (n.RIGHT == null) return false;
else if (n.RIGHT != null && n.RIGHT.KEY.compareTo(s) > 0) return false;
else find (n.RIGHT, s);
}
else if (n.KEY.compareTo(s) == 0) return true;
return false;
}
void deleteNode_Two_Children (Node n, String st) {
Node s = getSuccessor(n);
n = new Node (n.LEFT, s.KEY, s.C, n.RIGHT);
delete (s, st);
}
Node getSuccessor (Node n) {
Node temp = new Node();
while (n.LEFT != null) {
temp = n.LEFT;
n = temp;
}
return temp;
}
void inOrder (Node n) {
// Left
if (n.LEFT != null) inOrder (n.LEFT);
// Visit
System.out.print (n.KEY + " - " + n.C + ", ");
// Right
if (n.RIGHT != null) inOrder (n.RIGHT);
}
public static void main(String args[]){
BST t = new BST();
t.BST();
}
}
class Node {
String KEY;
int C;
Node LEFT;
Node RIGHT;
Node (String key) {
KEY = key;
C = 1;
LEFT = null;
RIGHT = null;
}
Node (Node L, String key, Node R) {
LEFT = L;
RIGHT = R;
KEY = key;
C = 1;
}
Node (Node L, String key, int c, Node R) {
LEFT = L;
RIGHT = R;
KEY = key;
C = c;
}
Node () {
KEY = null;
C = 0;
LEFT = null;
RIGHT = null;
}
// If 'this' is less than 'other', a negative number will be returned,
// 0 if equal
// Positive number if 'this' is greater.
int compare (Node other) {
return this.KEY.compareTo(other.KEY);
}
boolean equals (Node other) {
return this.KEY.equals(other.KEY);
}
}
The problem is your assumption that setting n to null will remove the node. Consider the following:
Object x = new Object();
public void someMethod(Object o) {
o = null;
}
This won't modify x. Java is pass-by-value, where o is the reference to some Object. You can certainly modify the internals of o through o's methods:
o.setValue(1);
This works because the value of o is really some address on the heap, which isn't being modifed. You can't overwrite o itself (eg, you can't set it to null or a new Object()). In order for you to delete a node, you must find the node's parent and set it's left or right child (whichever one you with to remove) and set that to null. Also, if that node has children, you have to make sure they aren't removed just because their parent is removed.
I'm trying to remove all of the leaves. I know that leaves have no children, this is what I have so far.
public void removeLeaves(BinaryTree n){
if (n.left == null && n.right == null){
n = null;
}
if (n.left != null)
removeLeaves(n.left);
if (n.right != null)
removeLeaves(n.right);
}
n = null; won't help you, since n is just a local variable of your function. Instead, you'd need to set n.left = null; or n.right = null; on the parent.
I won't give you a complete solution, since this smells a lot like homework, but you could, for example, add a return value to your function to indicate whether the node in question is a leaf or not and take appropriate actions in the parent (after the call to removeLeaves).
It's much easier if you break this down like this:
public void removeLeaves(BinaryTree n){
if (n.left != null) {
if (n.left.isLeaf()) {
n.removeLeftChild();
} else {
removeLeaves(n.left);
}
}
// repeat for right child
// ...
}
isLeaf, removeLeftChild and removeRightChild should be trivial to implement.
Instead of n = null, it should be:
if(n.parent != null)
{
if(n.parent.left == n)
{
n.parent.left = null;
}
else if(n.parent.right == n)
{
n.parent.right == null);
}
}
Since Java passes references by values n = null; simply does not work. With this line n was pointing to the leaf and now points to nothing. So you aren't actually removing it from the parent, you are just rerouting a dummy local reference. For the solution do what Matthew suggested.
Here's a simple java method to delete leaf nodes from binary tree
public BinaryTreeNode removeLeafNode(BinaryTreeNode root) {
if (root == null)
return null;
else {
if (root.getLeft() == null && root.getRight() == null) { //if both left and right child are null
root = null; //delete it (by assigning null)
} else {
root.setLeft(removeLeafNode(root.getLeft())); //set new left node
root.setRight(removeLeafNode(root.getRight())); //set new right node
}
return root;
}
}
Easy method with recusrion .
public static Node removeLeaves(Node root){
if (root == null) {
return null;
}
if (root.left == null && root.right == null) {
return null;
}
root.left = removeLeaves(root.left);
root.right = removeLeaves(root.right);
return root;
}
/* #author abhineet*/
public class DeleteLeafNodes {
static class Node{
int data;
Node leftNode;
Node rightNode;
Node(int value){
this.data = value;
this.leftNode = null;
this.rightNode = null;
}
}
public static void main(String[] args) {
Node root = new Node(1);
Node lNode = new Node(2);
lNode.leftNode = new Node(4);
root.leftNode = lNode;
Node rNode = new Node(3);
rNode.rightNode = new Node(5);
root.rightNode = rNode;
printTree(root);
deleteAllLeafNodes(root, null,0);
System.out.println("After deleting leaf nodes::");
printTree(root);
}
public static void deleteAllLeafNodes(Node root, Node parent, int direction){
if(root != null && root.leftNode == null && root.rightNode == null){
if(direction == 0){
parent.leftNode = null;
}else{
parent.rightNode = null;
}
}
if(root != null && (root.leftNode != null || root.rightNode != null)){
deleteAllLeafNodes(root.leftNode, root, 0);
deleteAllLeafNodes(root.rightNode, root, 1);
}
}
public static void printTree(Node root){
if(root != null){
System.out.println(root.data);
printTree(root.leftNode);
printTree(root.rightNode);
}
}
}
This should work-
public boolean removeLeaves(Node n){
boolean isLeaf = false;
if (n.left == null && n.right == null){
return true;
//n = null;
}
if (n!=null && n.left != null){
isLeaf = removeLeaves(n.left);
if(isLeaf) n.left=null; //remove left leaf
}
if (n!=null && n.right != null){
isLeaf = removeLeaves(n.right);
if(b) n.right=null; //remove right leaf
}
return false;
}