数据结构之Hashtable
来源:互联网 发布:windows10怎么隐藏软件 编辑:程序博客网 时间:2024/05/20 19:46
直接上JDK源码
Hashtable<K,V>源代码
public class Hashtableextends Dictionary implements Map , Cloneable, java.io.Serializable { private transient Entry,?>[] table; private transient int count; private int threshold; private float loadFactor; private transient int modCount = 0; private static final long serialVersionUID = 1421746759512286392L; public Hashtable(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal Load: "+loadFactor); if (initialCapacity==0) initialCapacity = 1; this.loadFactor = loadFactor; table = new Entry,?>[initialCapacity]; threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1); } public Hashtable(int initialCapacity) { this(initialCapacity, 0.75f); } public Hashtable() { this(11, 0.75f); } public Hashtable(Map extends K, ? extends V> t) { this(Math.max(2*t.size(), 11), 0.75f); putAll(t); } public synchronized int size() { return count; } public synchronized boolean isEmpty() { return count == 0; } public synchronized Enumeration keys() { return this. getEnumeration(KEYS); } public synchronized Enumeration elements() { return this. getEnumeration(VALUES); } public synchronized boolean contains(Object value) { if (value == null) { throw new NullPointerException(); } Entry,?> tab[] = table; for (int i = tab.length ; i-- > 0 ;) { for (Entry,?> e = tab[i] ; e != null ; e = e.next) { if (e.value.equals(value)) { return true; } } } return false; } public boolean containsValue(Object value) { return contains(value); } public synchronized boolean containsKey(Object key) { Entry,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry,?> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return true; } } return false; } @SuppressWarnings("unchecked") public synchronized V get(Object key) { Entry,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry,?> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return (V)e.value; } } return null; } private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; @SuppressWarnings("unchecked") protected void rehash() { int oldCapacity = table.length; Entry,?>[] oldMap = table; // overflow-conscious code int newCapacity = (oldCapacity << 1) + 1; if (newCapacity - MAX_ARRAY_SIZE > 0) { if (oldCapacity == MAX_ARRAY_SIZE) // Keep running with MAX_ARRAY_SIZE buckets return; newCapacity = MAX_ARRAY_SIZE; } Entry,?>[] newMap = new Entry,?>[newCapacity]; modCount++; threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1); table = newMap; for (int i = oldCapacity ; i-- > 0 ;) { for (Entry old = (Entry )oldMap[i] ; old != null ; ) { Entry e = old; old = old.next; int index = (e.hash & 0x7FFFFFFF) % newCapacity; e.next = (Entry )newMap[index]; newMap[index] = e; } } } private void addEntry(int hash, K key, V value, int index) { modCount++; Entry,?> tab[] = table; if (count >= threshold) { // Rehash the table if the threshold is exceeded rehash(); tab = table; hash = key.hashCode(); index = (hash & 0x7FFFFFFF) % tab.length; } // Creates the new entry. @SuppressWarnings("unchecked") Entry e = (Entry ) tab[index]; tab[index] = new Entry<>(hash, key, value, e); count++; } public synchronized V put(K key, V value) { // Make sure the value is not null if (value == null) { throw new NullPointerException(); } // Makes sure the key is not already in the hashtable. Entry,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry entry = (Entry )tab[index]; for(; entry != null ; entry = entry.next) { if ((entry.hash == hash) && entry.key.equals(key)) { V old = entry.value; entry.value = value; return old; } } addEntry(hash, key, value, index); return null; } public synchronized V remove(Object key) { Entry,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry )tab[index]; for(Entry prev = null ; e != null ; prev = e, e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } count--; V oldValue = e.value; e.value = null; return oldValue; } } return null; } public synchronized void putAll(Map extends K, ? extends V> t) { for (Map.Entry extends K, ? extends V> e : t.entrySet()) put(e.getKey(), e.getValue()); } public synchronized void clear() { Entry,?> tab[] = table; modCount++; for (int index = tab.length; --index >= 0; ) tab[index] = null; count = 0; } public synchronized Object clone() { try { Hashtable,?> t = (Hashtable,?>)super.clone(); t.table = new Entry,?>[table.length]; for (int i = table.length ; i-- > 0 ; ) { t.table[i] = (table[i] != null) ? (Entry,?>) table[i].clone() : null; } t.keySet = null; t.entrySet = null; t.values = null; t.modCount = 0; return t; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(e); } } public synchronized String toString() { int max = size() - 1; if (max == -1) return "{}"; StringBuilder sb = new StringBuilder(); Iterator > it = entrySet().iterator(); sb.append('{'); for (int i = 0; ; i++) { Map.Entry e = it.next(); K key = e.getKey(); V value = e.getValue(); sb.append(key == this ? "(this Map)" : key.toString()); sb.append('='); sb.append(value == this ? "(this Map)" : value.toString()); if (i == max) return sb.append('}').toString(); sb.append(", "); } } private Enumeration getEnumeration(int type) { if (count == 0) { return Collections.emptyEnumeration(); } else { return new Enumerator<>(type, false); } } private Iterator getIterator(int type) { if (count == 0) { return Collections.emptyIterator(); } else { return new Enumerator<>(type, true); } } private transient volatile Set keySet = null; private transient volatile Set > entrySet = null; private transient volatile Collection values = null; public Set keySet() { if (keySet == null) keySet = Collections.synchronizedSet(new KeySet(), this); return keySet; } private class KeySet extends AbstractSet { public Iterator iterator() { return getIterator(KEYS); } public int size() { return count; } public boolean contains(Object o) { return containsKey(o); } public boolean remove(Object o) { return Hashtable.this.remove(o) != null; } public void clear() { Hashtable.this.clear(); } } public Set > entrySet() { if (entrySet==null) entrySet = Collections.synchronizedSet(new EntrySet(), this); return entrySet; } private class EntrySet extends AbstractSet > { public Iterator > iterator() { return getIterator(ENTRIES); } public boolean add(Map.Entry o) { return super.add(o); } public boolean contains(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry,?> entry = (Map.Entry,?>)o; Object key = entry.getKey(); Entry,?>[] tab = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry,?> e = tab[index]; e != null; e = e.next) if (e.hash==hash && e.equals(entry)) return true; return false; } public boolean remove(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry,?> entry = (Map.Entry,?>) o; Object key = entry.getKey(); Entry,?>[] tab = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry )tab[index]; for(Entry prev = null; e != null; prev = e, e = e.next) { if (e.hash==hash && e.equals(entry)) { modCount++; if (prev != null) prev.next = e.next; else tab[index] = e.next; count--; e.value = null; return true; } } return false; } public int size() { return count; } public void clear() { Hashtable.this.clear(); } } public Collection values() { if (values==null) values = Collections.synchronizedCollection(new ValueCollection(), this); return values; } private class ValueCollection extends AbstractCollection { public Iterator iterator() { return getIterator(VALUES); } public int size() { return count; } public boolean contains(Object o) { return containsValue(o); } public void clear() { Hashtable.this.clear(); } } public synchronized boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Map)) return false; Map,?> t = (Map,?>) o; if (t.size() != size()) return false; try { Iterator > i = entrySet().iterator(); while (i.hasNext()) { Map.Entry e = i.next(); K key = e.getKey(); V value = e.getValue(); if (value == null) { if (!(t.get(key)==null && t.containsKey(key))) return false; } else { if (!value.equals(t.get(key))) return false; } } } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; } return true; } public synchronized int hashCode() { int h = 0; if (count == 0 || loadFactor < 0) return h; // Returns zero loadFactor = -loadFactor; // Mark hashCode computation in progress Entry,?>[] tab = table; for (Entry,?> entry : tab) { while (entry != null) { h += entry.hashCode(); entry = entry.next; } } loadFactor = -loadFactor; // Mark hashCode computation complete return h; } @Override public synchronized V getOrDefault(Object key, V defaultValue) { V result = get(key); return (null == result) ? defaultValue : result; } @SuppressWarnings("unchecked") @Override public synchronized void forEach(BiConsumer super K, ? super V> action) { Objects.requireNonNull(action); // explicit check required in case // table is empty. final int expectedModCount = modCount; Entry, ?>[] tab = table; for (Entry, ?> entry : tab) { while (entry != null) { action.accept((K)entry.key, (V)entry.value); entry = entry.next; if (expectedModCount != modCount) { throw new ConcurrentModificationException(); } } } } @SuppressWarnings("unchecked") @Override public synchronized void replaceAll(BiFunction super K, ? super V, ? extends V> function) { Objects.requireNonNull(function); // explicit check required in case // table is empty. final int expectedModCount = modCount; Entry [] tab = (Entry [])table; for (Entry entry : tab) { while (entry != null) { entry.value = Objects.requireNonNull( function.apply(entry.key, entry.value)); entry = entry.next; if (expectedModCount != modCount) { throw new ConcurrentModificationException(); } } } } @Override public synchronized V putIfAbsent(K key, V value) { Objects.requireNonNull(value); // Makes sure the key is not already in the hashtable. Entry,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry entry = (Entry )tab[index]; for (; entry != null; entry = entry.next) { if ((entry.hash == hash) && entry.key.equals(key)) { V old = entry.value; if (old == null) { entry.value = value; } return old; } } addEntry(hash, key, value, index); return null; } @Override public synchronized boolean remove(Object key, Object value) { Objects.requireNonNull(value); Entry,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry )tab[index]; for (Entry prev = null; e != null; prev = e, e = e.next) { if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) { modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } count--; e.value = null; return true; } } return false; } @Override public synchronized boolean replace(K key, V oldValue, V newValue) { Objects.requireNonNull(oldValue); Objects.requireNonNull(newValue); Entry,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry )tab[index]; for (; e != null; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { if (e.value.equals(oldValue)) { e.value = newValue; return true; } else { return false; } } } return false; } @Override public synchronized V replace(K key, V value) { Objects.requireNonNull(value); Entry,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry )tab[index]; for (; e != null; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { V oldValue = e.value; e.value = value; return oldValue; } } return null; } @Override public synchronized V computeIfAbsent(K key, Function super K, ? extends V> mappingFunction) { Objects.requireNonNull(mappingFunction); Entry,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry )tab[index]; for (; e != null; e = e.next) { if (e.hash == hash && e.key.equals(key)) { // Hashtable not accept null value return e.value; } } V newValue = mappingFunction.apply(key); if (newValue != null) { addEntry(hash, key, newValue, index); } return newValue; } @Override public synchronized V computeIfPresent(K key, BiFunction super K, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); Entry,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry )tab[index]; for (Entry prev = null; e != null; prev = e, e = e.next) { if (e.hash == hash && e.key.equals(key)) { V newValue = remappingFunction.apply(key, e.value); if (newValue == null) { modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } count--; } else { e.value = newValue; } return newValue; } } return null; } @Override public synchronized V compute(K key, BiFunction super K, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); Entry,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry )tab[index]; for (Entry prev = null; e != null; prev = e, e = e.next) { if (e.hash == hash && Objects.equals(e.key, key)) { V newValue = remappingFunction.apply(key, e.value); if (newValue == null) { modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } count--; } else { e.value = newValue; } return newValue; } } V newValue = remappingFunction.apply(key, null); if (newValue != null) { addEntry(hash, key, newValue, index); } return newValue; } @Override public synchronized V merge(K key, V value, BiFunction super V, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); Entry,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry )tab[index]; for (Entry prev = null; e != null; prev = e, e = e.next) { if (e.hash == hash && e.key.equals(key)) { V newValue = remappingFunction.apply(e.value, value); if (newValue == null) { modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } count--; } else { e.value = newValue; } return newValue; } } if (value != null) { addEntry(hash, key, value, index); } return value; } private void writeObject(java.io.ObjectOutputStream s) throws IOException { Entry
public abstractclass Dictionary{ public Dictionary() { } abstract public int size(); abstract public boolean isEmpty(); abstract public Enumeration keys(); abstract public Enumeration elements(); abstract public V get(Object key); abstract public V put(K key, V value); abstract public V remove(Object key);}
Map的源代码就不再叙述了
Hashtable是非泛型的集合,所以在检索和存储值类型时通常会发生装箱与拆箱的操作。
当把某个元素添加到 Hashtable 时,将根据键的哈希代码将该元素放入存储桶中,由于是散列算法所以会出现一个哈希函数能够为两个不同的键生成相同的哈希代码,该键的后续查找将使用键的哈希代码只在一个特定存储桶中搜索,这将大大减少为查找一个元素所需的键比较的次数。
Hashtable 的加载因子确定元素与Hashtable 可拥有的元素数的最大比率。加载因子越小,平均查找速度越快,但消耗的内存也增加。默认的加载因子 0.72通常提供速度和大小之间的最佳平衡。当创建 Hashtable 时,也可以指定其他加载因子。元素总量/ Hashtable 可拥有的元素数=加载因子
当向 Hashtable 添加元素时,Hashtable 的实际加载因子将增加。当实际加载因子达到指定的加载因子时,Hashtable 中存储桶的数目自动增加到大于当前 Hashtable 存储桶数两倍的最小素数。
扩容时所有的数据需要重新进行散列计算。虽然Hash具有O(1)的数据检索效率,但它空间开销却通常很大,是以空间换取时间。所以Hashtable适用于读取操作频繁,写入操作很少的操作类型。
当把某个元素添加到 Hashtable 时,将根据键的哈希代码将该元素放入存储桶中,由于是散列算法所以会出现一个哈希函数能够为两个不同的键生成相同的哈希代码,该键的后续查找将使用键的哈希代码只在一个特定存储桶中搜索,这将大大减少为查找一个元素所需的键比较的次数。
Hashtable 的加载因子确定元素与Hashtable 可拥有的元素数的最大比率。加载因子越小,平均查找速度越快,但消耗的内存也增加。默认的加载因子 0.72通常提供速度和大小之间的最佳平衡。当创建 Hashtable 时,也可以指定其他加载因子。元素总量/ Hashtable 可拥有的元素数=加载因子
当向 Hashtable 添加元素时,Hashtable 的实际加载因子将增加。当实际加载因子达到指定的加载因子时,Hashtable 中存储桶的数目自动增加到大于当前 Hashtable 存储桶数两倍的最小素数。
扩容时所有的数据需要重新进行散列计算。虽然Hash具有O(1)的数据检索效率,但它空间开销却通常很大,是以空间换取时间。所以Hashtable适用于读取操作频繁,写入操作很少的操作类型。
阅读全文
0 0
- 数据结构之hashtable
- 数据结构之Hashtable
- 数据结构探险之HashMap 与Hashtable
- Java 数据结构之 Hashtable(mark)
- java数据结构之散列集HashSet与散列表Hashtable
- 数据结构是哈希表(hashTable)
- Java 数据结构 --> Hashtable 接口
- 数据结构是哈希表(hashTable)
- 数据结构-HashTable的简单
- 数据结构—Hashtable(闭散列)
- 【数据结构】:哈希表(hashtable)
- 数据结构 hashtable C++实现 链式
- 数据结构-HashMap Hashtable HashSet
- Java数据结构源码分析-HashTable
- 数据结构大总结系列之从HASH谈到set/map再到hashtable/hash_map/hash_set
- 数据结构之HashTable(除留余数法—链地址法)
- 数据结构与算法分析之哈希表(HashTable,又称散列表)--理论篇
- 数据结构与算法分析之哈希表(HashTable,又称散列表)--代码篇
- 关于对qt connect函数的理解
- 【2017.6.5】logger.error()逗号和加号区别
- 设计模式之策略模式
- 工厂模式(更新之前的工厂模式)
- 设计模式之总纲
- 数据结构之Hashtable
- 数据结构之HashMap
- 倒影
- 如何使用万能地图下载器下载矢量建筑边界
- bzoj1735[Usaco2005 jan]Muddy Fields 泥泞的牧场
- cookie or session 状态保存信息存储
- 如何向一个Fragment传递参数---setArguments方法的介绍
- uC/OS-III之任务同步
- ASP.NET-Panel容器控件