4

I was able to implement Hashtable using array by simply using the following data structure.

LinkedList<Item<K,V>> table[]
const int MAX_SIZE = 100

i.e an array of linked list(hashing with chaining).

Now in various books,they say we can implement a hashtable with a BST if we want ordered data. How do I incorporate both key and value in a BST. Although I can store both just as I store a single item of data, but the key gives an integer that acts like an index to the array after it has been to a hash function. How do I use the key in BST? I don't need any index?

What I can think of is that I can compare two keys using the function and then do normal insertion,deletion accordingly.

EDITS:

Suppose I have BST from scratch

class Node {
        K key;
        V value;
        Node left;
        Node right;
    }


class BinarySearchTree {
            Node root;
        }


class Hashtable {

BinarySearchTree bst;

public void Hashtable() {
bst = new BinarySearchTree();
}

//hashfunction(K key)

//get(K Key)

//put(K key,V value)

//remove(K key)

}

How do I use the key mapped to integer to implement the

insert(V value) 

in BST.

Hooli
  • 711
  • 2
  • 13
  • 24
  • I'm pretty new to programming, but couldn't you use a tree map instead? http://stackoverflow.com/questions/13373854/binary-search-tree-java-implementation – spuder Jun 24 '13 at 16:02

4 Answers4

2

There is already an implementation of BST in java - TreeMap. It's a self balancing red-black tree. I guess implementing it would not be a much problem. For example:

public class Hashtable<T, V> implements Map<T, V> {

    private TreeMap<T, V> bst;

    public Hashtable() {
        bst= new TreeMap<T, V>();
    }

    @Override
    public void put(T element, V value) {
        bst.put(element, value);
    }

    ...

}

Since Hashtable should be implementation of Map interface, I suggest implementing java.util.Map. I would use a BST through composition rather than inheritance - so we can hide the API of the BST. The BST can be anything - in my code example I used Java's TreeMap class.

darijan
  • 9,725
  • 25
  • 38
2

Java specific answers have already been provided but I am guessing your question is more about the design rather than language specific implementation.

No, we do not need to calculate an index or use a hashing function. If we store the key,value pairs in the nodes of the bst, then its just a matter of traversing the tree by comparing the keys. This also gives you the added advantage of no collisions since the keys are unique.

You could use a hashing function and hash the key and then traverse the tree based on that value but this can lead to collisions if you are not careful with the hash function and then you would have to maintain some sort of chaining.

Whether to use the key or the hashed value of the key depends on the size of the key. If the key size is large, it makes sense to hash it to a smaller size for faster comparison.

pmathew
  • 21
  • 1
0

You don't need to implement the hash table with link list. It's only the case when the collision happens instead of using chaining which takes linear time to search O(n) , you can use a balanced bst so that the search time reduces to O(log n).

Vishal
  • 481
  • 1
  • 6
  • 14
0

Here is a simple implementation of HashMap with BST as buckets. This basic implementation of Map shows how put() and get() works to get data from Map backed by BST buckets. This BST implementation is NOT balanced. Ideally for production applications, this BST should be balanced using Red-Black tree algorithm to improve seek time.

With buckets implemented using balanced BST compared to Linked Lists, we are able to improve Get(key) time from O(n) to O(log n).

public class HashMapWithBST {

    private Node[] nodes;
    private static final int MAX_CAPACITY = 41;

    public HashMapWithBST() {
        nodes = new Node[MAX_CAPACITY];
    }

    /**
     * If key is a non-null object then return the hash code of key modulo hash map size as value. If key is null then return 0.
     * 
     * @param key
     * @return hash
     */
    public int getHash(String key) {

        if(key == null) {
            return 0;
        }

        int hash = key.hashCode();

        hash = hash >>> 16; // Spread the higher bits

        hash = hash % MAX_CAPACITY;

        return hash;
    }

    /**
     * In case of collisions, put the new key-value pair in a BST based on key comparisons.
     * 
     * @param key
     * @param value
     */
    public void put(String key, String value) {

        int hashOfKey = getHash(key);

        final Node newNode = new Node(key, value);

        if(nodes[hashOfKey] == null) {

            nodes[hashOfKey] = newNode;
        } else {

            Node root = nodes[hashOfKey];

            try {
                addToBSTBucket(root, newNode);
            } catch(Exception e ) {
                e.printStackTrace();
            }
        }

    }

    /**
     * If a collision happens while adding a node to Hashmap, add new node to the hashed bucket represented with a BST.
     * 
     * @param root      root of BST bucket
     * @param newNode   New Node to be added in BST bucket
     */
    private void addToBSTBucket(Node root, final Node newNode) {

        if(root == null) {
            root = newNode;
            return;
        }

        Node currentNode = root;
        Node parentNode = root;

        while(true) {

            parentNode = currentNode;

            if(newNode.key.compareTo(currentNode.key) == 0) {

                // if key values are same then just overwrite the vale in same node as duplicate keys are not allowed in this map
                currentNode.value = newNode.value;
                return;

            } else if(newNode.key.compareTo(currentNode.key) < 0) {
                currentNode = currentNode.left;

                if(currentNode == null) {
                    parentNode.left = newNode;
                    return;
                }
            } else {

                currentNode = currentNode.right;

                if(currentNode == null) {
                    parentNode.right = newNode;
                    return;
                }
            } 
        }

    }

    /**
     * Get the value for a particular key. If no key found then return null.
     * 
     * @param key
     * @return value or null
     */
    public String get(String key) {

        Node node = nodes[getHash(key)];

        if(node != null) {
            return getValueFromBST(node, key);
        }

        return null;
    }

    private String getValueFromBST(Node root, String key) {

        if(key == null) {
            return null;
        }

        while(root != null) {
            if(key.equals(root.key)) {
                return root.value;
            } else if(key.compareTo(root.key) < 0) {
                root = root.left;
            } else {
                root = root.right;
            }
        }

        return null;    
    }

    private static class Node {

        private String key;
        private String value;
        private Node left;
        private Node right;

        public Node(String key, String value) {
            this.key = key;
            this.value = value;
        }

    }
}

The complete code is located here: https://github.com/prabhash1785/DataStructures/blob/d842d07e1fc3bf7e1caed72eb6b0744a719a9bc6/src/com/prabhash/java/algorithms/datastructures/HashMapWithBST.java

Prabhash Rathore
  • 709
  • 10
  • 18
  • What is the purpose of spreading the higher bits? `hash = hash >>> 16; // Spread the higher bits` Won't that essentially zero out any number less than about 100,000? – Ryan Quinn May 13 '17 at 01:07