LRU hashMap(拉链) + 双向链表 java实现
- //基于 hash (拉链法) + 双向链表,LRUcache
- //若改为开放寻址,线性探测法能更好使用cpuCache
- public class LRU {
- private class Node {
- Node p; //访问序 priv
- Node n; //访问序 next
- Node hn; //hash 拉链 next
- Object key;
- Object val;
- public Node() {
- }
- public Node(Object key, Object val) {
- this.key = key;
- this.val = val;
- }
- @Override
- public String toString() {
- return "Node{" +
- "key=" + key +
- ", val=" + val +
- ", hn=" + (hn == null ? "n" : hn.key) +
- ", p=" + (p == null ? "n" : p.key) +
- ", n=" + (n == null ? "n" : n.key) +
- '}';
- }
- }
- Node head;
- Node tail;
- Node[] tables;
- int capa = 4;
- int tabSize; //2的整数倍
- int count;
- int countLimit = 8;
- float loadFactor = 0.75f; //装载因子
- public LRU(int countLimit) {
- this.countLimit = countLimit;
- tabSize = capa;
- tables = new Node[tabSize];
- count = 0;
- }
- public LRU() {
- tabSize = capa;
- tables = new Node[tabSize];
- count = 0;
- }
- public int getTabSize() {
- return tabSize;
- }
- public int getCountLimit() {
- return countLimit;
- }
- public int getCount() {
- return count;
- }
- public void put(Object key, Object val) {
- int indexh = hash(key);
- Node newNode = null;
- resize();
- //插入hash表
- if (tables[indexh] == null) {
- newNode = new Node(key, val);
- tables[indexh] = newNode;
- count++;
- } else {
- Node sentry = new Node();
- sentry.hn = tables[indexh];
- while (sentry.hn != null) { //hash相同,在同一个桶里,需要额外判断equals
- if (sentry.hn.key.equals(key)) {
- sentry.hn.val = val; //相同的key,替换val
- newNode = sentry.hn;
- break;
- } else
- sentry = sentry.hn; //key不相同继续找拉链的下一个
- }
- if (newNode == null) { //没有存在有相同key的节点,创建一个新的插入
- newNode = new Node(key, val);
- sentry.hn = newNode; //拉链尾接上新节点
- count++;
- }
- }
- //修改访问序链表
- if (head == null)
- head = newNode;
- if (tail == null) {
- tail = newNode;
- } else {
- if (newNode.p != null) //已存在的中间节点,从链表中取出
- newNode.p.n = newNode.n;
- if (newNode.n != null)
- newNode.n.p = newNode.p;
- newNode.n = null;
- newNode.p = tail; //放到链表尾部
- tail.n = newNode;
- tail = tail.n;
- }
- if (count > countLimit) {
- System.out.println("count > countLimit , del :" + del(head.key));
- }
- }
- public Node get(Object key) {
- int indexh = hash(key);
- //从hash表中查找
- Node chainHead = tables[indexh];
- while (chainHead != null) { //hash相同,在同一个桶里,需要额外判断equals
- if (!chainHead.key.equals(key)) //key不相同继续找拉链的下一个
- chainHead = chainHead.hn;
- break; //找到了
- }
- //处理访问序链表,将访问的节点放到最后
- if (chainHead != null && tail != chainHead) {
- if (chainHead.p != null)
- chainHead.p.n = chainHead.n;
- if (chainHead.n != null)
- chainHead.n.p = chainHead.p;
- if (head == chainHead) {
- head = head.n;
- }
- tail.n = chainHead;
- chainHead.p = tail;
- chainHead.n = null;
- tail = tail.n;
- }
- return chainHead;
- }
- public static class Pair {
- public Object key;
- public Object val;
- @Override
- public String toString() {
- return "{" +
- "key=" + key +
- ", val=" + val +
- '}';
- }
- }
- public List<Pair> getAll() {
- List<Pair> list = new ArrayList<>();
- for (Node cur = head; cur != null; cur = cur.n) {
- Pair p = new Pair();
- p.key = cur.key;
- p.val = cur.val;
- list.add(p);
- }
- return list;
- }
- public Node del(Object key) {
- int indexh = hash(key);
- Node chainHead = tables[indexh];
- Node delNode = null;
- Node delHnodeP = null;
- //从hash表中移除
- while (chainHead != null) { //hash相同,在同一个桶里,需要额外判断equals
- if (!chainHead.key.equals(key)) //key不相同继续找拉链的下一个
- chainHead = chainHead.hn;
- else {
- delNode = chainHead; //找到目标节点
- if (delHnodeP != null) { //中间节点
- delHnodeP.hn = delNode.hn;
- } else { //tables 头节点
- tables[indexh] = delNode.hn;
- }
- break;
- }
- delHnodeP = chainHead;
- }
- //从访问序链表中移除
- if (delNode != null) {
- if (delNode.p != null) //从链表中取出
- delNode.p.n = delNode.n;
- if (delNode.n != null) {
- delNode.n.p = delNode.p;
- }
- if (tail == delNode) //链表头尾处理
- tail = delNode.p;
- if (head == delNode)
- head = delNode.n;
- count--;
- }
- return delNode;
- }
- public int hash(Object key) {
- int hashc = key.hashCode();
- hashc = hashc ^ (hashc >> 16);
- int indexh = hashc & (tabSize - 1);
- return indexh;
- }
- //扩容
- public void resize() {
- if (loadFactor * capa > count)
- return;
- System.out.println("resize " + capa + " to " + (capa << 1));
- List<Pair> list = getAll();
- capa = capa << 1;
- tabSize = capa;
- Node[] newTables = new Node[tabSize];
- head = null;
- tail = null;
- count = 0;
- tables = newTables;
- for (Pair p : list) {
- put(p.key, p.val);
- }
- }
- public static void main(String[] args) {
- //测试
- //add
- LRU lru = new LRU();
- lru.put(1, 1);
- lru.put(2, 2);
- lru.put(5, 5);
- lru.put(7, 7);
- System.out.println(lru.getCount());
- for (Pair p : lru.getAll()) {
- System.out.println(p);
- }
- System.out.println();
- //get
- System.out.println(lru.get(2));
- System.out.println(lru.getCount());
- for (Pair p : lru.getAll()) {
- System.out.println(p);
- }
- System.out.println();
- //del
- System.out.println(lru.del(5));
- System.out.println(lru.getCount());
- for (Pair p : lru.getAll()) {
- System.out.println(p);
- }
- System.out.println();
- //same key
- lru.put(7, 72);
- for (Pair p : lru.getAll()) {
- System.out.println(p);
- }
- System.out.println();
- //hash collision
- lru.put(7 + lru.getTabSize(), 73);
- System.out.println(lru.getCount());
- for (Pair p : lru.getAll()) {
- System.out.println(p);
- }
- System.out.println();
- //get bucket chain head
- lru.get(7);
- for (Pair p : lru.getAll()) {
- System.out.println(p);
- }
- System.out.println();
- //del
- lru.del(23);
- System.out.println(lru.getCount());
- for (Pair p : lru.getAll()) {
- System.out.println(p);
- }
- System.out.println();
- lru.put(8, 8);
- lru.put(9, 9);
- lru.put(10, 10);
- lru.put(11, 11);
- lru.put(12, 12);
- lru.put(13, 13); //del 1
- lru.put(14, 14); //del 2
- System.out.println(lru.getCount());
- for (Pair p : lru.getAll()) { //7~14
- System.out.println(p);
- }
- System.out.println();
- }
- }
输出
- resize 4 to 8
- 4
- {key=1, val=1}
- {key=2, val=2}
- {key=5, val=5}
- {key=7, val=7}
- Node{key=2, val=2, hn=n, p=7, n=n}
- 4
- {key=1, val=1}
- {key=5, val=5}
- {key=7, val=7}
- {key=2, val=2}
- Node{key=5, val=5, hn=n, p=1, n=7}
- 3
- {key=1, val=1}
- {key=7, val=7}
- {key=2, val=2}
- {key=1, val=1}
- {key=7, val=7}
- {key=2, val=2}
- {key=7, val=72}
- 5
- {key=1, val=1}
- {key=7, val=7}
- {key=2, val=2}
- {key=7, val=72}
- {key=15, val=73}
- {key=1, val=1}
- {key=7, val=7}
- {key=2, val=2}
- {key=15, val=73}
- {key=7, val=72}
- 5
- {key=1, val=1}
- {key=7, val=7}
- {key=2, val=2}
- {key=15, val=73}
- {key=7, val=72}
- resize 8 to 16
- count > countLimit , del :Node{key=1, val=1, hn=9, p=n, n=2}
- count > countLimit , del :Node{key=2, val=2, hn=n, p=n, n=15}
- count > countLimit , del :Node{key=15, val=73, hn=n, p=n, n=7}
- 8
- {key=7, val=72}
- {key=8, val=8}
- {key=9, val=9}
- {key=10, val=10}
- {key=11, val=11}
- {key=12, val=12}
- {key=13, val=13}
- {key=14, val=14}
LRU hashMap(拉链) + 双向链表 java实现的更多相关文章
- How HashMap works in java 2
https://www.javacodegeeks.com/2014/03/how-hashmap-works-in-java.html Most common interview questio ...
- 昨天面试被问到的 缓存淘汰算法FIFO、LRU、LFU及Java实现
缓存淘汰算法 在高并发.高性能的质量要求不断提高时,我们首先会想到的就是利用缓存予以应对. 第一次请求时把计算好的结果存放在缓存中,下次遇到同样的请求时,把之前保存在缓存中的数据直接拿来使用. 但是, ...
- LRU的理解与Java实现
简介 LRU(Least Recently Used)直译为"最近最少使用".其实很多老外发明的词直译过来对于我们来说并不是特别好理解,甚至有些词并不在国人的思维模式之内,比如快速 ...
- 线性链表的双向链表——java实现
.线性表链式存储结构:将采用一组地址的任意的存储单元存放线性表中的数据元素. 链表又可分为: 单链表:每个节点只保留一个引用,该引用指向当前节点的下一个节点,没有引用指向头结点,尾节点的next引用为 ...
- HashMap如何工作 - Java
大多数人应该会同意HashMap是现在面试最喜欢问的主题之一.我和同事常常进行讨论,并很有帮助.现在,我继续和大家讨论. 我假设你对HashMap的内部工作原理感兴趣,并且你已经知道了基本的HashM ...
- 双向链表--Java实现
/*双向链表特点: *1.每个节点含有两个引用,previos和next,支持向前或向后的遍历(除头节点) *2.缺点插入或删除的时候涉及到引用修改的比较多 *注意:下面的双向链表其实也实现了双端链表 ...
- SpringMvc中Hashmap操作遇到 java.util.ConcurrentModificationException: null
代码按照网上修改为类似,还不能解决问题 for (Iterator<String> it = target.keySet().iterator(); it.hasNext(); ) { i ...
- 双向链表-java完全解析
原文:https://blog.csdn.net/nzfxx/article/details/51728516 "双向链表"-数据结构算法-之通俗易懂,完全解析 1.概念的引入 相 ...
- How HashMap works in Java
https://www.javainterviewpoint.com/hashmap-works-internally-java/ How a HashMap Works internally has ...
随机推荐
- Sqoop 抽数报错: java.io.FileNotFoundException: File does not exist
Sqoop 抽数报错: java.io.FileNotFoundException: File does not exist 一.错误详情 2019-10-17 20:04:49,080 INFO [ ...
- jquery.i18n 网站呈现各国语言
在做网站的时候可能会遇到不同语言切换的问题,实现的方法有很多种,本篇文章按照 js 加载的方法的来实现. 应用到的 js 文件: jquery.i18n.properties.js jquery.js ...
- weed3-2.1.开始纯java使用
Weed3 一个微型ORM框架(只有0.1Mb哦) 源码:https://github.com/noear/weed3 源码:https://gitee.com/noear/weed3 纯java使用 ...
- Android Studio出现Failed to open zip file问题的解决方法
直接在网上找到gradle-3.3-all.zip下载下来,不要解压缩,放在类似下面的目录中 C:\Users\Administrator\.gradle\wrapper\dists\gradle-3 ...
- java 网站源码 在线编辑模版 代码编辑器 兼容手机平板PC freemaker 静态引擎
前台: 支持四套模版, 可以在后台切换 系统介绍: 1.网站后台采用主流的 SSM 框架 jsp JSTL,网站后台采用freemaker静态化模版引擎生成html 2.因为是生成的html,所以 ...
- LATEX Mathematical Symbols
原文地址:https://www.caam.rice.edu/~heinken/latex/symbols.pdf
- java读取文本文件内容2
版权声明:本文为xing_star原创文章,转载请注明出处! 本文同步自http://javaexception.com/archives/183 很久之前写了一篇Java读取文本文件内容,链接地址是 ...
- Windows和linux下的端口转发
利用VPN,实现无公网IP或内网服务器的服务 @@@code netsh interface portproxy add v4tov4 listenport=8887 connectaddress=1 ...
- Dockerfile优化
总结: 1.编写.dockerignore文件 2.容器只运行单个应用 3.将多个RUN指令合并为一个 4.基础镜像的标签不要用latest 5.每个RUN指令后删除多余文件 6.选择合适的基础镜像( ...
- python-将一个列表切分成多个小列表
list是python中较为常见的数据类型,它是一个可迭代对象,迭代是什么?简单的可以理解成:一个可以被for循环遍历的对象 今天拿到一个类似这样的list list_info = ['name zh ...