自己一次失败的编码= =


public class LFUCache {
    private final Node first;
    private final Node last;
    private final HashRep cache;
    private final HashMap<Integer,Node> count;
    LFUCache(int capacity){
        cache = new HashRep(capacity);
        count = new HashMap<>();
        first = new Node(0,0);
        first.count=-1;
        last = new Node(0,0);
        last.count=-1;
        first.next = last;
        last.pre = first;
    }

    /**
     * 首先,get并返回值
     * 先从cache中get,如果为null,return -1
     * 先看该节点在不在count中
     *      如果在,删除掉该count
     * count++
     * 我们get一下这个++后的count值
     *      如果有,move链表,设置count
     */
    public int get(int key) {
        if (cache.capacity<1){
            return -1;
        }
        Node thisNode = cache.get(key);
        if (thisNode==null){
            return -1;
        }
        Node node = count.get(thisNode.count);

        if (node.key==thisNode.key){
            if (thisNode.next.count==thisNode.count){
                count.put(thisNode.count,thisNode.next);
            }else {
                count.remove(thisNode.count);
            }
        }
        thisNode.count++;
        Node nextNode = count.get(thisNode.count);
        if (nextNode!=null){
            thisNode.move(nextNode);
        }else if (node.key!=thisNode.key){
            thisNode.move(node);
        }
        count.put(thisNode.count,thisNode);
        return thisNode.val;
    }

    /**
     * 1.工具类比较智能,new Node,直接put
     * 2.返回0,只是修改了值,不做处理
     * 3.返回1,添加成功,需要把他 放在 count[0] 前面,并把count[0]改成新节点
     * 4.返回-1.很难受,我们要先删除最后一个节点
     *      cache 中删掉 remove方法
     *      节点.del()删除链表中的引用关系
     *      如果在count中,直接删除,因为它本来就在链表尾,不可能存在与他相同count
     *      试图放在count[0] 前面,如果count[0]为空就放在last前面,更新count[0]
     */
    public void put(int key, int value) {
        if (cache.capacity<1){
            return;
        }
        Node thisNode = new Node(key, value);
        int sign = cache.put(thisNode);
        if (sign == 0){
            return;
        }
        if (sign==-1){
            if (count.get(last.pre.count)==last.pre){
                count.remove(last.pre.count);
            }
            cache.remove(last.pre.key);
            last.pre.del();
        }
        Node nextNode = count.get(0);
        if (nextNode==null){
            nextNode=last;
        }
        thisNode.move(nextNode);
        count.put(0,thisNode);
    }
}

/**
 * 这个类定义容器类,只维护节点的值,以及访问次数
 * 不能维护任何链表顺序
 * 实现LFU仍然需要一个映射来维护访问次数对应链表的位置
 * 我们也可使用该工具类来保存映射  : 待定
 */
class HashRep {
    final int capacity;
    private int size;
    private final int hashKey;
    private final Node[] rep;

    HashRep(int capacity) {
        this.capacity = capacity;
        size = 0;
        int n = capacity - 1;
        int p = 1;
        while (p < 17) {
            n |= n >>> p;
            p <<= 1;
        }
        hashKey = n;
        rep = new Node[hashKey + 1];
    }

    /**
     * hash取index,循环取值,没取到返回-1,取到返回值
     * 不对count做操作
     * 单纯一个集合类
     */
     Node get(int key) {
        int index = key & hashKey;
        Node aimNode = rep[index];
        while (aimNode != null && aimNode.key != key) {
            aimNode = aimNode.get;
        }
        return aimNode;
    }

    /**
     * 返回0 存在key更改数值
     * 返回1 添加
     * 返回-1 添加,但容量溢出
     */
     int put(Node node) {
        int key = node.key;
        int index = key & hashKey;
        //三种情况: 1.index位置上为null  2. 往后找,找到了key   3.没有找到key相等的,取最后一个
        Node aimNode = rep[index];
        if (aimNode==null){
            rep[index] = node;
        }else {
            if (aimNode.key==key){
                aimNode.val = node.val;
                return 0;
            }
            while(aimNode.get!=null){
                //找到了key,更改值
                if (aimNode.key==key){
                    aimNode.val = node.val;
                    return 0;
                }
                aimNode=aimNode.get;
            }
            aimNode.get = node;
        }
        size++;
        return size>capacity?-1:1;
    }

    /**
     * 如果在桶上面,桶下面没节点 直接删桶 size--
     * 如果在桶上面,桶下面有节点,把桶下面那个移上来 size--
     * 如果在桶下的节点之间,上面的get->这个的get    size--
     * 如果在桶末尾,上面那个节点指向这个节点的指针干掉 size--
     */
    protected void remove(int key){
        //一切为性能,不能遍历两边链表
        int index = key & hashKey;
        Node aimNode = rep[index];
        if (aimNode==null){
            return;
        }
        if (aimNode.key==key){
            if (aimNode.get==null){
                rep[index]=null;
                size--;
            }else{
                rep[index] = aimNode.get;
                size--;
            }
            return;
        }
        //注意,单向链表使用get来对比
        while(aimNode.get!=null&&aimNode.get.key!=key){
            aimNode = aimNode.get;
        }
        //aimNode.get 有两种情况 一种为null,一种为目标节点
        if (aimNode.get!=null){
            if (aimNode.get.get!=null){
                aimNode.get = aimNode.get.get;
            }else {
                aimNode.get=null;
            }
        }
    }
}
class Node {
    Node pre;
    Node next;
    int key;
    int val;
    Node get;
    int count=0;
    Node(int key,int val){
        this.key =key;
        this.val = val;
    }
    public void move(Node nextNode){
        if(this.next!=null){
            this.next.pre = this.pre;
            this.pre.next = this.next;
        }
        this.pre=nextNode.pre;
        this.next=nextNode;
        this.pre.next = this;
        nextNode.pre = this;
    }
    public void del(){
        this.pre.next = next;
        this.next.pre = pre;
    }
}


一些感想:

根据不同的需求选择什么样的缓存算法,以及创新新的缓存算法是以后学习的一个方向

但目前还是先把眼前的问题解决,在写较长的逻辑时总会有很多逻辑错误,发生错误总会加一些条件判断来避免同类错误

但是错误多了之后会使代码很乱,没有条理,更可怕的是加条件判断的时候没有经过思考,导致条件与逻辑冲突,加的判断还有新的错误等等...以后写东西一定将逻辑梳理完整再写,争取写出来一次就过..

猜你喜欢

转载自blog.csdn.net/start_lie/article/details/84640059