Dictionary or Map

  • Dictionary or map is a data structure in Computer Science

  • Dictionary/map: (a.k.a an associative array)

    • A dictionary is a data structure that consists of a collection of (key, value) pairs called a entry of a dictionary

      Note: the key and the value can be composite

  • Example 1: (Word, Definition) (a.k.a a dictionary)

     ("gatekeeper", "a person who guards a gate")
     ("gateway",    "an opening for a gate")  ...
    

  • Example 2: (Name, Phone) (a.k.a a telephone book)

     ("Peter",    "404-455-8954")
     ("John",     "770-786-9899")  ...
    

Usage of and operations on a dictionary

  • Usage of a dictionary:

    • The dictionary data structure is used to store (key, value) pairs where the user can look up (= search) a value using the key

  • To support its usage, a dictionary must provide the following operations:

    • size(): return the number of entries stored inside this dictionary

    • put(key, value): if key is found in the dictionary, it updates the value with value, otherwise, it inserts (key,value) into the dictionary.

    • get(key): returns the corresponding value if key is found; and returns null otherwise.

    • remove(key): removes the dictionary entry containing key (and returns the corresponding value if key is found).

    The most frequenly used operation is get(key) --- fast look up required!

The Dictionary interface

  • We define an interface to describe the behavior of the Dictionary data structure:

      // Dictionary storing (key,value) pair of type K and V
    
      public interface Dictionary<K,V>
      {
          public int  size();        // Return # entries in the dictionary
    
          public void put(K k, V v); // Insert (k,v) if k not in dictionary
                                     // Otherwise update v for key k
    
          public V get(K k);         // Returns the value v for key k
                                     // Return null if k not in dictionary
    
          public V remove(K k);      // Remove entry (k, v) from dictionary
                                     // Return v when k found
    				 // Otherwise return null
      }
    

How to implement a dictionary data structure

  • We can implement the dictionary data strutures using:

    1. an array                                      or
    2. a linked list

  • Example how to implement/store a dictionary using an array:

  • Example how to implement/store a dictionary using a linked list:

Implementing a dictionary using an array

  • We will now implement the dictionary using an array:

  • What we will discuss next:

    • Definition of an Entry class to represent an entry in a dictionary

    • Definition of a class to represent a dictionary using an array

    • Implement the (support) methods for the dictionary

Representing an entry in a dictionary

  • An Entry in a dictionary can be represented by the following Java class:

        public class Entry<K,V>
        {
            private K key;   // The key (to loop up)
            private V value; // The value (corresponding to the key)
    
            public Entry(K k, V v)  // Constructor
            {   key = k;
                value = v;
            }
    
            /** Accessor method for the key */
    	public String getKey() {return key;}
    
    	/** Accessor method for the value */
    	public int getValue() {return value;}
    
    	/** Mutator method for the value */
    	public void setValue(int value) {this.value = value;}
    
            public String toString()
            {   return "(" + key + "," + value + ")";
            }
        }
    

Representing a dictionary

  • We now define the ArrayMap<K,V> class to represent/store a dictionary

  • A Dictionary consists of an array of Entry objects:

    public class ArrayMap<K,V> implements Dictionary<K,V>
    {
        Entry<K,V>[] entry;         // Dictionary
        int          nEntries;      // # Entries in dictionary
    
        public ArrayMap(int N)    // Constructor
        {
            entry = (Entry[]) new Entry[N];
            nEntries = 0;
        }
    
    
    }
    

  • Every class has a constructor to initialize the object....

    Let's write the constructor next...

Representing a dictionary

  • Technically, the syntax to instantiate a generic array is as follows:

    public class ArrayMap<K,V> implements Dictionary<K,V>
    {
        Entry<K,V>[] entry;         // Dictionary
        int          nEntries;      // # Entries in dictionary
    
        public ArrayMap(int N)    // Constructor
        {
            entry = new Entry<K,V>[N];  // Compile error
            nEntries = 0;
        }
    
    
    }
    

    However:   Java does not allow instantiation of generic arrays

    So we must omit the type parameters (you will get a unchecked warning)

