lru 淘汰算法

lru算法

计算机的内存缓存是有限的,在缓存满了就需要淘汰一部分数据,LRU 算法就是一种常用的淘汰旧数据的算法,LRU 算法的全称是 Least Recently Used,按照最近最少使用的原则来筛选数据,最不常用的数据会被筛选出来,而最近频繁使用的数据会留在缓存中。核心思想 如果数据最近有被访问过,那么将来被访问的几率也更高 。 redis 和 mysql 都有使用 LRU 算法来淘汰冷数据。

LRU 会把所有的数据组织成一个链表。每当有新的数据就插入到链表的头部,当链表中的数据被访问,就把数据移动到链表头部,如果链表满了,就从链表末尾开始淘汰。
20220325104033

C# 实现,LinkedList 作为双向链表删除和插入效率都高,但是查找起来就需要遍历,操作的时间复杂度为 O(n),可以使用一个 Dictionary 来记录 key 在链表中的位置。

public class LruCache
{
    private LinkedList<KeyValuePair<int, string>> _list;
    private Dictionary<int, LinkedListNode<KeyValuePair<int, string>>> _map;
    private int _capacity;

    public LruCache(int capacity)
    {
        _capacity = capacity;
        _list = new LinkedList<KeyValuePair<int, string>>();
        _map = new Dictionary<int, LinkedListNode<KeyValuePair<int, string>>>();
    }

    /// <summary>
    /// 获取值,如果值存在就把当前值的移动到链表首部。
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public string Get(int key)
    {
        if (!_map.ContainsKey(key)) return string.Empty;
        var item = _map[key];
        _list.Remove(item);
        _map[key] = _list.AddFirst(item.Value);
        return item.Value.Value;
    }

    public void Put(int key, string value)
    {
        if (_map.ContainsKey(key))
        {
            // key存在更新值,并且移到首部。
            var item = _map[key];
            _list.Remove(item);
            _map[key] = _list.AddFirst(new KeyValuePair<int, string>(key, value));
        }
        else
        {
            // key不存在,判断是否链表还有空间。
            if (_list.Count >= _capacity)
            {
                // 淘汰末尾key
                _map.Remove(_list.Last.Value.Key);
                _list.RemoveLast();
            }

            _map[key] = _list.AddFirst(new KeyValuePair<int, string>(key, value));
        }
    }

posted @ 2022-03-25 14:26  她微笑的脸  阅读(353)  评论(0编辑  收藏  举报