算法进阶面试题06——实现LFU缓存算法、计算带括号的公式、介绍和实现跳表结构

本文介绍了LFU缓存算法的实现,包括如何在O(1)时间复杂度内完成set和get操作。接着讨论了计算带有括号的公式的方法,针对不同情况给出了处理思路。最后讲解了跳表的原理和作用,分析了其在Redis中的应用,并阐述了插入和查询的优化策略。
摘要由CSDN通过智能技术生成

第一题

上一题实现了LRU缓存算法,LFU也是一个著名的缓存算法

自行了解之后实现LFU中的set 和 get

要求:两个方法的时间复杂度都为O(1)

 

LFU根据get、set操作次数决定的优先级。

 

 

同样次数,最不经常访问的先出去。

实现思路:建立一个次数链,每个次数再链接上一个双向链。(两个双链表)

 

 

Put和Get的时候,先检查是否存在

如果没有,put就存在1的链表下,get就返回null。

如果有,找到属于哪个头,然后分离出来,查看头部的下一个是否次数+1的关系,有就插入,没有就建出来。每次挂都是挂在小链表的头部。

size满了,就删最左边底下的head。

看代码...(代码是把最近操作的放在头部)

  

复制代码

public class Code_03_LFU {
    //小链表的节点
    public static class Node {
        public Integer key;
        public Integer value;
        public Integer times;
        public Node up;
        public Node down;

        public Node(int key, int value, int times) {
            this.key = key;
            this.value = value;
            this.times = times;
        }
    }

    public static class LFUCache {

        //把次数相同的节点连在一起的链表
        public static class NodeList {
            //本链的头尾
            public Node head;
            public Node tail;
            //前一个和后一个
            public NodeList last;
            public NodeList next;

            public NodeList(Node node) {
                head = node;
                tail = node;
            }

            public void addNodeFromHead(Node newHead) {
                newHead.down = head;
                head.up = newHead;
                head = newHead;
            }

            public boolean isEmpty() {
                return head == null;
            }

            //其中的任何节点都可能删,因为次数增加也要调整节点位置
            //把节点从本环境中分离
            public void deleteNode(Node node) {
                if (head == tail) {
                    head = null;
                    tail = null;
                } else {
                    if (node == head) {//头
                        head = node.down;
                        head.up = null;
                    } else if (node == tail) {//尾
                        tail = node.up;
                        tail.down = null;
                    } else {//其中
                        node.up.down = node.down;
                        node.down.up = node.up;
                    }
                }
                node.up = null;
                node.down = null;
            }
        }

        private int capacity;//容量
        private int size;//当前大小
        //通过key找Node
        private HashMap<Integer, Node> records;
        //找到Node的当前所在链表
        private HashMap<Node, NodeList> heads;
        private NodeList headList;

        public LFUCache(int capacity) {
            this.capacity = capacity;
            this.size = 0;
            this.records = new HashMap<>();
            this.heads = new HashMap<>();
            headList = null;
        }

        public void set(int key, int value) {
            if (records.containsKey(key)) {//存在
                Node node = records.get(key);
                node.value = value;
                node.times++;
                NodeList curNodeList = heads.get(node);
                move(node, curNodeList);//帮node找新家
            } else {
                if (size == capacity) {//腾出空间
                    Node node = headList.tail;
                    headList.deleteNode(node);
                    modifyHeadList(headList);//检查是否要调整(有可能删光了)
                    records.remove(node.key);
                    heads.remove(node);
                    size--;
                }
                Node node = new Node(key, value, 1);
                if (headList == null) {//第一次加
                    headList = new NodeList(node);
                } else {
                    //检查是否存在专属的次数链表
                    if (headList.head.times.equals(node.times)) {
                        headList.addNodeFromHead(node);
                    } else {//没有就建
                        NodeList newList = new NodeList(node);
                        newList.next = headList;
                        headList.last = newList;
                        headList = newList;
                    }
                }
                //记录信息
                records.put(key, node);
                heads.put(node, headList);
                size++;
            }
        }

        private void move(Node node, NodeList oldNodeList) {
            oldNodeList.deleteNode(node);//先从老家搬出
     
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值