Representing a dictionary

  • We will settle for the unchecked (type) array instantiation:

    public class ArrayMap<K,V> implements Dictionary<K,V>
    {
        Entry<K,V>[] entry;         // Dictionary
        int          nEntries;      // # Entries in dictionary
    
        public ArrayMap(int N)    // Constructor
        {
            entry = new Entry[N];
            nEntries = 0;
        }
    
    
    }
    

  • We will implement the supporting methods next....

     

Representing a dictionary

  • size( ): will simply return nEntries (= number of entries in the dictionary):

    public class ArrayMap<K,V> implements Dictionary<K,V>
    {
        Entry<K,V>[] entry;         // Dictionary
        int          nEntries;      // # Entries in dictionary
    
        public ArrayMap(int N)    // Constructor
        {
            entry = new Entry[N];
            nEntries = 0;
        }
    
        public int size()
        {
            return nEntries;
        }
    }
    

     

Implementing put(k, v)

  • put(k, v) will update/insert the dictionary entry containing key k:

        public void put(K k, V v)
        {
            for (int i = 0; i < nEntries; i++)
                if ( entry[i].getKey().equals(k) )
                {
                    // Found
                    entry[i].setValue(v);   // update value
                    return;
                }
    
            // Key not found --> insert (K,V)
            entry[nEntries] = new Entry(k,v);
            nEntries++;
        }
    

    Since we do not know the array index that store the entry containing key k, we will perform a linear search...

Implementing put(k, v)

  • Find the dictionary entry containing key k:

        public void put(K k, V v)
        {
            for (int i = 0; i < nEntries; i++)
                if ( entry[i].getKey().equals(k) )
                {
                    // Found
                    entry[i].setValue(v);   // update the value
                    return;
                }
    
            // Key not found --> insert (K,V)
            entry[nEntries] = new Entry(k,v);
            nEntries++;
        }
    

    If key k was found in the dictionary, we update the corresponding value
     

Implementing put(k, v)

  • If key k is not found, we insert the entry (k, v) into the dictionary:

        public void put(K k, V v)
        {
            for (int i = 0; i < nEntries; i++)
                if ( entry[i].getKey().equals(k) )
                {
                    // Found
                    entry[i].setValue(v);   // update the value
                    return;
                }
    
            // Key not found 
            entry[nEntries] = new Entry<K,V>(k,v); // insert (K,V)
            nEntries++;
        }
    

     
    We implement get(k) next...

Implementing get(k)

  • get(k) returns the corresponding value for key k if found and null otherwise:

        public void get(K k)
        {
            for (int i = 0; i < nEntries; i++)
                if ( entry[i].getKey().equals(k) )
                {
                    // Found
                    return entry[i].getValue();   
                }
    
            // Key not found
            return null;
        }
    

     
    We implement remove(k) next...

Implementing remove(k)

  • remove(k) removes the dictionary entry containing key k (returns the corresponding value):

        public V remove(K k)
        {
            boolean found = false;
            int loc = 0;
            V   ret = null;
    
            for (int i = 0; i < nEntries; i++)
                if ( entry[i].getKey().equals(k) )
                {
                    found = true;
                    loc = i;
                    break;
                }
    
            if ( found )
            {
                ret = entry[loc].getValue();   // Save return value
                for ( int i = loc+1; i < nEntries; i++ )
                    entry[i-1] = entry[i];    // Shift array
                nEntries--;
            }
            return ret;
        }
    

Implementing remove(k)

  • Initialize some help variables:

        public V remove(K k)
        {
            boolean found = false; // Indicate key not found
            int loc = -1;          // Contains index of key
            V   ret = null;        // Contain the return value (default = null)
    
            for (int i = 0; i < nEntries; i++)
                if ( entry[i].getKey().equals(k) )
                {
                    found = true;
                    loc = i;
                    break;
                }
    
            if ( found )
            {
                ret = entry[loc].getValue();   // Save return value
                for ( int i = loc+1; i < nEntries; i++ )
                    entry[i-1] = entry[i];    // Shift array
                nEntries--;
            }
            return ret;
        }
    

