2013-02-11 2 views
0

그래서 여기서는 HashTable 구현을 사용하여 배열 만 사용하여 작성했으며 코드에 대한 도움이 조금 있습니다. 불행히도 "get"또는 "put"메소드를 실행하는 동안 누군가가 추가 한 행 중 하나를 이해하지 못합니다. 아래 while 루프에서 정확히 무슨 일이 일어나고 있습니까? 이것은 선형 프로빙에 대한 올바른 방법입니까? 또한 루프가 점검중인 조건을 확인하는 이유는 무엇입니까? 특히Java HashTable 구현의 선형 탐색

,

int hash = hashThis(key); 

    while(data[hash] != AVAILABLE && data[hash].key() != key) { 

     hash = (hash + 1) % capacity; 
    } 

여기에 전체 참조 아래의 전체 Java 클래스입니다.

public class Hashtable2 { 

private Node[] data; 
private int capacity; 
private static final Node AVAILABLE = new Node("Available", null); 

public Hashtable2(int capacity) { 

    this.capacity = capacity; 
    data = new Node[capacity]; 
    for(int i = 0; i < data.length; i++) { 

     data[i] = AVAILABLE; 
    } 
} 

public int hashThis(String key) { 

    return key.hashCode() % capacity; 
} 

public Object get(String key) { 

    int hash = hashThis(key); 

    while(data[hash] != AVAILABLE && data[hash].key() != key) { 

     hash = (hash + 1) % capacity; 
    } 
    return data[hash].element(); 
} 

public void put(String key, Object element) { 

    if(key != null) { 
     int hash = hashThis(key); 
     while(data[hash] != AVAILABLE && data[hash].key() != key) { 

      hash = (hash + 1) % capacity; 
     } 

     data[hash] = new Node(key, element); 

    } 

} 



public String toString(){ 

    String s="<"; 

    for (int i=0;i<this.capacity;i++) 
    { 
     s+=data[i]+", ";  

    } 

    s+=">"; 

    return s; 
    } 

감사합니다.

답변

1

방금 ​​코드의 일부를 다시 작성하고 findHash 메소드를 추가했습니다. 코드 중복을 피하십시오!

private int findHash(String key) { 
    int hash = hashThis(key); 

    // search for the next available element or for the next matching key 
    while(data[hash] != AVAILABLE && data[hash].key() != key) { 

     hash = (hash + 1) % capacity; 
    } 
    return hash; 
} 

public Object get(String key) { 

    return data[findHash(key)].element(); 
} 

public void put(String key, Object element) { 

    data[findHash(key)] = new Node(key, element); 
} 

당신이 물어 본 것은 정확히 무엇입니까? 찾은 해시 루프는 무엇입니까? 데이터는 AVAILABLE으로 초기화되었습니다. 즉, 데이터에는 실제 데이터가 포함되어 있지 않습니다. 이제 put과 함께 요소를 추가 할 때 - 먼저 hashValue가 계산됩니다. 즉, 데이터를 넣을 배열 data의 색인 일뿐입니다. 이제 - 위치가 이미 동일한 해시 값이지만 다른 키를 가진 다른 요소에 의해 취해진 것을 발견하면 다음 AVAILABLE 위치를 찾습니다. 그리고 get 방법은 본질적으로 동일하게 작동합니다. 다른 키를 가진 데이터 요소가 탐지되면 다음 요소가 조사되는 식으로 계속됩니다. data 자체는 소위 링 버퍼입니다. 즉, 배열의 끝까지 검색되고 인덱스 0부터 시작하여 다시 검색됩니다. 이는 모듈러스 % 연산자로 수행됩니다.

괜찮습니까?

+0

P. 구현에는 몇 가지 중요한 메서드가 없습니다. 해시가 가득 차면 해시를 더 크게 만듭니다. 이미 전체 해시에 요소를 넣으면 현재는 끝없이 반복됩니다. 또한 제거가 가능하지 않습니다. 이를위한 단위 테스트를 작성하십시오. –

+0

완벽한 감사합니다. 네, 확실히 추가 할 것입니다.이 것들을 익히는 것만으로도 배우게되어 기쁩니다! – user1493543

0

충돌 해결을 위해 Generics 및 Linear Probing을 사용하는 샘플 Hashtable 구현입니다. 구현 중에는 몇 가지 가정이 있으며 클래스와 메소드 위에 javadoc에 설명되어 있습니다.

이 구현 크기, 제거 등 키 집합 putAll에 같은 해시 테이블의 모든 방법을 가지고 있지만 얻을 같은 가장 자주 사용되는 방법을 포함, 넣지 않는 등

GET 코드의 반복이있다, 넣어 색인을 찾으려면 제거하고 색인을 찾는 새로운 방법을 갖도록 개선 할 수 있습니다. 위의 코드의

class HashEntry<K, V> { 
    private K key; 
    private V value; 
    public HashEntry(K key, V value) { 
     this.key = key; 
     this.value = value; 
    } 
    public void setKey(K key) { this.key = key; } 
    public K getKey() { return this.key; } 

