1、HashTable的概述
从基本层面讲,数据结构有数组与链表两种。数组具有查找快,但插入耗时的特点;链表具有插入快,但查找费时的特点。有没有可能在查找与插入之间取得平衡呢?哈希表的诞生回答了这个问题。
构建一个好的哈希表,主要得考量哈希函数与解决冲突这两面。不管是哈希函数,还是解决冲突,往深里挖都是可以走得很远很远。
2、实现哈希表的思路
直接上思维导图,思维上建立了,写个哈希表就不那么费力了。
public class HashTable<K, V> { private int size;//元素个数 private static int initialCapacity=16;//HashTable的初始容量 private Entry<K,V> table[];//实际存储数据的数组对象 private static float loadFactor=0.75f;//加载因子 private int threshold;//阀值,能存的最大的数max=initialCapacity*loadFactor //构造指定容量和加载因子的构造器 public HashTable(int initialCapacity,float loadFactor){ if(initialCapacity<0) throw new IllegalArgumentException("Illegal Capacity:"+initialCapacity); if(loadFactor<=0) throw new IllegalArgumentException("Illegal loadFactor:"+loadFactor); this.loadFactor=loadFactor; threshold=(int)(initialCapacity*loadFactor); table=new Entry[threshold]; } //使用默认参数的构造器 public HashTable(){ this(initialCapacity,loadFactor); } //放入元素 public boolean put(K key,V value){ //取得在数组中的索引值 int hash=key.hashCode(); Entry<K,V> temp=new Entry(key,value,hash); if(addEntry(temp,table)){ size++; return true; } return false; } //添加元素到指定索引处 private boolean addEntry(HashTable<K, V>.Entry<K, V> temp, HashTable<K, V>.Entry<K, V>[] table) { //1.取得索引值 int index=indexFor(temp.hash,table.length); //2.根据索引找到该位置的元素 Entry<K,V> entry=table[index]; //2.1非空,则遍历并进行比较 if(entry!=null){ while(entry!=null){ if((temp.key==entry.key||temp.key.equals(entry.key))&&temp.hash==entry.hash &&(temp.value==entry.value||temp.value.equals(entry.value))) return false; else if(temp.key!=entry.key&&temp.value!=entry.value){ if(entry.next==null) break; entry=entry.next; } } //2.2链接在该索引位置处最后一个元素上 addEntryLast(temp,entry); } //3.若空则直接放在该位置 setFirstEntry(temp,index,table); //4.插入成功,返回true return true; } //链接元素到指定索引处最后一个元素上 private void addEntryLast(HashTable<K, V>.Entry<K, V> temp, HashTable<K, V>.Entry<K, V> entry) { if(size>threshold) reSize(table.length*4); entry.next=temp; } //初始化索引处的元素值 private void setFirstEntry(HashTable<K, V>.Entry<K, V> temp, int index, HashTable<K, V>.Entry<K, V>[] table) { if(size>threshold) reSize(table.length*4); table[index]=temp; //注意指定其next元素,防止多次使用该哈希表时造成冲突 temp.next=null; } //扩容容量 private void reSize(int newSize) { Entry<K,V> newTable[]=new Entry[newSize]; threshold=(int) (loadFactor*newSize); for(int i=0;i<table.length;i++){ Entry<K,V> entry=table[i]; //数组中,实际上每个元素都是一个链表,所以要遍历添加 while(entry!=entry){ addEntry(entry,newTable); entry=entry.next; } } table=newTable; } //计算索引值 private int indexFor(int hash, int tableLength) { //通过逻辑与运算,得到一个比tableLength小的值 return hash&(tableLength-1); } //取得与key对应的value值 protected V get(K k){ Entry<K,V> entry; int hash=k.hashCode(); int index=indexFor(hash,table.length); entry=table[index]; if(entry==null) return null; while(entry!=null){ if(entry.key==k||entry.key.equals(k)) return entry.value; entry=entry.next; } return null; } //内部类,包装需要存在哈希表中的元素 class Entry<K,V>{ Entry<K,V> next; K key; V value; int hash; Entry(K k,V v,int hash){ this.key=k; this.value=v; this.hash=hash; } } }
注:(1)本代码中采用的hash算法是:第一步采用JDK给出的hashcode()方法,计算加入对象的一个哈希值,其中hashcode()在Object类中定义为:public native int hashcode();说明这是一个本地方法,它的具体实现跟本地机器相关。第二步是通过hashcode&(table.lenth-1),返回一个比length小的值,即为索引值。
相关推荐
在.NET框架中,`Dictionary, TValue>`和`Hashtable`都是常见的哈希表实现,用于存储...通过阅读“dotnet C# 字典 Dictionary 和 Hashtable 的性能对比.md”文档,你可以进一步了解它们在实际应用中的表现和测试结果。
List、ArrayList、Vector及map、HashTable是Java中常用的容器类,它们都继承自Collection接口,并提供了不同的实现方式和特点。在实际开发中,选择合适的容器类是非常重要的。 Collection接口是Java中最基本的集合...
在Java编程语言中,`Hashtable`是`Dictionary`类的一个具体实现,它是早期Java版本中的一个线程安全的键值对存储容器。`Hashtable`遵循了一些基本的映射概念,如存储键值对、根据键查找值以及添加、删除键值对等。...
`HashMap` 和 `HashTable` 都是 Java 集合框架中非常重要的数据结构,它们都实现了 `Map` 接口,用于存储键值对。尽管它们在功能上有很多相似之处,但在实现细节和性能特性上存在显著差异。 #### 二、主要区别 1. ...
标签中的`hashtable`可能指的是`java.util.Hashtable`类,这是Java早期提供的一种线程安全的哈希表实现。虽然`HashMap`在性能上通常优于`Hashtable`,但`Hashtable`在多线程环境中更安全,因为它的所有方法都是同步...
Java性能优化是提升Java应用程序效率的关键技术,涵盖了代码优化、内存管理、并发处理等多个方面。在Java开发过程中,了解并掌握这些优化技巧可以显著提高应用的响应速度和资源利用率。 首先,我们关注的是代码层面...
在Java编程语言中,`Hashtable`是`Dictionary`类的一个具体实现,它提供了一个基于键值对的数据结构,允许程序员存储和检索对象。`Hashtable`类是线程安全的,因此可以在多线程环境中直接使用,而无需额外的同步控制...
在Java编程语言中,`HashMap`和`HashTable`都是实现键值对存储的数据结构,但它们之间存在一些显著的区别,这些区别主要体现在线程安全性、性能、null值处理以及一些方法特性上。以下是对这两个类的详细分析: 1. ...
Java标准库中的哈希表实现主要依赖于`java.util.Hashtable`类。在创建`Hashtable`对象时,用户可以通过构造函数指定初始容量`C`以及装载因子`F`。一旦对象被创建,装载因子便无法改变。装载因子决定了哈希表的负载...
性能对比 - **HashMap**通常比**HashTable**具有更好的性能。原因包括: - `HashMap`的非线程安全设计减少了同步开销。 - `HashMap`在哈希计算和扩容策略上的优化使其在大多数情况下都能提供更高的性能。 - ...
历史背景及实现原理 - **Hashtable**:该类继承自`Dictionary`类,并且实现了`Map`接口。它最早出现在Java 1.0版本中,可以视为早期实现键值对存储的一种方式。 - **HashMap**:相比之下,`HashMap`是在Java 1.2...
本研究针对这一问题进行了深入探讨,并着重分析了在并行程序中,这两种数据结构的性能对比以及如何重构相关代码,以提高并行程序的运行效率和稳定性。 首先,要了解Hashtable与ConcurrentHashMap的基本区别。...
LinkedList是List接口的另一个实现,它基于双向链表实现,对于在列表中间插入和删除元素,LinkedList的性能优于ArrayList,因为不需要移动元素。但在随机访问元素时,LinkedList的性能较差,因为需要从头或尾部开始...
### Java中HashMap, LinkedHashMap, TreeMap,HashTable的区别 在Java编程语言中,`Map`接口是集合框架中的一个重要组成部分,用于存储键值对。本文将详细分析四种常用的`Map`实现类:`HashMap`, `LinkedHashMap`, ...
Java提供了`java.util.Hashtable`和`java.util.HashMap`两个类来实现哈希表的功能。这两个类非常相似,通常提供相同的公共接口,但在某些方面有所不同。 - **Hashtable** 是线程安全的,这意味着可以在多线程环境中...
#### 四、性能比较 - **Hashtable**:由于其同步特性,`Hashtable` 的性能通常会低于 `HashMap`。在单线程环境下,这种差距尤为明显。 - **HashMap**:在不考虑同步的情况下,`HashMap` 提供了更好的性能表现,...
`HashTable`是古老的键值对存储结构,线程安全但效率较低,已被`HashMap`所取代,`HashMap`是非线程安全但性能更高的选择。 集合框架的使用极大地提高了代码的可读性和复用性,同时通过接口的定义,可以灵活地更换...
### Java系统性能优化手册知识点详解 #### 一、前言 在Java系统开发过程中,为了提升系统的整体性能,开发者需要掌握一系列的优化技巧。本文档旨在通过总结《河南省人口与计划生育利益导向管理信息系统》的实际应用...
3. **`HashTable.java`**:这个文件可能包含了整个哈希表的实现,包括哈希函数、链表结构以及相关操作如插入、删除和查找等。哈希表通常包含一个数组,每个元素是一个链表,数组的大小通常是质数,以减少哈希冲突。 ...
实际应用中,我们可以根据具体需求进一步优化,例如使用更现代的`HashMap`替代`Hashtable`(因为`Hashtable`是同步的,可能在多线程场景下性能不佳),或者考虑使用`ConcurrentHashMap`以实现线程安全且高效的并发...