How to efficiently Get Successor in HashTable? - java

I want to write a function that gets the data associated with the successor key of a key passed as an argument. I want to write it to perform the operation as simply as possible, and apart from getting some errors so far, I'd like some advice on how to fix my code so it does so. The method I want advice on is GetSuccessor(Comparable key).
class HashTable
{
int size;
int length;
Node nodes[];
// Constants
static final double max_load_factor = 0.7;
static final int initial_size = 5;
public HashTable()
{
size = initial_size;
nodes = new Node[size];
}
// Return the data associated with the given key, or null if the key
// is not present in the hash table.
public Object Search(Comparable key)
{
// Obtain index for the key
int index = key.hashCode() % size;
// Traverse collision list
for (Node node = nodes[index]; node != null; node = node.next)
if (node.key.equals(key))
return node.data;
// Not found
return null;
}
// Insert a pair key-data into the hash table
public void Insert(Comparable key, Object data)
{
// Check if the table must grow
double load_factor = (double) length / size;
if (load_factor > max_load_factor)
Grow();
// Create node
Node node = new Node(key, data);
// Get index for the key
int index = key.hashCode() % size;
// Insert node
node.next = nodes[index];
nodes[index] = node;
//Update length
length++;
}
// Grow the hash table. All node must be repositioned according
// to their new flash indices based on the new table.
void Grow()
{
// Message
System.out.println("Growing hash table");
// Save old nodes and table siz4
int old_size = size;
Node[] old_nodes = nodes;
// Create new table
size = size * 2;
length = 0;
nodes = new Node[size];
// Traverse old nodes
for (int i = 0; i < old_size; i++)
for (Node node = old_nodes[i]; node != null; node = node.next)
Insert(node.key, node.data);
}
// Return the data associated with the successor for the given key,
// or null if the key is the last or it is not present.
public Object GetSuccessor(Comparable key)
{
// Find node
Node node = Search(key);
if (node == null)
return null;
// Get sucessor node
for (Node node = nodes[key.hashCode()]; node != null; node = node.next)
if (node.key.equals(key))
return node.next.data;
// Return associated data
return node == null ? null : node.next.data;
}
}

first observation: when you run this it should produce an error when you initialize node to equal the result from Search(key). If you change it so that node= new Node(key, Search(key)) you'll move on to find an arrayindexoutofbounds exception. if you're in Ubal's 1:30 class check your email

Related

Red Black Trees getting merged?

