LFU算法

news2024/10/7 16:23:34

LFU算法

Least Frequently Used(最不频繁使用)
在这里插入图片描述
Leetcode有原题,之前手写过LRU,数据结构还是习惯于用java实现,实现是copy的评论题解。
题解注释写的很清楚

大致就是说LFUCache类维护一个存放node的map,同时维护两个双向链表,注意这个双向链表里面又包含了两个双向链表,访问的频率是first最大,last最小。其余的就是正常的双向链表的操作了(插入,删除)

import java.util.HashMap;
import java.util.Map;

class LFUCache {

    Map<Integer, Node> cache; // 存储缓存的内容,Node中除了value值外,还有key、freq、所在doublyLinkedList、所在doublyLinkedList中的postNode、所在doublyLinkedList中的preNode,具体定义在下方。

    DoublyLinkedList firstLinkedList; // firstLinkedList.post 是频次最大的双向链表

    DoublyLinkedList lastLinkedList; // lastLinkedList.pre 是频次最小的双向链表,满了之后删除 lastLinkedList.pre.tail.pre
                                     // 这个Node即为频次最小且访问最早的Node

    int size;

    int capacity;

    public LFUCache(int capacity) {

        cache = new HashMap<>(capacity);

        firstLinkedList = new DoublyLinkedList();

        lastLinkedList = new DoublyLinkedList();

        firstLinkedList.post = lastLinkedList;  // 是按照倒序排列的,最大的是first

        lastLinkedList.pre = firstLinkedList;

        this.capacity = capacity;

    }

    public int get(int key) {

        Node node = cache.get(key);

        if (node == null) {

            return -1;

        }

        // 该key访问频次+1

        freqInc(node);

        return node.value;

    }

    public void put(int key, int value) {

        if (capacity == 0) {

            return;

        }

        Node node = cache.get(key);

        // 若key存在,则更新value,访问频次+1

        if (node != null) {

            node.value = value;

            freqInc(node);

        } else {

            // 若key不存在

            if (size == capacity) {

                // 如果缓存满了,删除lastLinkedList.pre这个链表(即表示最小频次的链表)中的tail.pre这个Node(即最小频次链表中最先访问的Node),如果该链表中的元素删空了,则删掉该链表。

                cache.remove(lastLinkedList.pre.tail.pre.key);

                lastLinkedList.removeNode(lastLinkedList.pre.tail.pre);

                size--;

                if (lastLinkedList.pre.head.post == lastLinkedList.pre.tail) {

                    removeDoublyLinkedList(lastLinkedList.pre);

                }

            }

            // cache中put新Key-Node对儿,并将新node加入表示freq为1的DoublyLinkedList中,若不存在freq为1的DoublyLinkedList则新建。

            Node newNode = new Node(key, value);

            cache.put(key, newNode);

            if (lastLinkedList.pre.freq != 1) {

                DoublyLinkedList newDoublyLinedList = new DoublyLinkedList(1);

                addDoublyLinkedList(newDoublyLinedList, lastLinkedList.pre);

                newDoublyLinedList.addNode(newNode);

            } else {

                lastLinkedList.pre.addNode(newNode);

            }

            size++;

        }

    }

    /**
     * node的访问频次 + 1
     */
    void freqInc(Node node) {

        // 将node从原freq对应的双向链表里移除, 如果链表空了则删除链表。

        DoublyLinkedList linkedList = node.doublyLinkedList;

        DoublyLinkedList preLinkedList = linkedList.pre;

        linkedList.removeNode(node);

        if (linkedList.head.post == linkedList.tail) {

            removeDoublyLinkedList(linkedList);

        }

        // 将node加入新freq对应的双向链表,若该链表不存在,则先创建该链表。

        node.freq++;

        if (preLinkedList.freq != node.freq) {

            DoublyLinkedList newDoublyLinedList = new DoublyLinkedList(node.freq);

            addDoublyLinkedList(newDoublyLinedList, preLinkedList);

            newDoublyLinedList.addNode(node);

        } else {

            preLinkedList.addNode(node);

        }

    }

    /**
     * 增加代表某1频次的双向链表
     */
    void addDoublyLinkedList(DoublyLinkedList newDoublyLinedList, DoublyLinkedList preLinkedList) {

        newDoublyLinedList.post = preLinkedList.post;

        newDoublyLinedList.post.pre = newDoublyLinedList;

        newDoublyLinedList.pre = preLinkedList;

        preLinkedList.post = newDoublyLinedList;

    }

    /**
     * 删除代表某1频次的双向链表
     */
    void removeDoublyLinkedList(DoublyLinkedList doublyLinkedList) {

        doublyLinkedList.pre.post = doublyLinkedList.post;

        doublyLinkedList.post.pre = doublyLinkedList.pre;

    }

}

class Node {

    int key;

    int value;

    int freq = 1;