    public void setValue(V value) { this.value = value; } 
    public V getValue() { return this.value; } 
} 

/** 
* Hashtable implementation ... 
* - with linear probing 
* - without loadfactor & without rehash implementation. 
* - throws exception when table is full 
* - returns null when trying to remove non existent key 
* 
* @param <K> 
* @param <V> 
*/ 
public class Hashtable<K, V> { 

    private final static int DEFAULT_CAPACITY = 16; 

    private int count; 
    private int capacity; 
    private HashEntry<K, V>[] table; 

    public Hashtable() { 
     this(DEFAULT_CAPACITY); 
    } 

    public Hashtable(int capacity) { 
     super(); 
     this.capacity = capacity; 
     table = new HashEntry[capacity]; 
    } 

    public boolean isEmpty() { return (count == 0); } 

    public int size() { return count; } 

    public void clear() { table = new HashEntry[this.capacity]; count = 0; } 

    /** 
    * Returns null if either probe count is higher than capacity else couldn't find the element. 
    * 
    * @param key 
    * @return 
    */ 
    public V get(K key) { 
     V value = null; 
     int probeCount = 0; 
     int hash = this.hashCode(key); 
     while (table[hash] != null && !table[hash].getKey().equals(key) && probeCount <= this.capacity) { 
      hash = (hash + 1) % this.capacity; 
      probeCount++; 
     } 
     if (table[hash] != null && probeCount <= this.capacity) { 
      value = table[hash].getValue(); 
     } 
     return value; 
    } 

    /** 
    * Check on the no of probes done and terminate if probe count reaches to its capacity. 
    * 
    * Throw Exception if table is full. 
    * 
    * @param key 
    * @param value 
    * @return 
    * @throws Exception 
    */ 
    public V put(K key, V value) throws Exception { 
     int probeCount = 0; 
     int hash = this.hashCode(key); 
     while (table[hash] != null && !table[hash].getKey().equals(key) && probeCount <= this.capacity) { 
      hash = (hash + 1) % this.capacity; 
      probeCount++; 
     } 
     if (probeCount <= this.capacity) { 
      if (table[hash] != null) { 
       table[hash].setValue(value);     
      } else { 
       table[hash] = new HashEntry(key, value); 
       count++; 
      } 
      return table[hash].getValue(); 
     } else { 
      throw new Exception("Table Full!!"); 
     } 
    } 

    /** 
    * If key present then mark table[hash] = null & return value, else return null. 
    * 
    * @param key 
    * @return 
    */ 
    public V remove(K key) { 
     V value = null; 
     int probeCount = 0; 
     int hash = this.hashCode(key); 
     while (table[hash] != null && !table[hash].getKey().equals(key) && probeCount <= this.capacity) { 
      hash = (hash + 1) % this.capacity; 
      probeCount++; 
     } 
     if (table[hash] != null && probeCount <= this.capacity) { 
      value = table[hash].getValue(); 
      table[hash] = null; 
      count--; 
     } 
     return value; 
    } 

    public boolean contains(Object value) { 
     return this.containsValue(value); 
    } 

    public boolean containsKey(Object key) { 
     for (HashEntry<K, V> entry : table) { 
      if (entry != null && entry.getKey().equals(key)) { 
       return true; 
      } 
     } 
     return false; 
    } 

    public boolean containsValue(Object value) { 
     for (HashEntry<K, V> entry : table) { 
      if (entry != null && entry.getValue().equals(value)) { 
       return true; 
      } 
     } 
     return false; 
    } 

    @Override 
    public String toString() { 
     StringBuilder data = new StringBuilder(); 
     data.append("{"); 
     for (HashEntry<K, V> entry : table) { 
      if (entry != null) { 
       data.append(entry.getKey()).append("=").append(entry.getValue()).append(", "); 
      } 
     } 
     if (data.toString().endsWith(", ")) { 
      data.delete(data.length() - 2, data.length()); 
     } 
     data.append("}"); 
     return data.toString(); 
    } 

    private int hashCode(K key) { return (key.hashCode() % this.capacity); } 

    public static void main(String[] args) throws Exception { 
     Hashtable<Integer, String> table = new Hashtable<Integer, String>(2); 
     table.put(1, "1"); 
     table.put(2, "2"); 
     System.out.println(table); 
     table.put(1, "3"); 
     table.put(2, "4"); 
     System.out.println(table); 
     table.remove(1); 
     System.out.println(table); 
     table.put(1, "1"); 
     System.out.println(table); 
     System.out.println(table.get(1)); 
     System.out.println(table.get(3)); 
     // table is full so below line 
     // will throw an exception 
     table.put(3, "2"); 
    } 
} 

샘플 실행됩니다.

{2=2, 1=1} 
{2=4, 1=3} 
{2=4} 
{2=4, 1=1} 
1 
null 
Exception in thread "main" java.lang.Exception: Table Full!! 
    at Hashtable.put(Hashtable.java:95) 
    at Hashtable.main(Hashtable.java:177)