I have 6 Red Black trees filled with different data, but the further down I go, the more my trees get mixed up. I've commented out all but two of them, here's my code for those two trees.
Scanner co2DateFile = new Scanner(new File("co2.csv"));
Scanner co2NumFile = new Scanner(new File("co2.csv"));
RedBlackBST co2DateKey = new RedBlackBST();
RedBlackBST co2NumKey = new RedBlackBST();
while (co2DateFile.hasNextLine()) {
String[] line3 = co2DateFile.nextLine().split(",");
if (line3[0].equals("World")) {
LocalDate date = parseDateString(line3[2]);
String stringDate = date.toString();
co2DateKey.root = co2DateKey.put(co2DateKey.root, stringDate, line3[3]);
}
}
while (co2NumFile.hasNextLine()) {
String[] line4 = co2NumFile.nextLine().split(",");
if (line4[0].equals("World")) {
co2NumKey.root = co2NumKey.put(co2NumKey.root, line4[3], line4[2]);
}
}
co2DateKey.inorder(co2DateKey.root);
I'm using the same file for both trees, but using different pieces of data for the keys and values. If I print co2DateKey inorder, then it prints the keys/values for co2DateKey and co2NumKey, but if I comment out the code for co2NumKey, then co2DateKey only prints its own keys/values. I'm not sure where they're getting crossed, so any help would be appreciated.
Here's my RedBlackBST class:
import java.util.Scanner;
import java.util.LinkedList;
import java.util.Queue;
import java.io.File;
import java.io.FileNotFoundException;
class Node
{
Node left;
Node right; // initializing Nodes and variables
String key;
String value;
String type;
boolean color; // true means color is red, false is black
Node(String key, String value)
{
this.key = key;
this.value = value;
left = null;
right = null;
color = true; // new nodes are always red
}
}
public class RedBlackBST {
public static Node root = null; // root initialized
public Node rotateLeft(Node myNode)
{
Node child = myNode.right;
Node childLeft = child.left; // assigning variables
child.left = myNode;
myNode.right = childLeft; // rotating nodes to the left
return child;
}
public Node rotateRight(Node myNode)
{
Node child = myNode.left; // assigning variables
Node childRight = child.right;
child.right = myNode; // rotating nodes to the right
myNode.left = childRight;
return child;
}
public void flipColors(Node x, Node y) // flipping colors of two given nodes
{
boolean temp = x.color; // uses temp to store color of first node
x.color = y.color; // first node takes second node's color
y.color = temp; // second node takes first node's color
}
public String get(String key) {
return get(root, key); // this function is called from main, which calls recursive get
}
private String get(Node x, String key) {
while (x != null) {
int cmp = key.compareTo(x.key); // compares current key with the one we are searching for
if (cmp < 0)
x = x.left;
else if (cmp > 0)
x = x.right; // recursively searches through tree until key is found
else
return x.value; // returns value associated with said key
}
return null;
}
public boolean getColor(String key) {
return getColor(root, key); // this function is called from main, which calls recursive getColor
}
private boolean getColor(Node x, String key) {
while (x != null) {
int cmp = key.compareTo(x.key); // same idea as get
if (cmp < 0)
x = x.left;
else if (cmp > 0) // recursively searches through tree to find key
x = x.right;
else
return x.color; // returns color of node associated with said key
}
return false;
}
public boolean isRed(Node myNode)
{
if (myNode == null) // checks color of node passed into function, returns true if red
return false;
return (myNode.color == true);
}
// insertion into Left Leaning Red Black Tree.
public Node put(Node myNode, String key, String value)
{
// inserting node, checks for violations to left leaning red black tree come next
if (myNode == null)
return new Node(key, value);
if (key.compareTo(myNode.key) < 0) // compares keys, recursive calls to find proper spot
myNode.left = put(myNode.left, key, value);
else if (key.compareTo(myNode.key) > 0)
myNode.right = put(myNode.right, key, value);
else if (key.equals(myNode.key) == true) // if key is already in tree, numeric value is replaced
myNode.value = value;
else
return myNode;
// case 1.
// when right child is Red but left child is
// Black or doesn't exist.
if (isRed(myNode.right) && !isRed(myNode.left))
{
myNode = rotateLeft(myNode); // left rotate the node to make it into valid structure.
flipColors(myNode, myNode.left); // swap the colors as the child node should always be red
}
// case 2
// when left child as well as left grand child are Red
if (isRed(myNode.left) && isRed(myNode.left.left))
{
myNode = rotateRight(myNode); // right rotate the current node to make it into a valid structure, then flip colors
flipColors(myNode, myNode.right);
}
// case 3
// when both left and right child are Red in color.
if (isRed(myNode.left) && isRed(myNode.right))
{
myNode.color = !myNode.color; // invert the color of node as well it's left and right child
myNode.left.color = false; // change the color to black
myNode.right.color = false;
}
return myNode;
}
public Iterable<String> keys(Node node, Queue<String> queue) { // uses inorder traversal to put keys in right order
if (node != null)
{
keys(node.left, queue);
queue.add(node.key); // adds each key to queue in correct order
keys(node.right, queue);
}
return queue; // returns queue after all keys have been added
}
public String highest(Node node) {
Node current = node;
while (current.right != null) {
current = current.right;
}
return current.key;
}
void inorder(Node node)
{
if (node != null)
{
inorder(node.left);
System.out.println(node.key + " " + node.value);
inorder(node.right);
}
}
Problem is here:
public static Node root = null; // root initialized
The root is declared static, which means it is shared between all instances of RedBlackBST. They all have the same root. Sure they will be mixed up.
Remove the static keyword.

Traversing through a Array-Binary tree

I have troubles with traversing through a array binary tree without recursion.
I hope someone can tell me what iam doing wrong. For simplicity the code is kept simple.
Please note: Its not allowed to add other methods like Iterator to check if there is a hasNext() and so on.
For now i just want to print all keys out (incl. child keys) in the hope that i can do the rest of the learning!
Thank you very much for helping.
public class BTree {
private Node root;
public BTree(Node root) {
this.root = root;
}
public int getMaxKey() {
Node copy = root;
for (int i = 0; copy.child != null && i < copy.child.length; i++) {
System.out.println("key: " + copy.key); // output: 15, 80
if (copy.child != null) {
copy = copy.child[i];
}
}
return 0;
}
}
public class Node {
public int key;
public Node[] child;
public Node(int key, Node[] child) {
this.key = key;
this.child = child;
}
}
public class NodeMain {
public static void main(String[] args) {
Node[] lv1Nodes = new Node[2];
lv1Nodes[0] = new Node(25, null);
lv1Nodes[1] = new Node(99, null);
Node[] lv0Nodes = new Node[2];
lv0Nodes[0] = new Node(80, lv1Nodes);
lv0Nodes[1] = new Node(5, null);
Node root = new Node(15, lv0Nodes);
BTree bTree = new BTree(root);
int maxKey = bTree.getMaxKey(); // output should be 99
System.out.println(maxKey);
}
}
So, here you are following only one branch till null for the Binary tree traversal. But, you need to keep track of all nodes in traversal order of child array so that you can get the max element from it.
please refer to below code, here i've used stack to keep all of the value array nodes, which we can pop and check for maxValue.
public class BTree {
private final Node root;
public BTree(Node root) {
this.root = root;
}
public int getMaxKey() {
int maxKey = root.key;
Stack<Node> stack = new Stack<>();
stack.addAll(Arrays.asList(root.child));
while(!stack.isEmpty()){
Node node = stack.pop();
System.out.println(node.key);
if(node.key > maxKey)
maxKey = node.key;
if(node.child != null)
stack.addAll(Arrays.asList(node.child));
}
return maxKey;
}
}
Edit: I've created a image which can help us to understand the tree little bit more clearly, and i've used for my reference for this code.
My solution without Stack object:
public int getMaxKey() {
Node copy = root;
int max = -1;
while (copy.child != null) {
if (max < copy.key)
max = copy.key; //root
if (copy.child.length == 1) { // max key between parent and child node, only one path available
if (max < copy.child[0].key) {
max = copy.child[0].key;
copy = copy.child[0];
}
} else if (copy.child.length == 2) { // max between two nodes, decide between one path
int maxBetweenChild = Math.max(copy.child[0].key, copy.child[1].key);
Node node = Arrays.stream(copy.child).filter(n -> n.key == maxBetweenChild).findFirst().get();
copy = node;
if (max < maxBetweenChild)
max = maxBetweenChild;
}
}
return max;
}

Sort a linked linked list by name and date of birth

I have ran into some difficulties. I want to adapt this piece of code below to sort a singly linked list of type Person. for example, I have:
class Person{
private String fn = "NN";
private String ln = "NN";
private Date dob = new Date(1, 1, 1970);
}
I would like to sort the linked list of Persons by firstname, last name and date of birth. At the same time I have been given a piece of code to adapt it but, I can't seem to find a way around it. Any help will be highly appreciated. Here is the code to adapt below:
public void sort() {
TextIO.putln("sorting...");
if (head == null)
return;
Node max, t, out = null, h = new Node();
h.next = head;
while (h.next != null) {
// display();
TextIO.putln("max=" + (max = findmax(h)).next);
t = max.next;
max.next = t.next;
t.next = out;
out = t;
}
head = out;
}
private Node findmax(Node h) {
char max = '\0';
Node maxNode = h;
for (Node tmp = h; tmp.next != null; tmp = tmp.next) {
if (tmp.next.data.c >= max) {
max = tmp.next.data.c;
maxNode = tmp;
}
}
return maxNode;
}
If not, a detailed advice will be highly helpful thanks. Mind you, I cannot use collection.sort or any other ready function, it has to be implemented.
Thanks
First of all I would like you to look at this link. It will give you idea of how Node class is implemented and generally how to implement list.
Assuming you read content from the link here are some comments;
public void sort() {
//this method does ascending sort of the list
TextIO.putln("sorting...");
if (head == null)
return;
Node max, t, out = null, h = new Node();
h.next=head; //make new list node let him point to beginning of the list(head)
while (h.next != null) { //until we get to the end of the list
// display();
TextIO.putln("max="+(max = findmax(h)).next);
//after findmax is finished we know reference
//to the node that contains max value
//and we need to bring that node to the beginning of the list
//that requires some reference rewiring
//first set t to point to next node from max
t = max.next;
//than max node will point to the next node from t
//this way max node becomes detached from list
max.next = t.next;
// now max node will point to some node that will represent new list head
// not new list just new list head
t.next = out;
out = t;
}
//after we complete sorting just point list head to the sorted list
head = out;
}
//find node that contains max value starting from some node
private Node findmax(Node h) {
//declare that max is null char
char max = '\0';
// set maxNode to be current node
Node maxNode = h;
//go through all nodes starting from current which is h
for (Node tmp = h; tmp.next != null; tmp = tmp.next) {
//if the data of some node in the list is bigger then our max value
if (tmp.next.data.c >= max) {
//then we are going to set that new value to be max
max = tmp.next.data.c;
// and set maxNode to be the node that has max value
maxNode = tmp;
}
}
return maxNode;
}
My advice is to look at provided link and start using good old pen an paper. That is the best way to understand what is going on with list pointers and nodes.
But if you do not want pen and paper you could go to this link that will show you animation of basic list operations.

Duplicate a LinkedList with a pointer to a random node apart from the next node

Q: Every node of the linked list has a random pointer (in addition to the next pointer) which could randomly point to another node or be null. How would you duplicate such a linkedlist?
A: Here's what I have, I just wanted to ratify if this was the optimal way of doing it.
Since there's no space constraints specified, I'm going to use a LinkedHashSet and a LinkedHashMap (I can imagine people nodding their head in disagreement already ;) )
First Iteration: Do the obvious - read each node from the list to be copied and create nodes on the new list. Then, read the random node like so: this.random.data and insert into the LinkedHashSet.
Second Iteration: Iterate through the new list and add each node's data as the first column and the node itself as the second column into the LinkedHashMap (doesn't have to be Linked, but I'm just going with the flow).
Third Iteration: Iterate over the LinkedHashSet (this is the reason why this needs to be Linked - predictable ordering) and the new list simultaneously. For the first node, read the first entry of the LinkedHashSet, look up the corresponding object in the LinkedHashMap and add as the random node to the current node in the new list.
3 iterations does seem a little crazy, but the attempt was to keep the complexity as O(N). Any solution that improves on the O(3N) space requirement and O(3N) runtime complexity would be great. Thanks!
Edit: The entry from the LinkedHashSet can be removed when making an entry into the LinkedHashMap, so this would only take O(2N) space.
As pointed out by MahlerFive, I think you can do this with O(2N) runtime complexity, and O(N) space complexity.
Let's assume you have
public class Node {
private Node next;
private Node random;
private String data;
// getters and setters omitted for the sake of brevity
}
I would do a deep copy of a linked list of Nodes as:
private Node deepCopy(Node original) {
// We use the following map to associate newly created instances
// of Node with the instances of Node in the original list
Map<Node, Node> map = new HashMap<Node, Node>();
// We scan the original list and for each Node x we create a new
// Node y whose data is a copy of x's data, then we store the
// couple (x,y) in map using x as a key. Note that during this
// scan we set y.next and y.random to null: we'll fix them in
// the next scan
Node x = original;
while (x != null) {
Node y = new Node();
y.setData(new String(x.getData()));
y.setNext(null);
y.setRandom(null);
map.put(x, y);
x = x.getNext();
}
// Now for each Node x in the original list we have a copy y
// stored in our map. We scan again the original list and
// we set the pointers buildings the new list
x = original;
while (x != null) {
// we get the node y corresponding to x from the map
Node y = map.get(x);
// let x' = x.next; y' = map.get(x') is the new node
// corresponding to x'; so we can set y.next = y'
y.setNext(map.get(x.getNext()));
// let x'' = x.random; y'' = map.get(x'') is the new
// node corresponding to x''; so we can set y.random = y''
y.setRandom(map.get(x.getRandom()));
x = x.getNext();
}
// finally we return the head of the new list, that is the Node y
// in the map corresponding to the Node original
return map.get(original);
}
Edit: I found that this question is a duplicate of the one asked here: there you find an answer that shows how to solve this problem in O(3N) runtime complexity with no extra space: very ingenious! But it uses a trick with C pointers, and I'm not sure how to do the same in java.
You can do this with 2N steps and a map with N elements.
Walk the old list following the 'next' pointers. For each node you visit, add a node to your new list, connect the previous node in your new list to the new node, store the old node random pointer in the new new node, then store a mapping of the old node pointer to the new node pointer in a map.
Walk the new list, and for each random pointer, look it up in the map to find the associated node in the new list to replace it with.
I too was asked this question in interview recently.
Here is what i proposed.
Create a map of original list nodes where addreess of each node will be key and the offset of random pointer will be the value.
Now create a new linked list with random pointer =null from the original map.
In the end, iterate through the original list , with the help of map get offset of original pointer and use that offset to link random pointer in newly created map.
Interviewer was not happy in the end.May be looking for some better approach or he had the set answer in his mind and unable to grasp new way of solving it.
in O(n) time and with constant space
public class CloneLinkedListWithRandomPointer {
public static void main(String[] args) throws Exception {
SpecialLink link = new SpecialLink(1);
SpecialLink two = new SpecialLink(2);
SpecialLink three = new SpecialLink(3);
SpecialLink four = new SpecialLink(4);
SpecialLink five = new SpecialLink(5);
link.next = two;
two.next = three;
three.next = four;
four.next = five;
link.random = four;
two.random = five;
three.random = null;
four.random = five;
five.random=link;
SpecialLink copy = cloneSpecialLinkedList(link);
System.out.println(link);
System.out.println(copy);
}
public static SpecialLink cloneSpecialLinkedList(SpecialLink link) throws Exception{
SpecialLink temp = link;
while(temp != null){
temp.next = (SpecialLink) temp.clone();
temp = temp.next==null?temp.next:temp.next.next;
}
temp = link;
while(temp != null){
temp.next.random = temp.random!=null?temp.random.next:null;
temp = temp.next==null?temp.next:temp.next.next;
}
SpecialLink copy = link.next;
temp = link;
SpecialLink copyTemp = copy;
while(temp.next!= null && copyTemp.next != null){
temp.next = temp.next.next;
copyTemp.next = copyTemp.next.next;
temp = temp.next;
copyTemp = copyTemp.next;
}
return copy;
}
}
class SpecialLink implements Cloneable{
enum Type{
ORIGINAL,COPY
}
int val;
SpecialLink next;
SpecialLink random;
Type type;
public void setValue(int value){
this.val = value;
}
public SpecialLink addNode(int value){
return next = new SpecialLink(value);
}
public SpecialLink(int value) {
super();
this.val = value;
this.type = Type.ORIGINAL;
}
#Override
public String toString() {
SpecialLink temp = this;
StringBuilder builder = new StringBuilder();
while(temp != null){
builder.append(temp.val).append("--").append(temp.type.toString()).append("->").append(temp.random == null? null:temp.random.val).append("--").append(temp.random == null? null:temp.random.type);
builder.append(", ");
temp = temp.next;
}
return builder.toString();
}
#Override
public Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
SpecialLink clone = (SpecialLink) super.clone();
clone.type = Type.COPY;
return clone;
}
}
Walk the list and use clone()?
I wrote code for #MahlerFive 's solution, which works without mapping.
Here's the code:
private static class Node {
private String item;
private Node next;
private Node random;
}
public static Node cloneLinkedStructure(Node head) {
// make holes after each original node
for (Node p = head; p != null;) {
Node pnext = p.next;
Node hole = new Node();
hole.item = ".";
p.next = hole;
hole.next = pnext;
p = pnext;
}
Node fakeHead = new Node(); // fake new head
Node q = fakeHead;
Node p = head;
while (p != null) {
// build the new linked structure
Node oldq = q;
q = new Node();
q.item = p.item;
oldq.next = q;
q.random = p.random.next; // link to a hole
Node hole = p.next;
hole.random = q; // use link RANDOM as a backward link to new node
p = hole.next;
}
q.next = null;
Node newHead = fakeHead.next; // throw fake head
// build random links for the new linked structure
for (q = newHead; q != null; q = q.next)
q.random = q.random.random;
// delete holes to restore original linked structure
for (p = head; p != null; p = p.next)
p.next = p.next.next;
return newHead;
}
1) Create the copy of node 1 and insert it between node 1 & node 2 in original Linked List, create the copy of 2 and insert it between 2 & 3.. Continue in this fashion, add the copy of N afte the Nth node
2) Now copy the arbitrary link in this fashion
original->next->arbitrary = original->arbitrary->next; /*TRAVERSE TWO NODES*/
This works because original->next is nothing but copy of original and Original->arbitrary-> next is nothing but copy of arbitrary.
3) Now restore the original and copy linked lists in this fashion in a single loop.
original->next = original->next->next;
copy->next = copy->next->next;
4) Make sure that last element of original->next is NULL.
Time Complexity: O(n)
Auxiliary Space: O(1)
source
Here is the Java implementation:
public static <T> RandomLinearNode<T> clone(RandomLinearNode<T> head) {
if (head == null) {
return head;
}
RandomLinearNode<T> itr = head, temp;
// insert copy nodes after each original nodes
while (itr != null) {
temp = new RandomLinearNode<T>(itr.getElement());
temp.next(itr.next());
itr.next(temp);
itr = temp.next();
}
// copy the random pointer
itr = head;
while (itr != null && itr.next() != null) {
if (itr.random() != null) {
itr.next().random(itr.random().next());
}
itr = itr.next().next();
}
// break the list into two
RandomLinearNode<T> newHead = head.next();
itr = head;
while (itr != null && itr.next() != null) {
temp = itr.next();
itr.next(temp.next());
itr = temp.next();
}
return newHead;
}
Here is the unit tests
#Test
public void cloneLinkeListWithRandomPointerTest() {
RandomLinearNode<Integer> one = new RandomLinearNode<Integer>(1, null, null);
RandomLinearNode<Integer> two = new RandomLinearNode<Integer>(2, one, null);
RandomLinearNode<Integer> three = new RandomLinearNode<Integer>(3, two, null);
RandomLinearNode<Integer> four = new RandomLinearNode<Integer>(4, three, null);
RandomLinearNode<Integer> five = new RandomLinearNode<Integer>(5, four, four);
RandomLinearNode<Integer> six = new RandomLinearNode<Integer>(6, five, two);
RandomLinearNode<Integer> seven = new RandomLinearNode<Integer>(7, six, three);
RandomLinearNode<Integer> eight = new RandomLinearNode<Integer>(8, seven, one);
RandomLinearNode<Integer> newHead = LinkedListUtil.clone(eight);
assertThat(eight, not(sameInstance(newHead)));
assertThat(newHead.getElement(), equalTo(eight.getElement()));
assertThat(newHead.random().getElement(), equalTo(eight.random().getElement()));
assertThat(newHead.next().getElement(), equalTo(eight.next().getElement()));
assertThat(newHead.next().random().getElement(), equalTo(eight.next().random().getElement()));
assertThat(newHead.next().next().getElement(), equalTo(eight.next().next().getElement()));
assertThat(newHead.next().next().random().getElement(), equalTo(eight.next().next().random().getElement()));
assertThat(newHead.next().next().next().getElement(), equalTo(eight.next().next().next().getElement()));
assertThat(newHead.next().next().next().random().getElement(), equalTo(eight.next().next().next().random().getElement()));
}

