0
点赞
收藏
分享

微信扫一扫

java hashmap lru

晗韩不普通 2023-07-16 阅读 57

实现 Java HashMap LRU

简介

LRU(Least Recently Used,即最近最少使用)是一种常见的缓存淘汰策略,它的原理是根据数据的访问时间来决定数据是否被淘汰。在 Java 中,我们可以通过使用 HashMap 和双向链表来实现 LRU 缓存。

实现步骤

下面是实现 Java HashMap LRU 的步骤:

步骤 操作
1 创建一个 HashMap 用于存储数据
2 创建一个双向链表用于维护数据的访问顺序
3 当访问一个数据时,如果数据已经存在于 HashMap 中,则将其从链表中移除并放到链表头部;如果数据不存在于 HashMap 中,则将其添加到链表头部
4 当链表的长度超过设定的阈值时,将链表尾部的数据从 HashMap 和链表中移除

接下来我们一步一步实现上述步骤。

创建 HashMap 和双向链表

首先,我们需要创建一个 HashMap 和一个双向链表。Java 中提供了相应的类可以直接使用,所以我们只需要实例化它们即可。

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

public class LRUCache<K, V> {
    private Map<K, Node<K, V>> cache;
    private Node<K, V> head;
    private Node<K, V> tail;
    private int capacity;

    public LRUCache(int capacity) {
        this.cache = new HashMap<>();
        this.head = new Node<>();
        this.tail = new Node<>();
        this.head.next = tail;
        this.tail.prev = head;
        this.capacity = capacity;
    }
}

class Node<K, V> {
    K key;
    V value;
    Node<K, V> prev;
    Node<K, V> next;
}

在上述代码中,我们定义了一个泛型类 LRUCache,其中 K 表示键的类型,V 表示值的类型。cache 是用于存储数据的 HashMap,headtail 分别表示双向链表的头部和尾部。capacity 表示缓存容量。

访问数据

当访问一个数据时,我们需要判断该数据是否已经存在于 HashMap 中。如果存在,我们需要将其从链表中移除并放到链表头部;如果不存在,我们需要将其添加到链表头部。

public V get(K key) {
    Node<K, V> node = cache.get(key);
    if (node == null) {
        return null;
    }
    // 将访问的数据移到链表头部
    moveToHead(node);
    return node.value;
}

public void put(K key, V value) {
    Node<K, V> node = cache.get(key);
    if (node == null) {
        // 如果数据不存在,创建一个新的节点,并将其添加到链表头部和 HashMap 中
        Node<K, V> newNode = new Node<>();
        newNode.key = key;
        newNode.value = value;
        cache.put(key, newNode);
        addToHead(newNode);
        if (cache.size() > capacity) {
            // 如果链表长度超过容量,移除链表尾部的节点
            Node<K, V> tailNode = removeTail();
            cache.remove(tailNode.key);
        }
    } else {
        // 如果数据已经存在,更新其值,并将其移动到链表头部
        node.value = value;
        moveToHead(node);
    }
}

private void moveToHead(Node<K, V> node) {
    removeNode(node);
    addToHead(node);
}

private void removeNode(Node<K, V> node) {
    node.prev.next = node.next;
    node.next.prev = node.prev;
}

private void addToHead(Node<K, V> node) {
    node.prev = head;
    node.next = head.next;
    head.next.prev = node;
    head.next = node;
}

private Node<K, V> removeTail() {
    Node<K, V> tailNode = tail.prev;
    removeNode(tailNode);
    return tailNode;
}

在上述代码中,get 方法用于获取数据,put 方法用于插入或更新数据。moveToHead 方法用于将访问的数据移到链表头部,removeNode 方法用于从链表中移除节点,addToHead 方法用于将节点添加到链表头部,removeTail 方法用于移除链表尾部

举报

相关推荐

0 条评论