Java数据结构——哈希表

什么是哈希表?
哈希表是一种根据关键码去寻找值的数据映射结构,该结构通过把关键码映射的位置去寻找存放值的地方。

哈希表充分体现了算法设计领域的经典思想:空间换时间。哈希表是时间和空间之间的平衡。其中的哈希函数是最重要的,“键”通过哈希函数得到的“索引”分布越均匀越好。但是哈希表会失去顺序性。

哈希函数的设计
对于整型

  1. 小范围正整数直接使用
  2. 小范围负整数进行偏移 -100~100 ----> 0~200
  3. 大整数:模一个素数

对于浮点型
转成整型处理

对于字符串
也是转成整型处理

int hash=0;
for(int i=0;i<s.length();i++
{
hash=(hash*B+s.charAt(i))%M;
}

对于复合类型
依然转成整型处理

hash(code)=((((c%M)*B+o)%M*B+d)%M*B+e)%M; 

但是,转成整型处理,并不是唯一的方法

哈希函数设计原则

  1. 一致性:如果a==b,则hash(a)==hash(b),反之不一定成立
  2. 高效性:计算高效简便
  3. 均匀性:哈希值分布均匀

哈希冲突的处理
链地址法(O(1))

在jdk7之前是数组+链表
jdk8开始,当链表长度超过一定值后会转换成红黑树

开放地址法
不会形成链,当遇到哈希冲突时,直接往冲突的位置的后面的第一个空的位置里放。当这个哈希表足 够大且元素存的足够多的时候,会导致查找下一个空位的效率变得很低。

实现一个自己的哈希表

import java.util.TreeMap;

public class HashTable<K, V> {
private TreeMap<K, V>[] hashtable;
private int M;
private static final int upperTol = 10;
private static final int lowerTol = 2;
private static final int initCapacity = 7;
private final int[] capacity = { 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, 196613,
393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189,
805306457, 1610612741 };
private int capacityIndex = 0;
private int size;

public HashTable() {
this.M = capacity[capacityIndex];
size = 0;
hashtable = new TreeMap[M];
for (int i = 0; i < M; i++) {
hashtable[i] = new TreeMap<>();
}
}

private int hash(K Key) {
return (Key.hashCode() & 0x7fffffff) % M;
}

public int getSize() {
return size;
}

public void add(K key, V value) {
TreeMap<K, V> map = hashtable[hash(key)];
if (map.containsKey(key)) {
map.put(key, value);
} else {
map.put(key, value);
size++;
if (size >= upperTol * M && capacityIndex + 1 < capacity.length) {
capacityIndex++;
resize(capacity[capacityIndex]);
}
}
}

public V remove(K key) {
TreeMap<K, V> map = hashtable[hash(key)];
V ret = null;
if (map.containsKey(key)) {
ret = map.remove(key);
size--;
if (size < lowerTol * M && capacityIndex - 1 >= 0) {
capacityIndex--;
resize(capacity[capacityIndex]);
}
}
return ret;
}

public void set(K key, V value) {
TreeMap<K, V> map = hashtable[hash(key)];
if (!map.containsKey(key)) {
throw new IllegalArgumentException("don‘t find");
} else {
map.put(key, value);
}
}

public boolean contain(K key) {
return hashtable[hash(key)].containsKey(key);
}

public V get(K key) {
TreeMap<K, V> map = hashtable[hash(key)];
return map.get(key);
}

private void resize(int newM) {
TreeMap<K, V>[] newTable = new TreeMap[newM];
for (int i = 0; i < newM; i++) {
newTable[i] = new TreeMap<>();
}
int oldM = M;
this.M = newM;
for (int i = 0; i < oldM; i++) {
TreeMap<K, V> map = hashtable[i];
for (K key : map.keySet()) {
newTable[hash(key)].put(key, map.get(key));
}
}
this.hashtable = newTable;
}
}

原文地址:https://www.cnblogs.com/ericz2j/p/10800519.html

时间: 2024-11-06 22:14:54

Java数据结构——哈希表的相关文章

java数据结构——哈希表(HashTable)

哈希表提供了快速的插入操作和查找操作,每一个元素是一个key-value对,其基于数组来实现. 一.Java中HashMap与Hashtable的区别: HashMap可以接受null键值和值,而Hashtable则不能. Hashtable是线程安全的,通过synchronized实现线程同步.而HashMap是非线程安全的,但是速度比Hashtable快. 这两个类有许多不同的地方,下面列出了一部分: a) Hashtable 是 JDK 1 遗留下来的类,而 HashMap 是后来增加的.

