哈希表又称为散列表,它是由数组和链表或者数组和二叉树构成,今天先来谈谈由数组和链表构成的哈希表

哈希表结构

下图是哈希表的结构:整个哈希表就是一个数组存放许多条链表(链表数组)

mysql 的哈希索引 索引哈希表_算法

哈希函数

哈希表还有一个形影不离的伙伴叫哈希函数(散列函数)F,它是用来作关键字映射的。
每一个node都含有一个唯一标识关键字id,将id映射到哈希表的哪个HashList的工作就由哈希函数来完成,即F(id)->index,index为HashList在HashTable数组里的下标。哈希函数可以自己定义映射规则。

优势

哈希表比普通的单条链表存储结构的搜索速度更快
我们都知道,链表插入效率较高而搜索效率较低,这是因为搜索一个node的时候必须从头一个接一个地搜索,不能和数组一样快速定位。而数组是插入效率低而搜索效率高,这是因为插入可能需要大量的元素移动操作。而哈希表正是融合了这两者的优点:把一条长链表分割成好几段较短的链表,放到一个数组里。查找某个node时,先用哈希函数将node的id映射到某条链表的index,再利用数组的快速索引定位到指定链表,最后向该条链表里面搜索,这样大大减少了搜索次数,提高了搜索效率。而若是想向某条链表插入node,那也是比较高效的(通过哈希函数映射得到对应index,数组索引到对应index的这条链表,再把node插入这条链表,我们都知道,链表的插入操作是很高效率的)。

由于哈希表的搜索速率很高,因此哈希表也可以被用来做缓存。

算法代码
/**
 * 
 * @ClassName: Node
 * @Description: 链表节点
 * @author: fuling
 * @date: 2020年8月21日 上午12:02:03
 */
public class Node{
	public int id; //node id,配合散列函数使用
	public String ele; //node值
	public Node next;//指向下一个node的指针
	public Node(int id, String ele) {
		this.id = id;
		this.ele = ele;
	}
	@Override
	public String toString() {
		return "{id:" + id + ", ele:" + ele + "}";
	}
}
import com.wdl.search.vo.Node;

/**
 * 
 * @ClassName: HashTable
 * @Description: 哈希表
 * @author: fuling
 * @date: 2020年8月20日 下午11:58:50
 */
public class HashTable {
	private HashList[] hashLists;//存放hashList的数组
	
	public HashTable(int size) {
		hashLists = new HashList[size];
		for(int i = 0; i < size; i++) {
			hashLists[i] = new HashList();
		}
	}
	
	/**
	 * 
	 * @Title: HashFun
	 * @Description: 散列函数(哈希函数),根据id值获取index
	 * @param: @param id 
	 * @return: int 数组的下标index
	 */
	private int HashFun(int id) {
		return id % hashLists.length;
	}
	
	public void add(Node node) {
		int index = HashFun(node.id);
		hashLists[index].add(node);
	}
	
	public Node find(int id) {
		int index = HashFun(id);
		return hashLists[index].find(id);
	}
	
	public boolean update(Node node) {
		int index = HashFun(node.id);
		return hashLists[index].update(node);
	}
	
	public boolean delete(int id) {
		int index = HashFun(id);
		return hashLists[index].delete(id);
	}

}



/**
 * 
 * @ClassName: HashList
 * @Description: HashTable存储的元素
 * @author: fuling
 * @date: 2020年8月21日 上午12:00:51
 */
class HashList{
	private Node head; //指向链表的”头指针“
	
	/**
	 * 
	 * @Title: getEnd
	 * @Description: 找到链表最后一个node
	 * @return: Node 最后一个node,若链表为空,则返回null
	 */
	private Node getEnd() {
		if(head == null)return null;
		Node temp = head;
		while(temp.next != null)temp = temp.next;
		return temp;
	}
	
	/**
	 * 
	 * @Title: add
	 * @Description: 添加新的node到链表
	 * @param: @param node 要添加的node
	 * @return: void 
	 */
	public void add(Node node) {
		Node end = getEnd();
		if(end != null) {
			end.next = node;
		}else {
			head = node;
		}
	}
	
	/**
	 * 
	 * @Title: delete
	 * @Description: 删除包含指定id的node
	 * @param: @param id 指定删除的id
	 * @return: boolean 删除是否成功
	 */
	public boolean delete(int id) {
		if(head == null)return false;
		Node temp = head;
		while(temp.next != null && temp.next.id != id)temp = temp.next;
		if(temp.next.id == id) {
			temp.next = temp.next.next;
			return true;
		}
		return false;
		
	}
	
	/**
	 * 
	 * @Title: update
	 * @Description: 修改id所指向的node
	 * @param: @param node 要修改的node信息
	 * @return: boolean 修改是否成功
	 */
	public boolean update(Node node) {
		if(head == null)return false;
		Node temp = head;
		while(temp.next != null && temp.next.id != node.id)temp = temp.next;
		if(temp.next.id == node.id) {
			node.next = temp.next.next;
			temp.next = node;
			return true;
		}
		return false;
	}
	
	/**
	 * 
	 * @Title: find
	 * @Description: 找到id所在的node
	 * @param: @param id 所查找node的id
	 * @return: Node 找到的node,若找不到则返回null
	 */
	public Node find(int id) {
		if(head == null)return null;
		Node temp = head;
		while(temp != null) {
			if(temp.id == id)return temp;
			temp = temp.next;
		}
		return null;
	}
}

源码:github地址