PHP利用双向链表方式实现LFU(最不常使用)缓存算法

请你为 最不经常使用(LFU)缓存算法设计并实现数据结构。

实现 LFUCache 类:

  • LFUCache(int capacity) - 用数据结构的容量 capacity 初始化对象
  • int get(int key) - 如果键 key 存在于缓存中,则获取键的值,否则返回 -1 。
  • void put(int key, int value) - 如果键 key 已存在,则变更其值;如果键不存在,请插入键值对。当缓存达到其容量 capacity 时,则应该在插入新项之前,移除最不经常使用的项。在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,应该去除 最近最久未使用 的键。
  • 为了确定最不常使用的键,可以为缓存中的每个键维护一个 使用计数器 。使用计数最小的键是最久未使用的键。

当一个键首次插入到缓存中时,它的使用计数器被设置为 1 (由于 put 操作)。对缓存中的键执行 get 或 put 操作,使用计数器的值将会递增。

函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。

代码如下:
<?php

class Node
{
    public $key;
    public $val;
    public $prev;
    public $next;
    public $count;

    public function __construct($key, $val, $count = 1)
    {
        $this->key = $key;
        $this->val = $val;
        $this->count = $count;
    }
}

class LinkDoubleList
{

    protected $head;
    protected $tail;

    public function __construct()
    {
        $this->head = new Node(0, 0, PHP_INT_MAX);
        $this->tail = new Node(-1, 0, -1);
        $this->head->next = $this->tail;
        $this->tail->prev = $this->head;
    }

    public function updateSort(Node $node)
    {
        $node->count++;
        //取node前置节点
        $prev = $node->prev;
        while ($prev->count <= $node->count) {
            //获取前置节点和后置节点
            $start = $prev->prev;
            $end = $node->next;

            //开始互换位置
            $start->next = $node;
            $node->prev = $start;

            $node->next = $prev;
            $prev->prev = $node;

            $prev->next = $end;
            $end->prev = $prev;
            //位置调换结束后,将node的前置节点更新
            $prev = $start;
        }
    }

    public function removeTail()
    {
        $last = $this->tail->prev;
        $last->prev->next = $this->tail;
        $this->tail->prev = $last->prev;
        return $last->key;
    }

    public function addToLast(Node $node)
    {
        $prev = $this->tail->prev;
        $prev->next = $node;
        $node->prev = $prev;
        $node->next = $this->tail;
        $this->tail->prev = $node;
    }

}


class LFUCache
{

    public $linkDoubleList;
    public $capacity;
    public $cache = [];

    public function __construct($capacity)
    {
        $this->linkDoubleList = new LinkDoubleList();
        $this->capacity = $capacity;

    }


    public function get(int $key)
    {
        if (!isset($this->cache[$key])) {
            return -1;
        }
        $node = $this->cache[$key];
        $this->linkDoubleList->updateSort($node);
        return $node->val;
    }

    public function put(int $key, int $value)
    {
        if (isset($this->cache[$key])) {
            $this->cache[$key]->val = $value;
            $this->linkDoubleList->updateSort($this->cache[$key]);
            return;
        }
        if (count($this->cache) == $this->capacity) {
            if ($this->capacity === 0) {
                return;
            }
            $tail = $this->linkDoubleList->removeTail();
            unset($this->cache[$tail]);
        }


        $node = new Node($key, $value);
        $this->linkDoubleList->addToLast($node);
        $this->linkDoubleList->updateSort($node);
        $this->cache[$key] = $node;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

就叫我菜菜吧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值