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}
原文地址:https://www.cnblogs.com/cyy12/p/11861670.html