我正在研究哈希表,并通过其实现来链接java。麻烦在于get()
方法。索引值由key.hashCode() % table.length
确定。假设表大小为10
且key.hashCode()为124
,因此索引为4
。对于每个循环table[index]
从table[4]
开始,AFAIK索引逐一递增4,5,6,7... so on
。但是指数0,1,2,3
怎么样?他们被检查了吗? (我认为不)是否有可能在其中一个指数上发生关键? (我想是的)。另一个问题是null
检查,但最初null
和key
没有任何value
分配。那么检查怎么办呢?声明null
后会private LinkedList<Entry<K, V>>[] table
被分配吗?
// Data Structures: Abstraction and Design Using Java, Koffman, Wolfgang
package KW.CH07;
import java.util.AbstractMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
/**
* Hash table implementation using chaining.
* @param <K> The key type
* @param <V> The value type
* @author Koffman and Wolfgang
**/
public class HashtableChain<K, V>
// Insert solution to programming project 7, chapter -1 here
implements KWHashMap<K, V> {
/** The table */
private LinkedList<Entry<K, V>>[] table;
/** The number of keys */
private int numKeys;
/** The capacity */
private static final int CAPACITY = 101;
/** The maximum load factor */
private static final double LOAD_THRESHOLD = 3.0;
// Note this is equivalent to java.util.AbstractMap.SimpleEntry
/** Contains key-value pairs for a hash table.
@param <K> the key type
@param <V> the value type
*/
public static class Entry<K, V>
// Insert solution to programming project 6, chapter -1 here
{
/** The key */
private final K key;
/** The value */
private V value;
/**
* Creates a new key-value pair.
* @param key The key
* @param value The value
*/
public Entry(K key, V value) {
this.key = key;
this.value = value;
}
/**
* Retrieves the key.
* @return The key
*/
@Override
public K getKey() {
return key;
}
/**
* Retrieves the value.
* @return The value
*/
@Override
public V getValue() {
return value;
}
/**
* Sets the value.
* @param val The new value
* @return The old value
*/
@Override
public V setValue(V val) {
V oldVal = value;
value = val;
return oldVal;
}
// Insert solution to programming exercise 3, section 4, chapter 7 here
}
// Constructor
public HashtableChain() {
table = new LinkedList[CAPACITY];
}
// Constructor for test purposes
HashtableChain(int capacity) {
table = new LinkedList[capacity];
}
/**
* Method get for class HashtableChain.
* @param key The key being sought
* @return The value associated with this key if found;
* otherwise, null
*/
@Override
public V get(Object key) {
int index = key.hashCode() % table.length;
if (index < 0) {
index += table.length;
}
if (table[index] == null) {
return null; // key is not in the table.
}
// Search the list at table[index] to find the key.
for (Entry<K, V> nextItem : table[index]) {
if (nextItem.getKey().equals(key)) {
return nextItem.getValue();
}
}
// assert: key is not in the table.
return null;
}
/**
* Method put for class HashtableChain.
* @post This key-value pair is inserted in the
* table and numKeys is incremented. If the key is already
* in the table, its value is changed to the argument
* value and numKeys is not changed.
* @param key The key of item being inserted
* @param value The value for this key
* @return The old value associated with this key if
* found; otherwise, null
*/
@Override
public V put(K key, V value) {
int index = key.hashCode() % table.length;
if (index < 0) {
index += table.length;
}
if (table[index] == null) {
// Create a new linked list at table[index].
table[index] = new LinkedList<>();
}
// Search the list at table[index] to find the key.
for (Entry<K, V> nextItem : table[index]) {
// If the search is successful, replace the old value.
if (nextItem.getKey().equals(key)) {
// Replace value for this key.
V oldVal = nextItem.getValue();
nextItem.setValue(value);
return oldVal;
}
}
// assert: key is not in the table, add new item.
table[index].addFirst(new Entry<>(key, value));
numKeys++;
if (numKeys > (LOAD_THRESHOLD * table.length)) {
rehash();
}
return null;
}
/** Returns true if empty
@return true if empty
*/
@Override
public boolean isEmpty() {
return numKeys == 0;
}
}
答案 0 :(得分:1)
我认为您无法正确显示哈希表。哈希表有两个同样好的简单实现。
方法1使用链表:链表的数组(实际上是Vector)。
给定“键”,您可以获得该键的哈希值(*)。您将该哈希值的剩余部分相对于向量的当前大小,我们称之为“x”。然后,您按顺序搜索向量[x]指向的链接列表,以便与您的密钥匹配。
(*)您希望哈希值分布合理。这样做有复杂的算法。让我们希望你的JVM实现HashCode做得很好。
方法2避免链接列表:您创建一个Vector并计算Vector中的索引(如上所述)。然后你看看Vector.get(x)。如果这是您想要的密钥,则返回相应的值。我们假设不是。然后你看看Vector.get(x + 1),Vector.get(x + 2)等。最后,将发生以下三件事之一:
a)您找到了您要找的钥匙。然后返回相应的值。 b)你找到一个空条目(key == null)。返回null或您选择的任何值意味着“这不是您正在寻找的机器人”。 c)您已检查过Vector中的每个条目。再次,返回null或其他。
检查(c)是一种预防措施,因此如果哈希表恰好已满,则不会永远循环。如果哈希表即将填满(您可以保留已使用的条目数),则应重新分配更大的哈希表。在IDeally,你想让哈希表保持足够稀疏,以至于你永远不会在 near 附近搜索整个表:这会破坏哈希表的整个目的 - 你可以用比线性更少的搜索它时间,理想情况是按顺序1(即,比较的数量是&lt; =小的常数)。我建议您分配一个至少是您希望放入其中的条目数的10倍的Vector。
在您的问题中使用“链接”一词表明您想要实现第二种类型的哈希表。
顺便说一句,你不应该使用10作为哈希表的大小。大小应该是素数。
希望这有帮助。
答案 1 :(得分:1)
假设表大小为10且key.hashCode()为124,因此索引为4.对于每个循环表[index]从表[4]
开始
正确。
有空检查,但最初没有任何关键和值的空赋值。那么检查怎么办呢?
初始化对象数组时,所有值都设置为null
。
索引逐一增加4,5,6,7 ......等等。但是指数0,1,2,3呢?他们被检查了吗? (我认为不是)是否有可能在其中一个指数上发生关键? (我想是的)。
看起来这里有一些误解。首先,考虑这样的数据结构(已经添加了数据):
table:
[0] -> null
[1] -> LinkedList -> item 1 -> item 2 -> item 3
[2] -> LinkedList -> item 1
[3] -> null
[4] -> LinkedList -> item 1 -> item 2
[5] -> LinkedList -> item 1 -> item 2 -> item 3 -> item 4
[6] -> null
另一个重要的一点是,给定key
的哈希码不应该更改,因此它将始终映射到表中的相同索引。
所以说我们称get
为一个值,其哈希码将其映射到3,然后我们知道它不在表中:
if (table[index] == null) {
return null; // key is not in the table.
}
如果另一个键映射到1,现在我们需要迭代LinkedList:
// LinkedList<Entry<K, V>> list = table[index]
for (Entry<K, V> nextItem : table[index]) {
// iterate over item 1, item 2, item 3 until we find one that is equal.
if (nextItem.getKey().equals(key)) {
return nextItem.getValue();
}
}