How to implement the delete method for BinarySearchTree? - java

This is my code. I am stuck on the delete part. The insert and get methods are all fine. I want to save the old tree so that I can link the node together soon.
private BinaryTree<K, V> left, right;
public BinaryTree(K key, V value) {
// Leaf node constructor
this.key = key;
this.value = value;
}
public V put(K key, V value) {
if (this.key.equals(key)) {
// Replacing the value at the current node
V ret = this.value;
this.value = value;
return ret;
}
int comp = this.key.compareTo(key);
if (comp < 0) {
// this.key < key
// Put the key we are inserting to the right
// of the current key
if (right == null) {
// We have to create a node to the right
// (Leaf node)
right = new BinaryTree<K, V>(key, value);
return null; // Per interface
}
return right.put(key, value);
} else {
// We don't support keys where equals and compareTo
// disagree with each other.
assert(comp != 0);
// At this point, we know that comp > 0
// Therefore, this.key > key
// Put the key we are inserting to the left of current
if (left == null) {
// We have to create a node to the left
// (Leaf node)
left = new BinaryTree<K, V>(key, value);
return null; // Per interface
}
return left.put(key, value);
// Exercise: You could write a tiny little private method
// to implement this redundant code in one place.
}
}
public V get(K key) {
int comp = this.key.compareTo(key);
if (comp < 0) {
// this.key < key
// Recurse to the right
if (right == null) {
// Not in the tree
return null;
}
return right.get(key);
} else if (comp > 0) {
// this.key > key
// Recurse to the left
if (left == null) {
// Not in the tree
return null;
}
return left.get(key);
} else {
assert(this.key.equals(key));
return value;
}
}
public boolean containsKey(K key) {
// Note: Doesn't work with null values!
return get(key) != null;
}
public BinaryTree<K, V> delete(K key) {
BinaryTree<K,V> tmp,childL,childR,OldTree;
int comp=this.key.compareTo(key);
if(comp<0){
//this.key<Key goes right
if(this.right==null){
throw new UnsupportedOperationException("Nothing you can delete here");
}
else{
return this.right.delete(key);
}
}
if(comp>0){
if(this.left==null){
throw new UnsupportedOperationException("Nothing you can delte here");
}
else{
return this.left.delete(key);
}
}
if(this.key.equals(key)){
}
{
}
//}
// IMPLEMENT THIS FOR YOUR ASSIGNMENT!
// Remove key from the tree, if it exists.
// Throw UnsupportedOperationException if key isn't in the tree.
// Return the new root node if we did delete the key.
// (The new root node may be the same as the old one.)
// If you deleted the last node in the tree, it will return null.
return null;
}}
Some details are posted on the common, is it logical error on my code?

Related

Implementation of Custom HashMap code issues

