元月's blog 元月's blog
首页
  • 基础
  • 并发编程
  • JVM
  • Spring
  • Redis篇
  • Nginx篇
  • Kafka篇
  • Otter篇
  • Shardingsphere篇
  • 设计模式
  • MySQL
  • Oracle
  • 基础
  • 操作系统
  • 网络
  • 数据结构
  • 技术文档
  • Git常用命令
  • GitHub技巧
  • 博客搭建
  • 开发工具
更多

元月

临渊羡鱼,不如退而结网
首页
  • 基础
  • 并发编程
  • JVM
  • Spring
  • Redis篇
  • Nginx篇
  • Kafka篇
  • Otter篇
  • Shardingsphere篇
  • 设计模式
  • MySQL
  • Oracle
  • 基础
  • 操作系统
  • 网络
  • 数据结构
  • 技术文档
  • Git常用命令
  • GitHub技巧
  • 博客搭建
  • 开发工具
更多
  • 基础

  • 数据结构

    • 链表的基本操作:查找、删除
    • 链表的高级操作:链表的反转、合并、拆分
    • 链表的特殊状态:相交链表、回文链表、环形链表
    • 数组篇:双指针技巧
    • 数组篇:前缀和数组和差分数组
    • 数据结构与算法--跳表
    • 数据结构与算法--LRU算法
    • 数据结构与算法--LFU算法
      • 一、简介
      • 二、LFU算法的代码实现
        • 2.1、双链表的节点类
        • 2.2、双链表的实现类
        • 2.3、完整实现
  • 网络

  • 操作系统

  • 计算机网络
  • 数据结构
元月
2022-12-03
目录

数据结构与算法--LFU算法

# 数据结构与算法--LFU算法

# 一、简介

LFU 的全称是 Least Frequently Used(最近不经常使用),是一种缓存淘汰策略,它是根据频率维度来选择将要淘汰的元素,即删除访问频率最低的元素。如果两个元素的访问频率相同,则淘汰最久没被访问的元素。它的底层是 两个哈希表 + N个双链表 实现的,查找和添加的时间复杂度都是O(1)。

460. LFU 缓存 (opens new window)

# 二、LFU算法的代码实现

# 2.1、双链表的节点类

class DLinkedNode{//双链表节点类
        int key,val,freq;
        DLinkedNode pre,next;
        public DLinkedNode(int _key,int _val,int _freq){
            this.key = _key;
            this.val = _val;
            this.freq = _freq;
        }
}
1
2
3
4
5
6
7
8
9

# 2.2、双链表的实现类

class DLinkedList{//双链表
        DLinkedNode head,tail;//链表首尾结点

        public DLinkedList(){
            this.head = new DLinkedNode(-1,-1,-1);
            this.tail = new DLinkedNode(-1,-1,-1);
            head.next = tail;
            tail.pre = head;
        }

        public void addToHead(DLinkedNode node){//将节点添加到头部
            node.pre = head;
            node.next = head.next;
            head.next.pre = node;
            head.next = node;
        }

        public void removeNode(DLinkedNode node){//删除某个节点
            node.pre.next = node.next;
            node.next.pre = node.pre;
        }

        public boolean isEmpty(){//判断链表是否为空
            return head.next == tail;
        }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 2.3、完整实现

package com.offer;

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

class LFUCache {

    private Map<Integer,DLinkedNode> keyCache = new HashMap<>();

    private Map<Integer,DLinkedList> freqCache = new HashMap<>();

    int capacity;//容量

    int minFreq = 0;//记录缓存中最低频率

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

    public int get(int key) {
        DLinkedNode node = keyCache.get(key);
        if(node == null) return -1;
        //频率+1
        freqInc(node);
        return node.val;
    }

    public void put(int key, int value) {
        if(capacity == 0) return;
        DLinkedNode node = keyCache.get(key);
        if(node != null){
            node.val = value;//更改值
            freqInc(node);
        }else{
            //容量满了
            if(keyCache.size() == capacity){
                DLinkedList linkedList = freqCache.get(minFreq);
                keyCache.remove(linkedList.tail.pre.key);//删除keyCache
                linkedList.removeNode(linkedList.tail.pre);//删除DLinkedList尾部结点
                if(linkedList.isEmpty()){
                    //处理后,若此时minFreq的双链表为空
                    freqCache.remove(minFreq);
                }
            }
            //创建新节点
            DLinkedNode newNode = new DLinkedNode(key,value,1);
            keyCache.put(key,newNode);
            DLinkedList linkedList = freqCache.getOrDefault(newNode.freq,new DLinkedList());
            linkedList.addToHead(newNode);
            freqCache.put(newNode.freq,linkedList);
            minFreq = 1;

        }
    }

    public void freqInc(DLinkedNode node){
        //在当前频率(freq)链表中删除此结点
        int freq = node.freq;
        DLinkedList linkedList = freqCache.get(freq);
        linkedList.removeNode(node);
        if(linkedList.isEmpty()){
            //如果删除后,双链表为空,那么删除对应的频率
            freqCache.remove(freq);
            if(minFreq == freq){
                minFreq = freq + 1;
            }
        }
        //频率+1
        node.freq++;
        //在当前频率(freq+1)链表中插入此结点
        linkedList = freqCache.getOrDefault(node.freq,new DLinkedList());
        linkedList.addToHead(node);
        freqCache.put(node.freq,linkedList);

    }

    class DLinkedNode{//双链表节点类
        int key,val,freq;
        DLinkedNode pre,next;
        public DLinkedNode(int _key,int _val,int _freq){
            this.key = _key;
            this.val = _val;
            this.freq = _freq;
        }
    }

    class DLinkedList{//双链表
        DLinkedNode head,tail;//链表首尾结点

        public DLinkedList(){
            this.head = new DLinkedNode(-1,-1,-1);
            this.tail = new DLinkedNode(-1,-1,-1);
            head.next = tail;
            tail.pre = head;
        }

        public void addToHead(DLinkedNode node){//将节点添加到头部
            node.pre = head;
            node.next = head.next;
            head.next.pre = node;
            head.next = node;
        }

        public void removeNode(DLinkedNode node){//删除某个节点
            node.pre.next = node.next;
            node.next.pre = node.pre;
        }

        public boolean isEmpty(){//判断链表是否为空
            return head.next == tail;
        }

    }

    public static void main(String[] args) {
        LFUCache obj = new LFUCache(3);
        obj.put(1,11);
        obj.put(2,12);
        obj.put(3,13);
        obj.get(1);
        obj.get(2);
        obj.get(2);
        obj.get(2);
        obj.get(3);
        obj.get(3);
        obj.get(3);
        obj.put(4,14);
        System.out.println("args = " + Arrays.deepToString(args));
    }
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#数据结构
数据结构与算法--LRU算法
网络分层

← 数据结构与算法--LRU算法 网络分层→

最近更新
01
otter二次开发-支持按目标端主键索引Load数据
08-03
02
mvnw简介
06-21
03
gor流量复制工具
06-03
更多文章>
Theme by Vdoing | Copyright © 2022-2024 元月 | 粤ICP备2022071877号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式