Implementing remove(k)

  • Find the key k in the dictionary:

        public V remove(K k)
        {
            boolean found = false; // Indicate key not found
            int loc = -1;          // Contains index of key
            V   ret = null;        // Contain the return value (default = null)
    
            for (int i = 0; i < nEntries; i++)
                if ( entry[i].getKey().equals(k) )
                {
                    found = true;  // Indicates key k was found
                    loc = i;       // Remember the index of the entry
                    break;
                }
    
            if ( found )
            {
                ret = entry[loc].getValue();   // Save return value
                for ( int i = loc+1; i < nEntries; i++ )
                    entry[i-1] = entry[i];    // Shift array
                nEntries--;
            }
            return ret;
        }
    

Implementing remove(k)

  • If found, remove entry[loc] and update the ret return value:

        public V remove(K k)
        {
            boolean found = false; // Indicate key not found
            int loc = -1;          // Contains index of key
            V   ret = null;        // Contain the return value (default = null)
    
            for (int i = 0; i < nEntries; i++)
                if ( entry[i].getKey().equals(k) )
                {
                    found = true;  // Indicates key k was found
                    loc = i;       // Remember the index of the entry
                    break;
                }
    
            if ( found )
            {
                ret = entry[loc].getValue();   // Update return value
                for ( int i = loc+1; i < nEntries; i++ )  // Delete entry [loc]
                    entry[i-1] = entry[i];    // Shift array
                nEntries--;
            }
            return ret;
        }
    

Organization...

  • Since the Entry<K,V> objects will only be used by methods inside the ArrayMap<K,V> class, we can make the Entry<K,V> class an inner class:

    public class ArrayMap<K,V> implements Dictionary<K,V>
    {
        // Make Entry an inner class of ArrayMap
        private class Entry<K,V>
        {
            private K key;     // Key
            private V value;   // Value
    
            public Entry(K k, V v)  // Constructor
            {
                key = k;
                value = v;
            }
    
            // ... methods omitted for brevity
        }
    
        Entry<K,V>[] entry;         // Dictionary
        int          nEntries;      // # Entries in dictionary
    
        ...
    }
    

DEMO: 15-hashing/02-dictionary/ArrayMap.java

Demo program 1: put() and get()

    public static void main(String[] args)
    {
       Dictionary H = new ArrayMap<>(10);

       H.put("ice", "cold");
       H.put("fire", "hot");
       H.put("rock", "hard"); 
       H.put("wool", "soft");
       H.put("sun", "hot");
       H.put("sun", "**bright**");   // Update !
       H.put("moon", "shine");
 
       System.out.println("\n**** Test get(): ****");
       System.out.println("ice:" + H.get("ice"));
       System.out.println("fire:" + H.get("fire"));
    }

DEMO: 15-hashing/02-dictionary/Demo.java

Demo program 2: remove()

    public static void main(String[] args)
    {
       Dictionary H = new ArrayMap<>(10);

       H.put("ice", "cold");
       H.put("fire", "hot");
       H.put("rock", "hard");
       H.put("wool", "soft");
       H.put("sun", "hot");

       System.out.println("\nInitial hash table:");
       System.out.print(H);
       System.out.println("#Items = " + H.size() + "\n\n");

       System.out.println("\nTest remove():");
       System.out.println("-- ice:" + H.remove("ice"));
       System.out.print(H);
       System.out.println("#Items = " + H.size() + "\n");
       System.out.println("-- fire:" + H.remove("fire"));
       System.out.print(H);
       System.out.println("#Items = " + H.size() + "\n");
       System.out.println("-- sun:" + H.remove("sun"));
       System.out.print(H);
       System.out.println("#Items = " + H.size() + "\n");
    }

DEMO: 15-hashing/02-dictionary/Demo2.java

Problem with the ArrayMap implementation

  • A dictionary is used to lookup information (= value) for a given key

  • The lookup operation get( ) is O(n):

        public void get(K k)
        {
            for (int i = 0; i < nEntries; i++)
                if ( entry[i].getKey().equals(k) )
                {
                    // Found
                    return entry[i].getValue();   
                }
    
            // Key not found
            return null;
        }
    

  • Can we do better than O(n) ???

    • Yes, we can sort the array on key --- use binary search: O(log(n))

  • Can we do better than O(log(n)) ???        like: O(1) ???....