    Node pre; // Node所在频次的双向链表的前继Node

    Node post; // Node所在频次的双向链表的后继Node

    DoublyLinkedList doublyLinkedList; // Node所在频次的双向链表

    public Node() {
    }

    public Node(int key, int value) {

        this.key = key;

        this.value = value;

    }

}

class DoublyLinkedList {

    int freq; // 该双向链表表示的频次

    DoublyLinkedList pre; // 该双向链表的前继链表(pre.freq < this.freq)

    DoublyLinkedList post; // 该双向链表的后继链表 (post.freq > this.freq)

    Node head; // 该双向链表的头节点,新节点从头部加入,表示最近访问

    Node tail; // 该双向链表的尾节点,删除节点从尾部删除,表示最久访问

    public DoublyLinkedList() {

        head = new Node();

        tail = new Node();

        head.post = tail;

        tail.pre = head;

    }

    public DoublyLinkedList(int freq) {

        head = new Node();

        tail = new Node();

        head.post = tail;

        tail.pre = head;

        this.freq = freq;

    }

    void removeNode(Node node) {

        node.pre.post = node.post;

        node.post.pre = node.pre;

    }

    void addNode(Node node) {

        node.post = head.post;

        head.post.pre = node;

        head.post = node;

        node.pre = head;
        node.doublyLinkedList = this;

    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1411709.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jmeter之接口测试实现参数化(利用函数助手),参数值为1-9(自增的数字)

1.前言 思考&#xff1a;为什么不用postman&#xff0c;用postman的话就得导入csv文件/json文件 如果不想导入文件&#xff0c;postman是实现不了&#xff0c;因为postman每次只会运行一次 2.jmeter函数助手实现参数化 &#xff08;1&#xff09;新建“线程组”--新建“http…

MySQL-删除重复数据

在实际应用中&#xff0c;遇到一个这样的问题&#xff0c;MySQL中存储的数据为资讯类数据&#xff0c;在页面展示时会出现多个平台的新闻报导相同的内容&#xff0c;导致页面会出现重复数据。因为数据是每天定期更新&#xff0c;所以最快捷有效的方式是在更新完数据后增加一个去…

计算机网络-奈氏准则和香农定理(码间串扰 二者区别)

文章目录 失真失真的一种现象-码间串扰奈氏准则&#xff08;奈溃斯特定理&#xff09;例题 香农定理例题 奈氏和香农 失真 就是指与原来的不一样了 两种情况 前三个是正相关&#xff0c;最后一个是负相关 码元传输速率越快&#xff0c;失真程度越严重的原因可能包括以下几点…

世强硬创获凌讯微电子授权代理,助力功率半导体核心器件国产替代

近年来&#xff0c;国产功率半导体已在众多领域应用&#xff0c;特别是中高端产品&#xff0c;如超结MOSFET、IGBT、碳化硅等&#xff0c;市场逐渐从依赖进口向国内自给自足转变。 为服务更多硬科技企业实现国产化替代&#xff0c;功率半导体器件制造商广东凌讯微电子有限公司…

【Go 快速入门】安装 Go 语言 | 开发工具 Goland | 第一个 Go 语言程序

文章目录 前言安装 Go 语言编译器 Goland运行 Go 程序补充 前言 本系列教程&#xff0c;目的是帮助一个有其他编程基础的 Go 语言小白快速入门 Go 语言&#xff0c;而非启发式学习。每篇幅保证不说废话&#xff0c;尽可能精炼总结&#xff0c;为上手后续的 Go 相关项目打下基础…

渲染与创造之美:互为表里的艺术

在五彩斑斓的艺术世界中&#xff0c;渲染与创造是两股不可或缺的力量。它们之间的关系&#xff0c;恰如弓与箭&#xff0c;互为表里&#xff0c;共同塑造出无数令人叹为观止的视觉景象。创造之美是指通过创新思维和创造力&#xff0c;将想象具象化为现实&#xff0c;创造出新的…

Spyder安装与使用

Spyder是一个Python的集成开发环境&#xff08;IDE&#xff09;&#xff0c;由科学家、工程师和数据分析师设计。它提供了强大的编辑、调试和分析功能&#xff0c;以及数据探索和可视化工具&#xff0c;特别适合科学计算和数据分析。 Spyder的主要特点包括&#xff1a; 编辑器…

仿双色球抽奖大转盘

仿双色球抽奖大转盘 前言1、页面搭建2、JS逻辑编写3、Css样式编写4、编译发布5、往期回顾总结&#xff1a; 前言 需求来时奋笔疾书&#xff0c;需求变时追风逐电 &#xff01; 年低了&#xff0c;接到部门需求&#xff0c;2天时间要开发一个仿双色球抽奖大转盘&#xff0c;于是…

malloc()和free()

一、malloc() //格式&#xff1a; void *malloc(size_t str);//举例 double *ptd; ptd (double *) malloc(30*sizeof(double));//30个double类型的值请求内存空间 //并设置ptd指向该位置 malloc函数会找到合适的空闲内存块&#xff0c;这样的内存是匿名的。也就是说&#xff…

利用STM32CubeMX和Keil模拟器,3天入门FreeRTOS(4.2) —— 中断函数中使用队列

前言 &#xff08;1&#xff09;FreeRTOS是我一天过完的&#xff0c;由此回忆并且记录一下。个人认为&#xff0c;如果只是入门&#xff0c;利用STM32CubeMX是一个非常好的选择。学习完本系列课程之后&#xff0c;再去学习网上的一些其他课程也许会简单很多。 &#xff08;2&am…

Android HIDL概述与绑定模式的实现

一、前言 Android O(8.0) 版本之后&#xff0c;底层实现有了比较大的变化&#xff0c;最显著的一个方面就是 HIDL 机制的全面实施。本文对于理解系统源码中 Gnss、Usb、Camera 等模块的工作原理有极大帮助。 二、HIDL 设计目的 在 Android O(8.0) 之前系统的升级牵扯多方协作…

安全用电管理平台方案介绍——Acrelcloud-6000

安全用电管理平台是一个针对电力系统安全管理的平台&#xff0c;旨在提供对电力设备和用电行为进行监控、分析和管理的解决方案。该平台结合了物联网技术、数据分析和远程监控等技术手段&#xff0c;能够实时监测、分析和预警电力系统的安全状况&#xff0c;以便及时采取措施防…

再谈Android View绘制流程

一&#xff0c;先思考何时开始绘制 笔者在这里提醒读者&#xff0c;Android的View是UI的高级抽象&#xff0c;我们平时使用的XML文件也好&#xff0c;本质是设计模式中的一种策略模式&#xff0c;其View可以理解为一种底层UI显示的Request。各种VIew的排布&#xff0c;来自于开…

KernelGPT: LLM for Kernel Fuzzing

KernelGPT: Enhanced Kernel Fuzzing via Large Language Models 1.Introduction2.Background2.1.Kernel and Device Drivers2.2.Kernel Fuzzing2.2.1.Syzkaller规约2.2.2.规约生成 3.Approach3.1.Driver Detection3.2.Specification Generation3.2.1.Command Value3.2.2.Argum…

Vue2学习之第六、七章——vue-router与ElementUI组件库

路由 理解&#xff1a; 一个路由&#xff08;route&#xff09;就是一组映射关系&#xff08;key - value&#xff09;&#xff0c;多个路由需要路由器&#xff08;router&#xff09;进行管理。前端路由&#xff1a;key是路径&#xff0c;value是组件。 1.基本使用 安装vue-…

springboot快速写接口

1. 建proj形式 name会变成文件夹的名字&#xff0c;相当于你的项目名称 基础包 2. 基础依赖 3. 配置数据库 这里要打开mysql&#xff0c;并且创建数据库 方法&#xff1a; 安装好数据库&#xff0c;改好账号密码用navicat来建表和账号配置properties.yml文件即可 4.用res…

读AI3.0笔记07_游戏与推理

1. 始于游戏&#xff0c;不止于游戏 1.1. 开发超人类的游戏程序并不是人工智能的最终目的 1.2. AlphaGo所有的版本除了下围棋&#xff0c;其他什么也不会 1.2.1. 其最通用的版本AlphaGo Zero也一样 1.3. 这些游戏程序中没有一个能够将其在一款游戏中学到的知识迁移到其他游…

引领未来:云原生在产品、架构与商业模式中的创新与应用

文章目录 一、云原生产品创新二、云原生架构设计三、云原生商业模式变革《云原生落地 产品、架构与商业模式》适读人群编辑推荐内容简介目录 随着云计算技术的不断发展&#xff0c;云原生已经成为企业数字化转型的重要方向。接下来将从产品、架构和商业模式三个方面&#xff0c…

融合创新:传统企业数字化转型的业务、战略、操作和文化变革

引言 随着科技的不断演进&#xff0c;传统企业正站在数字化转型的前沿&#xff0c;这是一场前所未有的全面变革之旅。数字化已经超越了单纯的技术升级&#xff0c;成为企业保持竞争力、开创未来的必然选择。本文将引领您探讨&#xff0c;迈向数字化未来的传统企业全面数字化转…

回归预测 | Matlab基于SSA-SVR麻雀算法优化支持向量机的数据多输入单输出回归预测

回归预测 | Matlab基于SSA-SVR麻雀算法优化支持向量机的数据多输入单输出回归预测 目录 回归预测 | Matlab基于SSA-SVR麻雀算法优化支持向量机的数据多输入单输出回归预测预测效果基本描述程序设计参考资料 预测效果 基本描述 1.Matlab基于SSA-SVR麻雀算法优化支持向量机的数据…