- 哈希表的底层是数组实现的.可以方便插入和查找操作.
- 在往数据里添加值时有俩种计算位置的方式
-
- (1): 开放地址法,当发生冲突的时候。找到数组中空的位置插入进去。使用开放地址法会把别人的位置挤掉.
-
- (2) : 链式存储法 当发现hashcode的值相同时,以链表的方式存入进去.
- 具体上代码:
- 先是开放地址法:
info 类
public class Info {
private String key;
private String name;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
Info(String key, String name) {
super();
this.key = key;
this.name = name;
}
Info() {
super();
// TODO Auto-generated constructor stub
}
}
hash 表:
public class HashTable {
private Info[] arr;
public HashTable() {
arr = new Info[100];
}
public Info[] getArr() {
return arr;
}
public void setArr(Info[] arr) {
this.arr = arr;
}
/**
* 插入数据
*
* @param info
*/
public void insert(Info info) {
// arr[info.getKey()] = info;//使用 int 作为 key
String key = info.getKey();// 使用string 作为KEY
int hashVal = hashcode(key);
// 如果只删除name 那name 就是空
while (arr[hashVal] != null && arr[hashVal].getName() != null) {
// 进行递加
++hashVal;
// 循环
hashVal %= hashVal;
}
arr[hashVal] = info;
}
/**
* 查找数据
*
* @param key
* @return
*/
public Info find(String key) {
int hashVal = hashcode(key);
while(arr[hashVal] !=null){
if(arr[hashVal].getKey().equals(key)){
return arr[hashVal];
}
++hashVal;
hashVal %= arr.length;
}
return null;
}
/**
* 删除
* @param key
* @return
*/
public Info delete(String key){
int hashVal = hashcode(key);
while(arr[hashVal] !=null){
if(arr[hashVal].getKey().equals(key)){
Info temp = arr[hashVal];
arr[hashVal] = null;
return temp;
}
++hashVal;
hashVal %= arr.length;
}
return null;
}
public int hashcode(String key) {
// 这样有重复的
// int hashVal = 0;
// for(int i = key.length()-1; i>=0; i--){
// int letter =key.charAt(i)-96; //空格是96 a是97
// hashVal += letter;
// }
// 2)使用幂的连乘
// int hashVal = 0;
// int pow27 = 1;
// for(int i = key.length()-1; i>=0; i--){
// int letter =key.charAt(i)-96; //空格是96 a是97
//
// hashVal += letter*pow27; //26 个字母还有空格
// pow27 *= pow27;
// }
// 压缩:并且使用bigint
BigInteger hashVal = new BigInteger("0");
BigInteger pow27 = new BigInteger("1");
for (int i = key.length() - 1; i >= 0; i--) {
int letter = key.charAt(i) - 96; // 空格是96 a是97
BigInteger letterB = new BigInteger(String.valueOf(letter));
hashVal = hashVal.add(letterB.multiply(pow27));
pow27 = pow27.multiply(new BigInteger(String.valueOf(27)));
// hashVal += letter*pow27; //26 个字母还有空格
// pow27 *= pow27;
// }
// 对数组的长度取余
}
return hashVal.mod(new BigInteger(String.valueOf(arr.length))).intValue();
}
}
接下来是测试代码:
public static void main(String[] args) {
HashTable h = new HashTable();
h.insert(new Info("abc","aa"));
h.insert(new Info("bbb","bb"));
System.out.println(h.find("abc").getName());
System.out.println(h.find("bbb").getName());
h.delete("bbb");
System.out.println(h.find("bbb"));
}
输出:
aa
bb
null
abc 和bbb 计算出来的hash 值是一样的.但是还可以存放.其实这里是通过占用别人的位置实现的这个功能.有很大的弊端
接下来我们看 使用链式存储法,和HashMap 的原理非常相似
本来想自己画一张图的.但是太懒了.不想画了
理论和上图一样. 开始就是一个链表式的数组. 如果计算出他们的hash 值相同就链式存储下去. 如果查找和删除 计算的hash值相同 就使用 key.equals 来查找.
很多面试者都会被问到hashMap 的原理和底层实现.相信自己动手写过哈希表的人一定会说出来 底层就是hi哈希表实现的.或者是链式的数组..如果只是回答数组的话…那这个人80%没有学习过数据结构….
好了.废话不多说上代码:
public class Info {
private String key;
private String name;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
Info(String key, String name) {
super();
this.key = key;
this.name = name;
}
Info() {
super();
// TODO Auto-generated constructor stub
}
}
节点类:
/**
*
* @功能:节点
* @版本:1.0
* @修改:
*/
public class Node {
public Info info;
public Node next;
public Node(Info info){
this.info= info;
}
}
链表:
public class LinkList {
//头结点
public Node first;
//插入一个节点在头结点后面插入
public void insertFirst(Info info){
Node node = new Node(info);
node.next= first;
first = node;
}
//在头结点后面进行删除。
public Node deleteFirst(){
Node temp =first;
first = temp.next;
return temp;
}
public Node find(String key){
Node current =first;
while(!key.equals(current.info.getKey())){
if(current.next == null){
return null;
}
current = current.next;
}
return current;
}
/**
* 删除一个节点
* @param key
* @return
*/
public Node delete(String key){
Node current = first;
Node previous = first;
while(!key.equals(current.info.getKey())){
if(current.next ==null){
return null;
}
previous = current;
current = current.next;
}
if(current == first){
//如果是第一个 那么他下一个为第一个
first = first.next;
}else{
//不是第一个。
previous.next = current.next;
}
return current;
}
}
hashtable 的实现:
public class HashTable {
private LinkList[] arr;
public HashTable(int maxSize) {
arr = new LinkList[maxSize];
}
public HashTable() {
arr = new LinkList[100];
}
/**
* 插入数据
*
* @param info
*/
public void insert(Info info) {
// arr[info.getKey()] = info;//使用 int 作为 key
String key = info.getKey();// 使用string 作为KEY
int hashVal = hashcode(key);
if(arr[hashVal] == null){
arr[hashVal] = new LinkList();
}
arr[hashVal].insertFirst(info);
}
/**
* 查找数据
*
* @param key
* @return
*/
public Info find(String key) {
int hashVal = hashcode(key);
return arr[hashVal].find(key).info;
}
/**
* 删除
* @param key
* @return
*/
public Info delete(String key){
int hashVal = hashcode(key);
return arr[hashVal].delete(key).info;
}
public int hashcode(String key) {
// 这样有重复的
// int hashVal = 0;
// for(int i = key.length()-1; i>=0; i--){
// int letter =key.charAt(i)-96; //空格是96 a是97
// hashVal += letter;
// }
// 2)使用幂的连乘
// int hashVal = 0;
// int pow27 = 1;
// for(int i = key.length()-1; i>=0; i--){
// int letter =key.charAt(i)-96; //空格是96 a是97
//
// hashVal += letter*pow27; //26 个字母还有空格
// pow27 *= pow27;
// }
// 压缩:并且使用bigint
BigInteger hashVal = new BigInteger("0");
BigInteger pow27 = new BigInteger("1");
for (int i = key.length() - 1; i >= 0; i--) {
int letter = key.charAt(i) - 96; // 空格是96 a是97
BigInteger letterB = new BigInteger(String.valueOf(letter));
hashVal = hashVal.add(letterB.multiply(pow27));
pow27 = pow27.multiply(new BigInteger(String.valueOf(27)));
// hashVal += letter*pow27; //26 个字母还有空格
// pow27 *= pow27;
// }
// 对数组的长度取余
}
return hashVal.mod(new BigInteger(String.valueOf(arr.length))).intValue();
}
}
测试类:
public static void main(String[] args) {
HashTable h = new HashTable();
h.insert(new Info("a","aa"));
h.insert(new Info("ct","bb"));
h.insert(new Info("b","zqp"));
System.out.println(h.find("a").getName());
System.out.println(h.find("ct").getName());
System.out.println(h.find("b").getName());
System.out.println(h.hashcode("a"));
System.out.println(h.hashcode("ct"));
System.out.println(h.delete("a"));
}
aa
bb
zqp
1
1
com.ch17.Info@83dae1
可以看到 a 和 ct 的hash 值是一样的.但是ct并没有占到别人的位置,而是链式存储到了 下标为 1 的那个链表上去了.
以前对hashMap 的原理只是知道他是怎么实现的.今天学习完哈希表数据结构之后.对他的理解更深.