java中哈希表及其应用详解

哈希表也称为散列表,是用来存储群体对象的集合类结构. 什么是哈希表 数组和向量都可以存储对象,但对象的存储位置是随机的,也就是说对象本身与其存储位置之间没有必然的联系.当要查找一个对象时,只能以某种顺序(如顺序查找或二分查找)与各个元素进行比较,当数组或向量中的元素数量很多时,查找的效率会明显的降低. 一种有效的存储方式,是不与其他元素进行比较,一次存取便能得到所需要的记录.这就需要在对象的存储位置和对象的关键属性(设为 k)之间建立一个特定的对应关系(设为 f),使每个对象与一个唯一的存储位置

数据结构哈希表(转)

数据结构哈希表 参考代码如下: [plain] view plain copy /* 名称:哈希表 语言:数据结构C语言版 编译环境:VC++ 6.0 日期: 2014-3-26 */ #include <stdio.h> #include <malloc.h> #include <windows.h> #define NULLKEY 0   // 0为无记录标志 #define N 10        // 数据元素个数 typedef int KeyType;// 

数据结构---哈希表(散列表)

我们在Java容器中谈到:有哈希表(也称为散列表)支持的HashMap.LinkedHashSet等都具有非常高的查询效率.这其中就是Hash起的作用.顺序查找的时间复杂度为O(N) ,二分查找和查找树的时间复杂度为O(logN),而 哈希表的时间复杂度为O(1) .不过这只是理想状态,实际并不那么完美. 1.哈希表的概念和思想 哈希表是唯一的专用于集合的数据结构.可以以常量的平均时间实现插入.删除和查找. 哈希表的思想是:用一个与集合规模差不多大的数组来存储这个集合,将数据元素的关键字映射到数

Code Review:C#与JAVA的哈希表内部机制的一些区别

看C#与JAVA源码时发现C#与JAVA哈希表的实现略有不同,特此分享一下. 我觉得看哈希表的机制可以从"碰撞"这里划线分为两部分来分析. 1,发生碰撞前 在发生碰撞前决定get与put的速度唯一因素是通过哈希函数计算键值位置的速度.而占用空间大小取决于需要的桶的数量(取决于极限装载值(load factor)(假设已知需要放入哈希表中元素的数量)),和桶的大小. C#的默认装载系数=0.72 // Based on perf work, .72 is the optimal load

Java数据结构之线性表(2)

从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的几张,我们将会分别讲解这几种数据结构,主要也是通过Java代码的方式来讲解相应的数据结构. 今天要讲解的是:Java线性结构 Java数据结构之线性结构 说到线性结构的话,我们可以根据其实现方式分为两类: 1)顺序结构的线性表 2)链式结构的线性表 3)栈和队列的线性表 对于1)和2)的讲解,请参考

Java数据结构之线性表

从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的几张,我们将会分别讲解这几种数据结构,主要也是通过Java代码的方式来讲解相应的数据结构. 今天要讲解的是:Java线性结构 Java数据结构之线性结构 说到线性结构的话,我们可以根据其实现方式分为三类: 1)顺序结构的线性表 2)链式结构的线性表 3)栈和队列的线性表 1.顺序结构的线性表    

数据结构 - 哈希表

哈希表 1. 哈希表的引入 1.1 哈希表的简单概述   哈希表一个通过哈希函数来计算数据存储位置的数据结构,通常支持如下操作 (高效的操作):python中的字典是通过哈希表实现的 insert(key, value):插入键值对(key,value) get(key):如果存在键为key的键值对则返回其value,否则返回空值 delete(key):删除键为key的键值对  1.2.直接寻址表 当关键字的key 的 全域U(关键字可能出现的范围)比较小时,直接寻址是一种简单而有效的方法 存

数据结构 哈希表 c++

什么是哈希表 理想的查找是不经过任何的比较,一次存取就能得到想要查询的记录:要达到这样的目的就需要在记录的储存位置和它的关键字之间建立一个确定的关系f , 让每个关键字和结构中的一个唯一的地址相对应.在查找的时候,只需要对应关系f找到给定值K的像f(K),若结构中存在关键字和K相等,则必定在f(K)的储存位置上,由此不需要任何比较就能得到查询: 就好像数组一样,我们要找第一个数,调用a[0]就能得到第一个数, 当我们通过关键字来找的时候,通过一定的规则,把关键字和储存位置建立一个映射,就能通过数