哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
数组的特点是:寻址容易,插入和删除困难;
而链表的特点是:寻址困难,插入和删除容易。
综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构,这就是哈希表,哈希表有多种不同的实现方法,我接下来解释的是最常用的一种方法——拉链法,我们可以理解为“链表的数组”,如图:
左边很明显是个数组,数组的每个成员包括一个指针,指向一个链表的头,当然这个链表可能为空,也可能元素很多。我们根据元素的一些特征把元素分配到不同的链表中去,也是根据这些特征,找到正确的链表,再从链表中找出这个元素。
哈希构造:
1.直接寻址法 : f(key) = key 或者 f(key) = a ´ key + b 此法仅适合于:地址集合的大小 = = 关键字集合的大小,其中a和b为常数。
2.除留余数法: 设定哈希函数为:H(key) = key%n ( n≤m ),其中, m为表长(容量),n 为不大于 m 的素数,或是不含 20 以下的质因子
哈希冲突解决:
1.链地址法:(数组+单向链表)
2.探测法:pos(n)=f(n)+p(n)
线性探测 :p(n)=1
p(n)=2,,,,,,
随机探测:p(n)=random()
代码:
/**
*
*/
package com.tulun.jihe;
/**
* @author lzq
*
*/
public class HashMap {
/**
* 节点类
* @author 李正全
*
*/
class Entry{
/**
* 键
*/
int key;
/**
* 值
*/
String val;
/**
* 下一个节点
*/
Entry next;
/**
* 构造方法
* @param key 键
* @param val 值
*/
public Entry(int key, String val) {
this.key = key;
this.val = val;
}
}
/**
* 当前的Hash表长度
*/
int size;
/**
* 数组
*/
Entry[] array;
/**
* 构造函数,初始化
*/
public HashMap() {
this.size = 0;
array = new Entry[10];
}
/**
* put方法
* @param key 键
* @param val 值
*/
public void put(int key,String val) {
//临时Key
int tempKey = key%10;
Entry node = new Entry(key, val);
if(array[tempKey] == null) {
array[tempKey] = node;
} else {
insertTail( array[tempKey], node);
}
size++;
}
/**
* 尾插法
* @param head 头结点
* @param newNode 新节点
*/
private void insertTail(Entry head,Entry newNode){
if(head==null){
return;
}
Entry temp = head;
while(temp.next!=null){
temp = temp.next;
}
temp.next = newNode;
}
/**
* get方法
* @param key 键
* @return
*/
public String get(int key){
int tempKey = key%10;
Entry tempNode = array[tempKey];
while(tempNode!=null){
if(tempNode.key == key){
return tempNode.val;
}
tempNode = tempNode.next;
}
return null;
}
public void remove(int key){
int tempKey = key%10;
Entry tempNode = array[tempKey];
Entry tempNode2 = array[tempKey].next;
if(tempNode2== null){
array[tempKey] = null;
} else {
while(tempNode2 != null){
if(tempNode2.key == key){
break;
}
tempNode = tempNode.next;
tempNode2 = tempNode2.next;
}
tempNode.next = tempNode.next.next;
tempNode2 = null;
}
size--;
}
public void test(){
HashMap a = new HashMap();
a.put(50, "图论");
a.put(20, "中国");
a.put(52, "李正全");
a.put(64, "算法");
a.put(96, "数据");
a.put(57, "计算机");
a.put(47, "电脑");
a.put(79, "笔记本");
a.put(9, "Java");
a.put(19, "前端");
System.out.print(a.get(50)+" ");
System.out.print(a.get(20)+" ");
System.out.print(a.get(52)+" ");
System.out.print(a.get(64)+" ");
System.out.print(a.get(96)+" ");
System.out.print(a.get(57)+" ");
System.out.print(a.get(47)+" ");
System.out.print(a.get(79)+" ");
System.out.print(a.get(9)+" ");
System.out.println(a.get(19));
a.remove(64);
System.out.println("================");
System.out.println("删除后:");
System.out.println("================");
System.out.print(a.get(50)+" ");
System.out.print(a.get(20)+" ");
System.out.print(a.get(52)+" ");
System.out.print(a.get(64)+" ");
System.out.print(a.get(96)+" ");
System.out.print(a.get(57)+" ");
System.out.print(a.get(47)+" ");
System.out.print(a.get(79)+" ");
System.out.print(a.get(9)+" ");
System.out.println(a.get(19));
}
}
运行结果:
图论 中国 李正全 算法 数据 计算机 电脑 笔记本 Java 前端
================
删除后:
================
图论 中国 李正全 null 数据 计算机 电脑 笔记本 Java 前端