PHP实现简单的LRU算法

/**
 * LRU算法
 * 构造一个双向链表(双向链表删除尾部节点的上一个元素时间复杂度为O(1))
 */
class LRUCache
{

    //头部节点
    private $head;

    //尾部节点
    private $tail;

    //最大容量,大于淘汰尾部节点指向的上一个元素
    private $capacity;

    //存放key对应的节点 key => node
    private $hashmap;

    /**
     * 初始化头部尾部节点
     * LRUCache constructor.
     * @param $capacity
     */
    public function __construct($capacity)
    {
        $this->capacity = $capacity;
        $this->hashmap = array();
        $this->head = new Node(null, null);
        $this->tail = new Node(null, null);
        //头结点右指针指向尾结点
        $this->head->setNext($this->tail);
        //尾结点左指针指向头结点
        $this->tail->setPrevious($this->head);
    }

    /**
     * 获取元素
     * @param $key
     * @return null
     */
    public function get($key)
    {

        if (!isset($this->hashmap[$key])) {
            return null;
        }

        $node = $this->hashmap[$key];
        if (count($this->hashmap) == 1) {
            return $node->getData();
        }

        //先删除已经存在的结点
        $this->detach($node);
        //重新将新结点插入到头结点之后
        $this->attach($this->head, $node);

        return $node->getData();
    }

    /**
     * 设置key value
     * @param $key
     * @param $data
     * @return bool
     */
    public function put($key, $data)
    {
        if ($this->capacity <= 0) {
            return false;
        }
        if (isset($this->hashmap[$key]) && !empty($this->hashmap[$key])) {
            $node = $this->hashmap[$key];
            //重置结点到头结点之后
            $this->detach($node);
            $this->attach($this->head, $node);
            $node->setData($data);
        } else {
            $node = new Node($key, $data);
            $this->hashmap[$key] = $node;
            //添加节点到头部节点之后
            $this->attach($this->head, $node);
            //检测容量是否达到最大值
            if (count($this->hashmap) > $this->capacity) {
                //如果达到最大值 删除尾节点左指针指向的元素
                $nodeToRemove = $this->tail->getPrevious();
                $this->detach($nodeToRemove);
                unset($this->hashmap[$nodeToRemove->getKey()]);
            }
        }
        return true;
    }


    /**
     * 删除key
     * @param $key
     * @return bool
     */
    public function remove($key)
    {
        if (!isset($this->hashmap[$key])) {
            return false;
        }
        $nodeToRemove = $this->hashmap[$key];
        $this->detach($nodeToRemove);
        unset($this->hashmap[$nodeToRemove->getKey()]);
        return true;
    }


    /**
     * 添加新结点到头结点之后
     * @param $head
     * @param $node
     */
    private function attach($head, $node)
    {
        //双向链表插入一个元素到头结点之后
        $node->setPrevious($head);
        $node->setNext($head->getNext());
        $node->getNext()->setPrevious($node);
        $node->getPrevious()->setNext($node);
    }


    /**
     * 删除结点
     * @param $node
     */
    private function detach($node)
    {
        $node->getPrevious()->setNext($node->getNext());
        $node->getNext()->setPrevious($node->getPrevious());
    }

}

/**
 * 结点数据结构
 */
class Node
{

    private $key;

    //key对应的内容
    private $data;

    //结点右指针
    private $next;

    //结点左指针
    private $previous;

    /**
     * Node constructor.
     * @param $key
     * @param $data
     */
    public function __construct($key, $data)
    {
        $this->key = $key;
        $this->data = $data;
    }

    /**
     * Sets a new value for the node data
     * @param string the new content of the node
     */
    public function setData($data)
    {
        $this->data = $data;
    }

    /**
     * Sets a node as the next node
     * @param Node $next the next node
     */
    public function setNext($next)
    {
        $this->next = $next;
    }

    /**
     * Sets a node as the previous node
     * @param Node $previous the previous node
     */
    public function setPrevious($previous)
    {
        $this->previous = $previous;
    }

    /**
     * Returns the node key
     * @return string the key of the node
     */
    public function getKey()
    {
        return $this->key;
    }

    /**
     * Returns the node data
     * @return mixed the content of the node
     */
    public function getData()
    {
        return $this->data;
    }

    /**
     * Returns the next node
     * @return Node the next node of the node
     */
    public function getNext()
    {
        return $this->next;
    }

    /**
     * Returns the previous node
     * @return Node the previous node of the node
     */
    public function getPrevious()
    {
        return $this->previous;
    }

}

$cache = new LRUCache(10);
$cache->put('myKey', 'myValue');
echo $cache->get('myKey');```
posted @ 2020-12-22 16:12  Master-lcf  阅读(293)  评论(0)    收藏  举报