JAVA 实现 - 哈希表
哈希表
v1
package com.datastructure.hashtable;
public class HashTable {
//节点类
static class Entry {
int hash;
Object key;
Object value;
Entry next;
public Entry(int hash, Object key, Object value) {
this.hash = hash;
this.key = key;
this.value = value;
}
}
Entry[] table = new Entry[16]; //数组存放链表第一个元素
int size = 0;
//根据 hash 获取 value
Object get(int hash, Object key, Object value) {
int inx = hash & (table.length - 1);
if (table[inx] == null) {
return null;
}
//遍历链表
Entry p = table[inx];
while (p != null) {
if (p.key.equals(key)) {
return p.value;
}
p = p.next;
}
return null;
}
/*
1. 向hash中存入key value, 如果key 重复,则更新为value
hash 决定存在数组中的哪个位置:hash % 数组长度 得到的值即为落入数组的位置
2. 求模运算没有位运算效率高,可以替换为位运算
- 前提: 数组长度是2的n次方
- hash % 数组 等价于 hash & *(数组长度 - 1)
*/
void put(int hash, Object key, Object value) {
int idx = hash & (table.length - 1);
Entry p = table[idx];
if (p == null) { //1. 在数组中找到空位直接放入
Entry entry = new Entry(hash, key, value);
table[idx] = entry;
size++;
} else {
while (true) { //2. 数组中没有找到空位,遍历链表,如果key 相等更新,如果没找到相等的key 就新增
if (p.key.equals(key)) {
//更新
p.value = value;
return;
}
if (p.next == null) {
break;
}
p = p.next;
}
p.next = new Entry(hash, key, value);
size++;
}
}
//移除元素
Object remove(int hash, Object key) {
return null;
}
public static void main(String[] args) {
String str1 = "abc";
String str2 = "bca";
System.out.println("str1 => String.hashCode:" + str1.hashCode());
System.out.println("str2 => String.hashCode:" + str2.hashCode());
int hash = 0;
for (int i = 0; i < str1.length(); i++) {
char c = str1.charAt(i);
System.out.println((int) c);
hash = (hash << 5) - hash + c; //loop1: 0+a, loop2: (0+a)*10+b, lopp3: ((0+a)*10+b) * 10 + c <=> a*100 + b*10 +c
}
System.out.println(hash);
}
}
测试类:
package com.datastructure.hashtable;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class HashTableTest {
@Test
public void test1() {
HashTable table = new HashTable();
table.put(1, "zhangsan", "23"); // 1 % 16 = 1
table.put(17, "lisi", "28"); // 17 % 16 = 1
table.put(2, "wangwu", "29"); // 2 % 16 = 2
// assertEquals()
assertEquals(3, table.size);
assertEquals("23", table.table[1].value);
assertEquals("28", table.table[1].next.value);
assertEquals("29", table.table[2].value);
//更新
table.put(1, "zhangsan", "25");
table.put(17, "lisi", "27");
assertEquals("25", table.table[1].value);
assertEquals("27", table.table[1].next.value);
}
}
求莫与按位与等价:
什么是哈希算法
hash 算法是一种将任意长度的数据通过一个算法,变成固定长度数据的过程,这个固定长度的数据就是hash值。hash算法可以将任意大小的数据压缩到固定大小的值。常见的hash算法有MD5、SHA1、SHA256、SHA512、CRC32等。其中,MD5和SHA系列算法是最常用的hash算法。这些算法在计算hash值时,都考虑了原始数据的每一个字节,一旦改动原始数据的任何一个字节,所得到的hash值都会有明显的不同。因此,hash算法被广泛应用于数据完整性校验和加密等方面。
hash 算法是将任意对象,分配一个编号的过程,其中编号是一个有限范围内的数据(如int范围内)
哈希算法 String.hashCode
public static void main(String[] args) {
String str1 = "abc";
String str2 = "bca";
int hash = 0;
for (int i = 0; i < str2.length(); i++) {
char c = str1.charAt(i);
System.out.println((int)c);
hash += c;
}
System.out.println(hash);
}
以上hash值是将每个字符的值相加得到一个hashcode,但问题是"abc" 与 "cba" 的hashcode 就会一致。如何解决?
可以给前两位字符都乘以一个权重,如下
a * 100 + b * 10 + c
b * 100 + c * 10 + a
实现如下:
public static void main(String[] args) {
String str1 = "abc";
String str2 = "bca";
System.out.println("str1 => String.hashCode:" + str1.hashCode());
System.out.println("str2 => String.hashCode:" + str2.hashCode());
int hash = 0;
for (int i = 0; i < str1.length(); i++) {
char c = str1.charAt(i);
System.out.println((int) c);
hash = hash * 10 + c; //loop1: 0+a, loop2: (0+a)*10+b, lopp3: ((0+a)*10+b) * 10 + c <=> a*100 + b*10 +c
}
System.out.println(hash);
}
还可以进一步优化, 将 hash * 10 改为 乘以一个质数 如31 ,但是为什么是质数那?
public static void main(String[] args) {
String str1 = "abc";
String str2 = "bca";
System.out.println("str1 => String.hashCode:" + str1.hashCode());
System.out.println("str2 => String.hashCode:" + str2.hashCode());
int hash = 0;
for (int i = 0; i < str1.length(); i++) {
char c = str1.charAt(i);
System.out.println((int) c);
hash = hash * 31 + c; //loop1: 0+a, loop2: (0+a)*10+b, lopp3: ((0+a)*10+b) * 10 + c <=> a*100 + b*10 +c
}
System.out.println(hash);
}
输出:
str1 => String.hashCode:96354
str2 => String.hashCode:97344
97
98
99
96354
此时输出的hashcode 就是 String 类的实现,还可以进一步优化: 将乘法运算转换为 左移位运算,因为位运算的效率比乘法高,32为 2 的 5次方,因此可以左移5位
public static void main(String[] args) {
String str1 = "abc";
String str2 = "bca";
System.out.println("str1 => String.hashCode:" + str1.hashCode());
System.out.println("str2 => String.hashCode:" + str2.hashCode());
int hash = 0;
for (int i = 0; i < str1.length(); i++) {
char c = str1.charAt(i);
System.out.println((int) c);
hash = (hash << 5) - hash + c; //loop1: 0+a, loop2: (0+a)*10+b, lopp3: ((0+a)*10+b) * 10 + c <=> a*100 + b*10 +c
}
System.out.println(hash);
}
本文来自博客园,作者:chuangzhou,转载请注明原文链接:https://www.cnblogs.com/czzz/p/18328212