LRU算法原理及实现(java)

本文介绍了LRU(Least Recently Used)缓存淘汰算法的基本原理,即最近频繁访问的数据在以后也更可能被访问。文章详细阐述了LRU算法的实现思路,包括使用双向链表和HashMap来构建缓存结构,以及get、put、delete和change操作的具体实现。通过Java代码展示了LRUCache类的完整实现,包括添加、删除、更新和获取缓存项的操作,以及如何在超出容量时淘汰最不常用的数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.原理
LRU(Least Recently Used)是一种常见的 页面置换算法 ,在计算中,所有的文件操作都要放在内存中进行,然而计算机内存大小是固定的,所以我们不可能把所有的文件都加载到内存,因此我们需要制定一种策略对加入到内存中的文件进项选择。
 
LRU的设计原理就是,当数据在最近一段时间经常被访问,那么它在以后也会经常被访问。这就意味着,如果经常访问的数据,我们需要然其能够快速命中,而不常访问的数据,我们在容量超出限制内,要将其淘汰。
 
2.实现思路
大致思路:
 
构建双向链表节点ListNode,应包含key,value,prev,next这几个基本属性
 
对于Cache对象来说,我们需要规定缓存的容量,所以在初始化时,设置容量大小,然后实例化双向链表的head,tail,并让head.next->tail tail.prev->head,这样我们的双向链表构建完成
 
对于get操作,我们首先查阅hashmap,如果存在的话,直接将Node从当前位置移除,然后插入到链表的首部,在链表中实现删除直接让node的前驱节点指向后继节点,很方便.如果不存在,那么直接返回Null
 
对于put操作,比较麻烦。
 
3.java代码实现
package com.facishare.bi.stat.util.LRU ;
import java.util.HashMap ;
 
public class LRUCache{
  private int capacity ;
  private HashMap<String , Node> cache ;
  private Node head ;
  private Node tail ;
 
  public LRUCache ( int capacity){
    this . capacity = capacity ;
    cache = new HashMap<String , Node> (capacity) ;
    head = new Node( "head" , "head" ) ;
    tail = new Node( "tail" , "tail" ) ;
    head . next = tail ;
    tail . pre = head ;
  }
 
  /**
   * put方法
   * 1。判断这个node在cache中是否存在,如果不存在,即插入新node
   * 2。插入新node之前要判断一下,cache的容量是否已经超出最大容量,如果超出,必须先移除链表尾部的node,之后再插入新node
   * 3。如果此node已经存在,需要将此node从原来的未知移除,再插入链表头部
   * @param key
   * @param value
   */
 
  public void put (String key , Object value){
    Node node = cache .get(key) ;
    if (node== null ){
      if ( cache .size() > capacity ){
        removeOldestNode() ;
      }
      Node newNode = new Node(key , value) ;
      addNodeToHead(newNode) ;
      cache .put(key , newNode) ;
    }
    if (node!= null ){
      removeThisNode(node) ;
      addNodeToHead(node) ;
    }
  }
 
  /**
   * delete方法
   * @param key
   */
  public void delete (String key){
    Node node = cache .get(key) ;
    if (node!= null ){
      removeThisNode(node) ;
      cache .remove(key) ;
    }
    if (node== null ){
      System. out .println( "此节点不存在!" ) ;
    }
  }
 
  /**
   * change方法
   * 1。通过key获取node信息,如果不为空,更新node信息,然后将此node从当前未知移除,插入链表头部
   * 2。如果为空,调用put方法将此node插入链表头部
   * @param newNode
   */
  public void change (Node newNode){
    Node oldNode= cache .get(newNode. key ) ;
    if (oldNode != null ){
      oldNode. value = newNode. value ;
      removeThisNode(oldNode) ;
      addNodeToHead(oldNode) ;
    }
    if (oldNode == null ){
      put(newNode. key , newNode. value ) ;
    }
  }
 
  /**
   * get方法
   * 1。通过key获取node,如果node不为空,将此node从当前位置移除,插入链表头部,返回node的value
   * 2。如果为空,返回null
   * @param key
   * @return
   */
  public Object get (String key){
    Node node = cache .get(key) ;
    if (node!= null ){
      removeThisNode(node) ;
      addNodeToHead(node) ;
      return node. value ;
    }
    return null;
  }
 
  //移除当前node
  private void removeThisNode (Node node) {
    node. pre . next = node. next ;
    node. next . pre = node. pre ;
  }
 
  //将node插入链表头部
  private void addNodeToHead (Node newNode) {
    newNode. next = head . next ;
    head . next . pre = newNode ;
    head . next = newNode ;
    newNode. pre = head ;
 
  }
 
  //移除链表尾部的node
  private void removeOldestNode () {
    String oldKey = tail . pre . key ;
    tail . pre . pre . next = tail ;
    tail . pre = tail . pre . pre ;
    cache .remove(oldKey) ;
  }
 
  @Override
  public String toString () {
    StringBuilder sb = new StringBuilder() ;
    Node node = head ;
    while (node != null ) {
      sb.append(String. format ( "%s:%s " , node. key , node. value )) ;
      node = node. next ;
    }
    return sb.toString() ;
  }
 
 
  public static void main (String[] args) {
    LRUCache lru = new LRUCache( 5 ) ;
    lru.put( "1" , "a" ) ;
    lru.put( "2" , "b" ) ;
    lru.put( "3" , "c" ) ;
    lru.put( "4" , "d" ) ;
    lru.put( "5" , "e" ) ;
    System. out .println( "原始链表为:" +lru.toString()) ;
 
    lru.get( "4" ) ;
    System. out .println( "获取key为4的元素之后的链表:" +lru.toString()) ;
 
    lru.put( "6" , "f" ) ;
    System. out .println( "新添加一个key为6之后的链表:" +lru.toString()) ;
 
    lru.delete( "3" ) ;
    System. out .println( "移除key=3的之后的链表:" +lru.toString()) ;
  }
 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值