How can I implement extendible hashing in java?

extendible hashing is one of the best hashing method,I want to create program in java, for extenidble hashing. is there any api available for doing that? i dont get the clear algorithm for doing that myself, so if there is no api, .if possible post algoirhtm
I'm just curious, why do you need to implement such an algorithm? Are the standard Java Map implementations not performing for you? If you are suffering from an issue of buckets becoming too heavily loaded you may want to take a look at the hashCode() method before opting for non-standard routes. An alternative could also be to look at some of the options provided by GNU Trove.
Finally - a similar algorithm to Extendible is Cuckoo hashing. Some information below:
http://en.wikipedia.org/wiki/Cuckoo_hashing
Source code here:
http://lmonson.com/blog/?page_id=99
This file defines a HashTable class. Keys and values in the hash table
are of type Object. Keys cannot be null. The default constructor
creates a table that initially has 64 locations, but a different
initial size can be specified as a parameter to the constructor.
The table increases in size if it becomes more than 3/4 full.
public class HashTable {
static private class ListNode {
// Keys that have the same hash code are placed together
// in a linked list. This private nested class is used
// internally to implement linked lists. A ListNode
// holds a (key,value) pair.
Object key;
Object value;
ListNode next; // Pointer to next node in the list;
// A null marks the end of the list.
}
private ListNode[] table; // The hash table, represented as
// an array of linked lists.
private int count; // The number of (key,value) pairs in the
// hash table.
public HashTable() {
// Create a hash table with an initial size of 64.
table = new ListNode[64];
}
public HashTable(int initialSize) {
// Create a hash table with a specified initial size.
// Precondition: initalSize > 0.
table = new ListNode[initialSize];
}
void dump() {
// This method is NOT part of the usual interface for
// a hash table. It is here only to be used for testing
// purposes, and should be removed before the class is
// released for general use. This lists the (key,value)
// pairs in each location of the table.
System.out.println();
for (int i = 0; i < table.length; i++) {
// Print out the location number and the list of
// key/value pairs in this location.
System.out.print(i + ":");
ListNode list = table[i]; // For traversing linked list number i.
while (list != null) {
System.out.print(" (" + list.key + "," + list.value + ")");
list = list.next;
}
System.out.println();
}
} // end dump()
public void put(Object key, Object value) {
// Associate the specified value with the specified key.
// Precondition: The key is not null.
int bucket = hash(key); // Which location should this key be in?
ListNode list = table[bucket]; // For traversing the linked list
// at the appropriate location.
while (list != null) {
// Search the nodes in the list, to see if the key already exists.
if (list.key.equals(key))
break;
list = list.next;
}
// At this point, either list is null, or list.key.equals(key).
if (list != null) {
// Since list is not null, we have found the key.
// Just change the associated value.
list.value = value;
}
else {
// Since list == null, the key is not already in the list.
// Add a new node at the head of the list to contain the
// new key and its associated value.
if (count >= 0.75*table.length) {
// The table is becoming too full. Increase its size
// before adding the new node.
resize();
}
ListNode newNode = new ListNode();
newNode.key = key;
newNode.value = value;
newNode.next = table[bucket];
table[bucket] = newNode;
count++; // Count the newly added key.
}
}
public Object get(Object key) {
// Retrieve the value associated with the specified key
// in the table, if there is any. If not, the value
// null will be returned.
int bucket = hash(key); // At what location should the key be?
ListNode list = table[bucket]; // For traversing the list.
while (list != null) {
// Check if the specified key is in the node that
// list points to. If so, return the associated value.
if (list.key.equals(key))
return list.value;
list = list.next; // Move on to next node in the list.
}
// If we get to this point, then we have looked at every
// node in the list without finding the key. Return
// the value null to indicate that the key is not in the table.
return null;
}
public void remove(Object key) {
// Remove the key and its associated value from the table,
// if the key occurs in the table. If it does not occur,
// then nothing is done.
int bucket = hash(key); // At what location should the key be?
if (table[bucket] == null) {
// There are no keys in that location, so key does not
// occur in the table. There is nothing to do, so return.
return;
}
if (table[bucket].key.equals(key)) {
// If the key is the first node on the list, then
// table[bucket] must be changed to eliminate the
// first node from the list.
table[bucket] = table[bucket].next;
count--; // Remove new number of items in the table.
return;
}
// We have to remove a node from somewhere in the middle
// of the list, or at the end. Use a pointer to traverse
// the list, looking for a node that contains the
// specified key, and remove it if it is found.
ListNode prev = table[bucket]; // The node that precedes
// curr in the list. Prev.next
// is always equal to curr.
ListNode curr = prev.next; // For traversing the list,
// starting from the second node.
while (curr != null && ! curr.key.equals(key)) {
curr = curr.next;
prev = curr;
}
// If we get to this point, then either curr is null,
// or curr.key is equal to key. In the later case,
// we have to remove curr from the list. Do this
// by making prev.next point to the node after curr,
// instead of to curr. If curr is null, it means that
// the key was not found in the table, so there is nothing
// to do.
if (curr != null) {
prev.next = curr.next;
count--; // Record new number of items in the table.
}
}
public boolean containsKey(Object key) {
// Test whether the specified key has an associated value
// in the table.
int bucket = hash(key); // In what location should key be?
ListNode list = table[bucket]; // For traversing the list.
while (list != null) {
// If we find the key in this node, return true.
if (list.key.equals(key))
return true;
list = list.next;
}
// If we get to this point, we know that the key does
// not exist in the table.
return false;
}
public int size() {
// Return the number of key/value pairs in the table.
return count;
}
private int hash(Object key) {
// Compute a hash code for the key; key cannot be null.
// The hash code depends on the size of the table as
// well as on the value returned by key.hashCode().
return (Math.abs(key.hashCode())) % table.length;
}
private void resize() {
// Double the size of the table, and redistribute the
// key/value pairs to their proper locations in the
// new table.
ListNode[] newtable = new ListNode[table.length*2];
for (int i = 0; i < table.length; i++) {
// Move all the nodes in linked list number i
// into the new table. No new ListNodes are
// created. The existing ListNode for each
// key/value pair is moved to the newtable.
// This is done by changing the "next" pointer
// in the node and by making a pointer in the
// new table point to the node.
ListNode list = table[i]; // For traversing linked list number i.
while (list != null) {
// Move the node pointed to by list to the new table.
ListNode next = list.next; // The is the next node in the list.
// Remember it, before changing
// the value of list!
int hash = (Math.abs(list.key.hashCode())) % newtable.length;
// hash is the hash code of list.key that is
// appropriate for the new table size. The
// next two lines add the node pointed to by list
// onto the head of the linked list in the new table
// at position number hash.
list.next = newtable[hash];
newtable[hash] = list;
list = next; // Move on to the next node in the OLD table.
}
}
table = newtable; // Replace the table with the new table.
} // end resize()
} // end class HashTable
A Program for Testing HashTable:
A little program to test the HashTable class. Note that I start with a really small table so that I can easily test the resize() method.
public class TestHashTable {
public static void main(String[] args){
HashTable table = new HashTable(2);
String key,value;
while (true) {
System.out.println("\nMenu:");
System.out.println(" 1. test put(key,value)");
System.out.println(" 2. test get(key)");
System.out.println(" 3. test containsKey(key)");
System.out.println(" 4. test remove(key)");
System.out.println(" 5. show complete contents of hash table.");
System.out.println(" 6. EXIT");
System.out.print("Enter your command: ");
switch ( TextIO.getlnInt()) {
case 1:
System.out.print("\n Key = ");
key = TextIO.getln();
System.out.print(" Value = ");
value = TextIO.getln();
table.put(key,value);
break;
case 2:
System.out.print("\n Key = ");
key = TextIO.getln();
System.out.println(" Value is " + table.get(key));
break;
case 3:
System.out.print("\n Key = ");
key = TextIO.getln();
System.out.println(" containsKey(" + key + ") is "
+ table.containsKey(key));
break;
case 4:
System.out.print("\n Key = ");
key = TextIO.getln();
table.remove(key);
break;
case 5:
table.dump();
break;
case 6:
return; // End program by returning from main()
default:
System.out.println(" Illegal command.");
break;
}
System.out.println("\nHash table size is " + table.size());
}
}
} // end class TestHashTable
Preface: I do not know what is extendible hashing.
Based on what I understood from this wiki(http://en.wikipedia.org/wiki/Extendible_hashing), that it can search using maximum two lookups, you might want to look at the Java implementation of Bernstein DB (sg-cDB).
http://cr.yp.to/cdb.html
A Java implementation of extendible hashing:
http://en.wikibooks.org/wiki/Data_Structures/Hash_Tables#A_Java_implementation_of_extendible_hashing
As srini.venigalla says... the sg-cDB of Bernstein is good. You can found a ported version of CDB in pure Java made by Michael Alyn Miller in GitHub: https://github.com/malyn/sg-cdb
// Java program to demonstrate implementation of our
// own hash table with chaining for collision detection
import java.util.ArrayList;
// A node of chains
class HashNode<K, V>
{
K key;
V value;
// Reference to next node
HashNode<K, V> next;
// Constructor
public HashNode(K key, V value)
{
this.key = key;
this.value = value;
}
}
// Class to represent entire hash table
class Map<K, V>
{
// bucketArray is used to store array of chains
private ArrayList<HashNode<K, V>> bucketArray;
// Current capacity of array list
private int numBuckets;
// Current size of array list
private int size;
// Constructor (Initializes capacity, size and
// empty chains.
public Map()
{
bucketArray = new ArrayList<>();
numBuckets = 10;
size = 0;
// Create empty chains
for (int i = 0; i < numBuckets; i++)
bucketArray.add(null);
}
public int size() { return size; }
public boolean isEmpty() { return size() == 0; }
// This implements hash function to find index
// for a key
private int getBucketIndex(K key)
{
int hashCode = key.hashCode();
int index = hashCode % numBuckets;
return index;
}
// Method to remove a given key
public V remove(K key)
{
// Apply hash function to find index for given key
int bucketIndex = getBucketIndex(key);
// Get head of chain
HashNode<K, V> head = bucketArray.get(bucketIndex);
// Search for key in its chain
HashNode<K, V> prev = null;
while (head != null)
{
// If Key found
if (head.key.equals(key))
break;
// Else keep moving in chain
prev = head;
head = head.next;
}
// If key was not there
if (head == null)
return null;
// Reduce size
size--;
// Remove key
if (prev != null)
prev.next = head.next;
else
bucketArray.set(bucketIndex, head.next);
return head.value;
}
// Returns value for a key
public V get(K key)
{
// Find head of chain for given key
int bucketIndex = getBucketIndex(key);
HashNode<K, V> head = bucketArray.get(bucketIndex);
// Search key in chain
while (head != null)
{
if (head.key.equals(key))
return head.value;
head = head.next;
}
// If key not found
return null;
}
// Adds a key value pair to hash
public void add(K key, V value)
{
// Find head of chain for given key
int bucketIndex = getBucketIndex(key);
HashNode<K, V> head = bucketArray.get(bucketIndex);
// Check if key is already present
while (head != null)
{
if (head.key.equals(key))
{
head.value = value;
return;
}
head = head.next;
}
// Insert key in chain
size++;
head = bucketArray.get(bucketIndex);
HashNode<K, V> newNode = new HashNode<K, V>(key, value);
newNode.next = head;
bucketArray.set(bucketIndex, newNode);
// If load factor goes beyond threshold, then
// double hash table size
if ((1.0*size)/numBuckets >= 0.7)
{
ArrayList<HashNode<K, V>> temp = bucketArray;
bucketArray = new ArrayList<>();
numBuckets = 2 * numBuckets;
size = 0;
for (int i = 0; i < numBuckets; i++)
bucketArray.add(null);
for (HashNode<K, V> headNode : temp)
{
while (headNode != null)
{
add(headNode.key, headNode.value);
headNode = headNode.next;
}
}
}
}
// Driver method to test Map class
public static void main(String[] args)
{
Map<String, Integer>map = new Map<>();
map.add("this",1 );
map.add("coder",2 );
map.add("this",4 );
map.add("hi",5 );
System.out.println(map.size());
System.out.println(map.remove("this"));
System.out.println(map.remove("this"));
System.out.println(map.size());
System.out.println(map.isEmpty());
}
}
private ITEM[] st; private int N, M; ST(int maxN) { N = 0; M = 4; st = new ITEM[M]; } private void expand() { ITEM[] t = st; N = 0; M = M+M; st = new ITEM[M]; for (int i = 0; i < M/2; i++) if (t[i] != null) insert(t[i]); } void insert(ITEM x) { int i = hash(x.key(), M); while (st[i] != null) i = (i+1) % M; st[i] = x; if (N++ >= M/2) expand(); }
/*
A little program to test the HashTable class. Note that I
start with a really small table so that I can easily test
the resize() method.
*/
public class TestHashTable {
public static void main(String[] args){
HashTable table = new HashTable(2);
String key,value;
while (true) {
System.out.println("\nMenu:");
System.out.println(" 1. test put(key,value)");
System.out.println(" 2. test get(key)");
System.out.println(" 3. test containsKey(key)");
System.out.println(" 4. test remove(key)");
System.out.println(" 5. show complete contents of hash table.");
System.out.println(" 6. EXIT");
System.out.print("Enter your command: ");
switch ( TextIO.getlnInt()) {
case 1:
System.out.print("\n Key = ");
key = TextIO.getln();
System.out.print(" Value = ");
value = TextIO.getln();
table.put(key,value);
break;
case 2:
System.out.print("\n Key = ");
key = TextIO.getln();
System.out.println(" Value is " + table.get(key));
break;
case 3:
System.out.print("\n Key = ");
key = TextIO.getln();
System.out.println(" containsKey(" + key + ") is "
+ table.containsKey(key));
break;
case 4:
System.out.print("\n Key = ");
key = TextIO.getln();
table.remove(key);
break;
case 5:
table.dump();
break;
case 6:
return; // End program by returning from main()
default:
System.out.println(" Illegal command.");
break;
}
System.out.println("\nHash table size is " + table.size());
}
}
} // end class TestHashTable
Hashtable implements a key value pair kind of collection
*/
import java.util.*;
public class HashtableDemo {
static String newLine = System.getProperty("line.separator");
public static void main(String[] args) {
System.out.println(newLine + "Hashtable in Java" + newLine);
System.out.println("-----------------------" + newLine);
System.out.println("Adding items to the Hashtable" + newLine);
//Creating Hashtable object
//dictionary can be created using HashTable object
//as dictionary is an abstract class
Hashtable ht = new Hashtable();
//you add elements to Hashtable using put method
//put(key, value)
ht.put("Java", 1);
ht.put(".NET", 2);
ht.put("Javascript", 3 );
ht.put("HTML", 4);
//You will see that the items will be arranged as per the hash function
System.out.println(newLine + "Items in the Hashtable..." + ht + newLine);
System.out.println("-----------------------" + newLine);
//looping through all the elements in hashtable
String str;
//you can retrieve all the keys in hashtable using .keys() method
Enumeration names = ht.keys();
while(names.hasMoreElements()) {
//next element retrieves the next element in the dictionary
str = (String) names.nextElement();
//.get(key) returns the value of the key stored in the hashtable
System.out.println(str + ": " + ht.get(str) + newLine);
}
}
}

Categories