I am preparing my own custom HashMap implementation in Java. Below is my imlementation.
public class Entry<K,V> {
private final K key;
private V value;
private Entry<K,V> next;
public Entry(K key, V value, Entry<K,V> next) {
this.key = key;
this.value = value;
this.next = next;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
public Entry<K, V> getNext() {
return next;
}
public void setNext(Entry<K, V> next) {
this.next = next;
}
public K getKey() {
return key;
}
}
public class MyCustomHashMap<K,V> {
private int DEFAULT_BUCKET_COUNT = 10;
private Entry<K,V>[] buckets;
public MyCustomHashMap() {
buckets = new Entry[DEFAULT_BUCKET_COUNT];
for (int i = 0;i<DEFAULT_BUCKET_COUNT;i++)
buckets[i] = null;
}
public void put(K key,V value){
/**
* This is the new node.
*/
Entry<K,V> newEntry = new Entry<K,V>(key, value, null);
/**
* If key is null, then null keys always map to hash 0, thus index 0
*/
if(key == null){
buckets[0] = newEntry;
}
/**
* get the hashCode of the key.
*/
int hash = hash(key);
/**
* if the index does of the bucket does not contain any element then assign the node to the index.
*/
if(buckets[hash] == null) {
buckets[hash] = newEntry;
} else {
/**
* we need to traverse the list and compare the key with each of the keys till the keys match OR if the keys does not match then we need
* to add the node at the end of the linked list.
*/
Entry<K,V> previous = null;
Entry<K,V> current = buckets[hash];
while(current != null) {
boolean done = false;
while(!done) {
if(current.getKey().equals(key)) {
current.setValue(value);
done = true; // if the keys are same then replace the old value with the new value;
} else if (current.getNext() == null) {
current.setNext(newEntry);
done = true;
}
current = current.getNext();
previous = current;
}
}
previous.setNext(newEntry);
}
}
public V getKey(K key) {
int hash = hash(key);
if(buckets[hash] == null) {
return null;
} else {
Entry<K,V> temp = buckets[hash];
while(temp != null) {
if(temp.getKey().equals(key))
return temp.getValue(); // returns value corresponding to key.
temp = temp.getNext();
}
return null; //return null if key is not found.
}
}
public void display() {
for(int i = 0; i < DEFAULT_BUCKET_COUNT; i++) {
if(buckets[i] != null) {
Entry<K,V> entry = buckets[i];
while(entry != null){
System.out.print("{"+entry.getKey()+"="+entry.getValue()+"}" +" ");
entry=entry.getNext();
}
}
}
}
public int bucketIndexForKey(K key) {
int bucketIndex = key.hashCode() % buckets.length;
return bucketIndex;
}
/**
*
* #param key
* #return
*/
private int hash(K key){
return Math.abs(key.hashCode()) % buckets.length;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
MyCustomHashMap<String, Integer> myCustomHashMap = new MyCustomHashMap<String, Integer>();
myCustomHashMap.put("S", 22);
myCustomHashMap.put("S", 1979);
myCustomHashMap.put("V", 5);
myCustomHashMap.put("R", 31);
System.out.println("Value corresponding to key R: "+myCustomHashMap.getKey("R"));
System.out.println("Value corresponding to key V: "+myCustomHashMap.getKey("V"));
System.out.println("Displaying the contents of the HashMap:: ");
myCustomHashMap.display();
}
}
1) I feel that put (K key,V value) is somewhat flawed. Please do kindly validate and let me know what's wrong here. On entering the same key its giving me wrong result. I have not yet tested it for collision cases having different keys.
2) It is said that we rehash the hashCode so that it eliminates wrong implementation of hashCode. how do I do it because if I give hashCode of key i.e. hash(key.hashCode()) then it dosn't take as it can't compute hashCode of int. How to do this?
Any help would be highly appreciated.
Thanks
Sid
You handle null key incorrectly :
if(key == null){
buckets[0] = newEntry;
}
It's possible that buckets[0] already contains entries, in which case you will lose those entries.
The following loop has some issues :
Entry<K,V> previous = null;
Entry<K,V> current = buckets[hash];
while(current != null) {
boolean done = false;
while(!done) {
if(current.getKey().equals(key)) {
current.setValue(value);
done = true;
} else if (current.getNext() == null) {
current.setNext(newEntry);
done = true;
}
current = current.getNext();
previous = current; // you are not really setting previous to
// to the previous Entry in the list - you
// are setting it to the current Entry
}
}
previous.setNext(newEntry); // you don't need this statement. You
// already have a statement inside the
// loop that adds the new Entry to the list
It looks like removing any statements related to previous will fix this loop.
EDIT:
As kolakao commented, in order for your implementation to be efficient (i.e. require expected constant time for get and put), you must resize the HashMap when the number of entries exceeds some threshold (in order for the average number of entries in each bucket to be bound by a constant).
It is said that we rehash the hashCode so that it eliminates wrong implementation of hashCode. how do I do it because if I give hashCode of key i.e. hash(key.hashCode()) then it dosn't take as it can't compute hashCode of int. How to do this?
The idea of re-hashing doesn't involve calling hashCode for the hashCode of the key. It involves running some hardcoded function on the value obtained by key.hashCode().
For example, in Java 7 implementation of HashMap, the following function is used :
static int hash(int h) {
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
Then you use it with :
int hash = hash(key.hashCode());
int bucket = hash % buckets.length;

BST: return first entry larger than the key

I am writing to write a Java method that takes a binary search tree (BST) T and a key k, and returns the first entry larger than k that would appear in an inorder traversal. If k is absent or no key larger than k is present, return null. For example, when applied to the BST in the figure below you should return 29 if k = 23; if k = 32, you should return null.
http://imgur.com/fpNk9fT
The pseudo code is:
findFirstEntryLargerThanKey(BSTNode t, int key)
// go left
findFirstEntryLargerThanKey(t.left, key);
// visit the node
if t.nodeValue == key
key exists, set a boolean value to true
else if t.nodeValue > key
check if this node value is the first entry larger than key
// go right
findFirstEntryLargerThanKey(t.right, key);
The code that I have written uptil now:
boolean found = false;
int x = 0;
public Integer findFirstEntryLargerThanKey(BSTNode t, int key) {
// the scan terminates on an empty subtree
if (t != null) {
// descend left
findFirstEntryLargerThanKey(t.left, key);
// visit the node
if (t.nodeValue == key){
found = true;
}
else if (t.nodeValue > key && found == true && ? && ?){
x = t.nodeValue;
}
// descend right
findFirstEntryLargerThanKey(t.right, key);
return x;
}
return null;
}
I need help regarding the conditions that I have to use.
Do an in order traversal , which will print the tree key in ascending order . simultaneously keep comparing the key and print the first key that is greater than your key .. The time complexity will be less than O(n)
You can directly return the answer when you find it, since x is globally declared.
Your function should be something like this :
boolean found = false;
int x = 0;
public Integer findFirstEntryLargerThanKey(BSTNode t, int key) {
// the scan terminates on an empty subtree
if (t != null) {
// descend left
findFirstEntryLargerThanKey(t.left, key);
// visit the node
if (t.nodeValue == key){
found = true;
}
else if (t.nodeValue > key && found == true){
x = t.nodeValue;
return x;
}
// descend right
findFirstEntryLargerThanKey(t.right, key);
return x;
}
return null;
}
Or, do something like this :
int x = 0;
public Integer findFirstEntryLargerThanKey(BSTNode t, int key) {
// the scan terminates on an empty subtree
if (t != null) {
// descend left
findFirstEntryLargerThanKey(t.left, key);
// visit the node
if (t.nodeValue > key){
x = t.nodevalue;
return x;
}
// descend right
findFirstEntryLargerThanKey(t.right, key);
return x;
}
return null;
}
Lets try the usual key search with two extra steps:
* Whenever we go left from a parent to a child,
remember the parent as a potential answer.
* If the key is found and it has a right subtree,
then the answer is left-most (smallest) node of that subtree.
FindFirstEntryLargerThanKey(BSTNode t, int key) {
BSTNode result_so_far = null;
for (BSTNode cur = t; cur; ) {
if (key < cur->key) {
result_so_far = cur;
cur = cur->left;
}
else if (key == cur->key) {
if (cur->right) {
result_so_far = LeftMostNode(cur->right);
}
break;
}
else {
cur = cur->right;
}
}
return result_so_far;
}
try this out
public Integer findFirstEntryLargerThanKey(BSTNode t, int key) {
Integer x =null;
// the scan terminates on an empty subtree
if (t != null && x!=null) {
// descend left
findFirstEntryLargerThanKey(t.left, key);
// visit the node
if (t.nodeValue > key ||t.nodeValue==key){
x = t.nodeValue;
}
// descend right
findFirstEntryLargerThanKey(t.right, key);
}
return x;
}

Deleting a node from a linked list in Java

I'm trying to write a code that handles a linked list. This linked list is somehow different because it's a key-value pair linked list (singly). The linked list should provide the user with basic functions, such as retrieving the size of linked list, checking for a key whether it's in the list or not, insertion, and deletion. It seems that all the functions are working properly except for the deletion. The code for the deletion method run correctly with no run time error, but it gives me results that's not what I wanted to have. Here is my code:
public class SequentialSearch<Key,Value> {
private int N; // number of key-value pairs
private Node head; // the linked list of key-value pairs
private Node tail;
// a helper linked list data type
private class Node {
private Key key;
private Value val;
private Node next;
public Node(Key key, Value val, Node next) {
this.key = key;
this.val = val;
this.next = next;
}
public void setNext(Node next) {
this.next = next;
}
}
public SequentialSearch() {
}
public int size() {
if (head == null)
return 0;
else {
Node x = head;
while (x.next != null) {
N++;
x = x.next;
}
}
return N;
}
public boolean isEmpty() {
return size() == 0;
}
public boolean contains(Key key) {
return get(key) != null;
}
public Value get(Key key) {
for (Node x = head; x != null; x = x.next) {
if (key.equals(x.key))
return x.val;
}
return null;
}
public void put(Key key, Value val) {
if (val == null) {
delete(key);
return;
}
for (Node x = first; x != null; x = x.next) {
if (key.equals(x.key)) {
x.val = val;
return;
}
}
first = new Node(key, val, first);
N++;
}
public boolean delete(Key key) {
Node curr = head;
Node prev = null;
boolean result = false;
if(isEmpty())
System.err.println("Error: The list is empty.");
while(curr != null) {
if(key.equals(curr.key)) {
if(curr.equals(head)) {
head = curr = null;
N--;
result = true;
return result;
} else {
prev.next = curr.next;
curr.setNext(null);
N--;
result = true;
return result;
}
} else {
prev = curr;
curr = curr.next;
}
}
return result;
}
}
I've written a main program to test for the add (put) and deletion, but it seems to be working for the insertion but not for the deletion. I think I might have a problem the deletion in case there is only one node in the list and the case of deleting a node from the middle of the list.
I'm also trying to modify the deletion method by writing a new method using the recursion, but I faced some errors -also logically. Here is the code of that function:
public void delete(Key key) {
first = delete(first, key);
}
private Node delete(Node x, Key key) {
if (x == null) return null;
if (key.equals(x.key)) {
N--;
return x.next;
}
x.next = delete(x.next, key);
return x;
}
Could you please tell me what did I do wrong?
head = curr = null;
This statement is a little confusing but I think it might be your problem for when deleting. If you're deleting a match that is at 'head', you just want to set head to 'curr.next'
What I think is going on:
delete(a)
a -> b -> c -> d
head = a
curr = a
curr.next = b
you set head to null, but head needs to point to the first item in the new list, which if you deleted 'a', would be 'b', or curr.next

Recursive Binary Search Tree Insert

So this is my first java program, but I've done c++ for a few years. I wrote what I think should work, but in fact it does not. So I had a stipulation of having to write a method for this call:
tree.insertNode(value);
where value is an int.
I wanted to write it recursively, for obvious reasons, so I had to do a work around:
public void insertNode(int key) {
Node temp = new Node(key);
if(root == null) root = temp;
else insertNode(temp);
}
public void insertNode(Node temp) {
if(root == null)
root = temp;
else if(temp.getKey() <= root.getKey())
insertNode(root.getLeft());
else insertNode(root.getRight());
}
Thanks for any advice.
// In java it is little trickier as objects are passed by copy.
// PF my answer below.
// public calling method
public void insertNode(int key) {
root = insertNode(root, new Node(key));
}
// private recursive call
private Node insertNode(Node currentParent, Node newNode) {
if (currentParent == null) {
return newNode;
} else if (newNode.key > currentParent.key) {
currentParent.right = insertNode(currentParent.right, newNode);
} else if (newNode.key < currentParent.key) {
currentParent.left = insertNode(currentParent.left, newNode);
}
return currentParent;
}
Sameer Sukumaran
The code looks a little confusing with overloaded functions. Assuming member variables 'left' and 'right' to be the left child and right child of the BSTree respectively, you can try implementing it in the following way:
public void insert(Node node, int value) {
if (value < node.value)
{
if (node.left != null)
{
insert(node.left, value);
}
else
{
node.left = new Node(value);
}
}
else if (value > node.value)
{
if (node.right != null)
{
insert(node.right, value);
}
else
{
node.right = new Node(value);
}
}
}
........
public static void main(String [] args)
{
BSTree bt = new BSTree();
Node root = new Node(100);
bt.insert(root, 50);
bt.insert(root, 150);
}
You should have a look to this article. It helps to implement a tree structure and search, insert methods:
http://quiz.geeksforgeeks.org/binary-search-tree-set-1-search-and-insertion/
// This method mainly calls insertRec()
void insert(int key) {
root = insertRec(root, key);
}
/* A recursive function to insert a new key in BST */
Node insertRec(Node root, int key) {
/* If the tree is empty, return a new node */
if (root == null) {
root = new Node(key);
return root;
}
/* Otherwise, recur down the tree */
if (key < root.key)
root.left = insertRec(root.left, key);
else if (key > root.key)
root.right = insertRec(root.right, key);
/* return the (unchanged) node pointer */
return root;
}
You can use standard Integer (wrapper for primitive int) object instead of creating a new object type Node. On latest java Integer/int auto-boxing is supported. Hence your method insertNode(int key) can take in Integer argument too (ensure it is not null).
EDIT: Pls ignore above comment. I did not understand your real question. You will have to overload insertNode(). I think you are right.
but where is temp when you insertNode?? With your current implementation temp is lost if root is not null.
I think you want something like
root.getLeft().insertNode(temp);
and
root.getRight().insertNode(temp);
i.e. To insert the new Node (temp) to either the left or the right subtree.

Put method of a TreeMap implementation

I'm working on an implementation of TreeMap(called MyTreeMap) and I'm having a lot of trouble with the put method. I was hoping someone could look at my code and point me in the right direction as to where things start to go wrong.
public class MyTreeMap<K extends Comparable<? super K>,V> extends AbstractMap<K,V> {
K key;
V value;
int height;
MyTreeMap<K,V> left,right;
int size;
public V put(K key, V value) {
int compareValue = this.key.compareTo(key);
if(!this.containsKey(key)) {
if(this.key == null) {
this.key = key;
this.value = value;
}
if(this.isLeaf() || this.isEmpty()) {
if(this.key.compareTo(key) > 0)
this.left = new MyTreeMap<K,V>(key,value,null,null);
else
this.right = new MyTreeMap<K,V>(key,value,null,null);
if(left.height > right.height + 1 || right.height > left.height + 1)
restructure(this);
this.size++;
setHeight();
return null;
}
else {
if(compareValue > 0)
return this.left.put(key, value);
else
return this.right.put(key, value);
}
}
else {
if(compareValue == 0) {
V temp = this.value;
this.value = value;
return temp;
}
else if(compareValue < 0)
return this.right.put(key, value);
else
return this.left.put(key, value);
}
}
I think your logic is a bit inside-out, and as a result is a lot more complicated than it needs to be: the top level if should probably be looking at the compareValue, not doing the containsKey check.
Logic should be:
if compareValue==0 then this means you have found the right key, so just update the value and return
otherwise check the left or right branch as appropriate (depending on sign of compareValue):
if the branch is null, then turn it into a new TreeMap branch containing your key and value (you are now done)
otherwise (branch is not null), call put recursively on this branch. If you like you can do rebalancing logic after this call.
P.S. I suggest not allowing null keys in a TreeMap, it will make your life simpler, and will avoid the need to do null checks on keys

Categories

Resources