LRU算法

LRU算法

  package com.redis;

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

  /**
   * LRU缓存实现
   * 使用哈希表+双向链表实现O(1)时间复杂度的get和put操作
   */
  public class LRUCache {

      // 头部和尾部节点
      private Entry head, tail;

      // 当前缓存大小
      private int size;

      // 缓存容量
      private int capacity;

      // 哈希表用于快速查找
      private Map<Integer, Entry> cache;


      // 双向链表节点类
      public static class Entry{
          int key;
          int value;
          Entry prev;
          Entry next;

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

          public Entry() {

          }
      }

      /**
       * 构造函数初始化LRU缓存
       * @param capacity 缓存容量
       */
      public LRUCache(int capacity) {
          this.capacity = capacity;

          // 初始化链表
          initLinkedList();

          this.size = 0;

          cache = new HashMap <>(capacity + 2);
      }

      // 初始化链表
      private void initLinkedList() {
          head = new Entry();
          tail = new Entry();
          head.next = tail;
          tail.prev = head;
      }

      /**
       * 获取缓存值,如果不存在则返回-1,否则将节点移动到头节点,并返回节点数据
       * @param key 键
       * @return 如果key存在返回对应的value
       */
      public int get(int key) {
          Entry nodo = cache.get(key);
          if(nodo == null){
              return -1;
          }
          moveToHead(nodo);
          return nodo.value;
      }


      /**
       * 添加或更新缓存
       * @param key 键
       * @param value 值
       */
      public void put(int key, int value) {
          Entry node = cache.get(key);
          if(node != null){
              node.value = value;
              moveToHead(node);
              return;
          }

          // 不存在,先加进去,再移除尾节点
          // 此时容量已满,删除尾节点
          if(size == capacity){
              Entry lastNode = tail.prev;
              // 从链表中删除尾节点
              deleteNode(lastNode);
              // 从缓存中删除尾节点
              cache.remove(lastNode.key);
              size--;
          }

          // 将新的节点放置head节点的后面
          Entry newNode = new Entry();
          newNode.key = key;
          newNode.value = value;
          addToHead(newNode);
          cache.put(key,newNode);
          size ++;
      }



      /**
       * 移动节点到链表头部
       * @param node 要移动的节点
       */
      private void moveToHead(Entry node) {
          // 首先删除原来节点的关系
          deleteNode(node);

          // 将原来节点放置head节点的后面
          addToHead(node);
      }

      private void addToHead(Entry node) {

          node.prev = head;       // 新节点的prex--->指向head
          node.next = head.next;  // 新节点的next--->指向原节点

          head.next.prev = node;  //原节点的prev--->指向新节点
          head.next = node;       // head的next---> 指向新节点

      }


      private void deleteNode(Entry node) {
          node.prev.next = node.next;
          node.next.prev = node.prev;
      }


      /**
       * 打印当前缓存内容(用于调试)
       */
      public void printCache() {
          System.out.print("Cache: ");
          Entry current = head.next;
          while (current != tail) {
              System.out.print("[" + current.key + "=" + current.value + "] ");
              current = current.next;
          }
          System.out.println();
      }

      public static void main(String[] args) {
          // 测试案例
          LRUCache cache = new LRUCache(2);

          cache.put(1,1);
          cache.put(2,2);
          cache.printCache(); //21

          cache.get(1);
          cache.printCache(); // 12

          cache.put(3,3);
          cache.printCache(); //31

          System.out.println(cache.get(2)); // -1
      }
  }


执行结果

posted @ 2025-04-03 21:59  jock_javaEE  阅读(48)  评论(0)    收藏  举报