IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> JAVA实现LRU算法 -> 正文阅读

[数据结构与算法]JAVA实现LRU算法

LRU算法

LRU是一种页面置换算法,least recently used(最近最少使用)算法,意思是在发生缺页现象时,需要置换页面的时候,将最近最少使用的页面删除,添加需要的页面进来

LRU举例

下面我们来看看具体的LRU算法是如何工作的,我们假设内存页面有2块,每次访问内存时总会一次性读取一页的数据进来,当页面数量不够时,发生LRU置换:
有以下页面走向:1 2 3 2 4

轮次12345
页面111232
页面22324

每次请求页面的时候,都去寻找最近最不常使用的页面丢弃,将新页面加载进来

LRU题目

运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:

  • LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
    int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
  • void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
    进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?

思路分析

想要实现get和put的操作,想要用Key拿到Value嘛,很容易想到用HashMap来实现,这样子好像get的O(1)操作就完成了,返回一个value,其实不然,因为拿到值之后还需要调整顺序,以便后续让不经常使用的页面删除出去,于是想到用双向链表来存储节点,插入和删除节点都非常简单,但是如何定位这个节点的位置呢?比如我想删除key为2的节点,如果我要在链表中从头遍历一次,那么定位的时间复杂度就是O(n),能实现O(1)的复杂度就是HashMap,于是想到用HashMap来存储Key对应的节点,让key对应一个节点,节点中存储value,找到节点,对节点的前后进行调整,最后让节点挂到尾部表示最近挂载上去的,让删除节点从链表头开始。
get和put,分析如下几种情况:

  • 通过key get到了节点
    • 调整替换的节点到链表尾
  • 通过key 没get到节点
    • 返回-1
  • put插入的时候已有
    • 更新key对应的node中的value值,调整节点到链表尾部
  • put插入的时候没有
    • 容量不够
      • 将新节点挂载到链表尾部,头结点删除
    • 容量充足
      • 新节点直接挂在到链表尾部

代码实现

import java.util.HashMap;

public class LRUCache {
    class Node {
        int key;
        int val;
        Node next;
        Node pre;

        public Node(int key, int val, Node next, Node pre) {
            this.key = key;
            this.val = val;
            this.next = next;
            this.pre = pre;
        }
    }
    HashMap<Integer, Node> nodeMap;
    Node head;
    Node tail;
    int capacity;
    int size;

    LRUCache(int capacity) {
        nodeMap = new HashMap<>();
        head = tail = null;
        this.size = 0;
        this.capacity = capacity;
    }

    int get(int key) {
        if (nodeMap.get(key) == null) {
            // 获取不到Node
            return -1;
        } else {
            // 获取到Node 调整链表顺序
            Node node = nodeMap.get(key);
            if (node != tail) {
                moveToTail(node);
            }
            return node.val;
        }
    }

    private void moveToTail(Node node) {
        if(node != head){
            node.pre.next = node.next;
        }else{
            head = head.next;
        }
        node.next.pre = node.pre;
        node.next = null;
        node.pre = tail;
        tail.next = node;
        tail = node;
    }

    void put(int key, int value) {
        if (nodeMap.get(key) != null) {
            // 能找到当前key,只需要替换,调整链表
            Node node = nodeMap.get(key);
            node.val = value;
            // 获取到Node 调整链表顺序
            if (node != tail) {
                moveToTail(node);
            }
        }else {
            // 找不到当前key,说明需要插入
            // 容量足够
            if (size < capacity) {
                if (size == 0) {
                    Node node = new Node(key, value, null, null);
                    head = tail = node;
                    nodeMap.put(key, node);
                } else {
                    Node node = new Node(key, value, null, tail);
                    addToTail(node);
                }
                size++;
            } else {
                // 容量不足,需要把链表尾替换为要插入的node,删除链表头部
                Node node = new Node(key, value, null, tail);
                addToTail(node);
                removeHead();
            }
        }
    }

    private void removeHead() {
        nodeMap.remove(head.key);
        head = head.next;
        head.pre = null;

    }

    private void addToTail(Node node) {
        node.next = null;
        tail.next = node;
        tail = node;
        nodeMap.put(node.key, node);
    }
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-21 15:43:11  更:2021-08-21 15:44:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:58:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码