LFU算法Java实现

Redis内存淘汰策略中会使用到 LFU 算法,以下是简单说明及Java代码实现。

一、前言

LFU(The Least Frequently Used)即最不经常使用算法。其原理是如果一个数据最近被访问次数不多,那么将来它被使用的可能也更低,因此在内存达到一定阈值时,将最不经常使用的数据淘汰的一种策略算法。

二、图解

TODO 图解说明后期有空再补充

三、LFU 算法 Java 实现

3.1 定义节点类

节点Node类中应包含 key(键)、value(值)、cnt(使用频次)和prev(前置节点)、next(后置节点)指针

import lombok.Getter;
import lombok.Setter;

/**
 * 节点Node
 */
@Getter
@Setter
public class Node {
   
   

    /**
     * 节点键key
     */
    private int key;

    /**
     * 节点值value
     */
    private int value;

    /**
     * 使用频次
     */
    private int cnt;

    /**
     * 前置节点
     */
    private Node prev;

    /**
     * 后置节点
     */
    private Node next;

    public Node() {
   
   
    }

    public Node(int key, int value) {
   
   
        this.key = key;
        this.value = value;
        this.cnt = 1;
    }

}

注意:代码中 @Getter、@Setter 使用的是 lombok 插件,如果没有安装直接删除这两个注解和对应 import 导入逻辑,再手工给所有属性添加 Getter/Setter 方法即可,后续代码也是不做另外说明;

3.2 双向链表实现

双向链表中定义 dummyHead(虚拟头节点)、dummyTail(虚拟尾节点)两个虚拟头尾节点,避免后续处理中针对头尾节点的特殊处理;再用 length 属性维护链表长度

真实头节点:dummyHead.next
真实尾节点:dummyTail.prev

双向链表中定义 add、delete、deleteHead 方法,实现对链表的新增、删除及删除头节点功能(因为我们新增插入是在链表尾部,所以如需淘汰从链表头开始);

import lombok.Getter;
import lombok.Setter;

/**
 * 双向链表
 * LFU相同使用频次实现使用双向链表存储,头尾节点(head、tail)使用两个默认的虚拟节点,这样避免使用时针对头尾节点的特殊处理
 */
@Getter
@Setter
public class DoubleLinkedList {
   
   

    /**
     * 虚拟头节点,实际头节点应为dummyHead.next
     */
    private Node dummyHead;

    /**
     * 虚拟尾节点,实际尾节点应为dummyTail.prev
     */
    private Node dummyTail;

    /**
     * 链表长度
     */
    private int length;

    public DoubleLinkedList() {
   
   
        //默认虚拟头、尾节点初始化
        this.dummyHead = new Node();
        this.dummyTail = new Node();
        this.dummyHead.setNext(this.dummyTail);
        this.dummyTail.setPrev(this.dummyHead);
        this.length = 0;
    }

    /**
     * 添加节点
     * 每次添加节点在链表末尾
     * @param node
     */
    public void add(Node node) {
   
   
        node.setNext(this.dummyTail);
        node.setPrev(this.dummyTail.getPrev());
        this.dummyTail.getPrev().setNext(node);
        this.dummyTail.setPrev(node);
        this.length++;
    }

    /**
     * 删除节点
     * @param node
     */
    public void delete(Node node) {
   
   
        node.getPrev().setNext(node.getNext());
        node.getNext().setPrev(node.getPrev());
        node.setPrev(null);
        node.setNext(null);
        this
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值