Java自己实现一个LRU算法

LRU(Least Recently Used) 最近最少使用算法 在指定空间内, 存入元素时, 判断是否存在, 将其放置队列一端(如有取代旧元素). 当队满, 再添加新的元素时, 删除队列另一端的元素.
由于元素会频繁移动, 所以不能使用Array, 应考虑使用链表实现.

方案一

LinkedHashMap 是一个保存了元素插入顺序的HashMap.
accessOrder属性, 插入或获取元素时, 都会将其放入队尾.
removeEldestEntry方法, 是否删除最老的元素, 每次插入元素时都会被执行, 默认返回false.

创建子类

class LruLinkedHashMap<K, V> extends LinkedHashMap<K, V> {
    private int capacity;

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return this.size() > capacity;
    }

    LruLinkedHashMap(int capacity) {
        super(16, 0.75F, true); // accessOrder 必须为 true
        this.capacity = capacity;
    }
}

测试

public static void main(String[] args) {
    LruLinkedHashMap<String, String> map = new LruLinkedHashMap<>(4);
	map.put("1", "1");
	map.put("2", "2");
	map.put("3", "3");
	map.put("4", "4");
	map.put("5", "5");
	map.put("4", "7");
	map.forEach((key, value) -> System.out.println(key + "->" + value));
}

结果

2->2
3->3
5->5
4->7

Process finished with exit code 0

方案二

自定义双向链表, Node内部存储previous和next, 比较浪费空间, 但是提升了效率. 也可以使用单向链表.

链表类节点类

class Node<K, V> {

    private K key;
    private V value;
    private Node<K, V> previous, next;

    public Node(K key, V value, Node<K, V> previous, Node<K, V> next) {
        this.key = key;
        this.value = value;
        this.previous = previous;
        this.next = next;
    }

	// getter and setter
    ...
	
}

链表类
构造方法指定容量, 提供get和put方法

class LRULink<K, V> {
    private Node<K, V> head;
    private Node<K, V> tail;
    private int capacity;
    private int count;

    public LRULink(int capacity) {
        this.capacity = capacity;
    }

    public Node<K, V> get(K key) {
        if (head != null) {
            Node<K, V> current = head;
            do {
                if (current.getKey() == key || current.getKey().equals(key)) {
                    if (head == current) {
                        return head;
                    } else if (current.getNext() == null) {
                        // 获取的元素在队尾
                        current.getPrevious().setNext(null);
                    } else {
                        // 获取的元素在队中
                        current.getPrevious().setNext(current.getNext());
                        current.getNext().setPrevious(current.getPrevious());
                    }
                    head.setPrevious(current);
                    current.setNext(head);
                    current.setPrevious(null);
                    head = current;
                    return current;
                }
                current = current.getNext();
            } while (current != null && current.getNext() != null);
        }
        return null;
    }

    public void put(K key, V value) {
        Node<K, V> node = new Node<>(key, value, null, null);
        if (head == null) {
            tail = head = node;
            count = 1;
            return;
        }
        Node<K, V> dummy = get(key);
        if (dummy == null) {
            // 添加元素
            Node<K, V> oldHead = head;
            oldHead.setPrevious(node);
            node.setNext(oldHead);
            head = node;
            count++;
            checkCapacity();
        } else {
			// 变更元素值
            dummy.setValue(value);
        }
    }

	// 超过容量之后, 从尾部循环删除
    private void checkCapacity() {
        while (count > capacity) {
            tail = tail.getPrevious();
            tail.setNext(null);
            count--;
        }
    }

    public Node<K, V> getHead() {
        return head;
    }
}

测试

public static void main(String[] args) {
    LRULink<String, String> lruLink = new LRULink(5);
    lruLink.put("1", "1");
    lruLink.put("2", "2");
    lruLink.put("4", "4");
    lruLink.put("3", "3");
    lruLink.put("5", "5");
    lruLink.put("4", "7");

    Node<String, String> node = lruLink.getHead();
    do {
        System.out.println(node.getKey() + "->" + node.getValue());
        node = node.getNext();
    } while (node != null && node.getNext() != null);

}

结果

4->7
5->5
3->3
2->2

Process finished with exit code 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值