zoukankan      html  css  js  c++  java
  • 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}
  • 相关阅读:
    网络摄像头监控中什么情况下需要使用流媒体转发服务器?
    流媒体播放器播放h264编码视频与h265编码视频哪个更清晰?
    RTMP推流视频流媒体服务如何实现网络传输?
    web视频直播服务器更改端口号后录像功能失效问题解决
    互联网视频直播/点播流媒体服务器使用http和rtmp做点播时有什么区别?
    视频互联网直播/点播服务器中关于内容分发CDN的相关问题汇总
    网页直播系统推流端和拉流端都有哪些环节?
    自建视频流媒体服务器需要满足哪些条件?
    线上课堂教育行业选择互动直播时有哪些直播方案?
    互联网直播点播平台在进行iframe直播分享时如何禁止本地视频自动播放?
  • 原文地址:https://www.cnblogs.com/cyy12/p/11861670.html
Copyright © 2011-2022 走看看