LRU缓存算法设计——哈希双端链表

原题在这里

  题意:实现满足O(1)时间复杂度的get和put操作的LRU算法。

analyse:

  1.第一次做的时候,选用了图论中链式前向星+set哈希处理的解法

    思路:翻译为图,也就是找num时间戳在capacity范围内的边

      对于每一个key,就当作一个节点,每指向一个value就是一条边

      get操作:

        head[key]==0:

          return -1

        head[key]!=0:

           找到对应的num时间戳,哈希set删除,并新建该边。

      put操作:

        如果哈希set中存在时间戳,那么删除

        直接新建边

      建边处理:

        定义数组head,id,mp分别表示key指向num时间戳,num时间戳指向key,num时间戳指向value

        哈希set,表示当前LRU存在的时间戳列表。

        添加head、id、mp数组元素和set当前时间戳

          如果set列表数量大于capacity,则情况set列表头时间戳对应的head对应的key值所指向的时间戳

code:

class LRUCache
{
    //翻译在链式前向星图中就是,在num时间戳为固定范围内的边
    vector<int> head, id, mp; // key指向num时间戳,num时间戳指向key,num时间戳指向value
    set<int> st;              //存在的num时间戳表
    int num, m;
    void add(int x, int y)
    {
        //如果有,固定删除head[x]所对应的边,但是不需要实际操作
        mp.emplace_back(y);
        head[x] = ++num;
        id.emplace_back(x);
        st.insert(num);
        while (st.size() > m)
        {
            head[id[*st.begin()]] = 0;
            st.erase(st.begin());
        }
    }

public:
    LRUCache(int capacity)
    {
        num = 0, m = capacity;
        head = vector<int>(1e4 + 9);
        mp.clear(), id.clear();
        id.emplace_back(0);
        mp.emplace_back(0);
        st.clear();
    }

    int get(int key)
    {
        if (head[key] != 0)
        {
            int x = head[key], y = mp[x];
            st.erase(x);
            add(key, mp[x]);
            return y;
        }
        return -1;
    }

    void put(int key, int value)
    {
        int x = head[key];
        if (x)
            st.erase(x); //如果有,直接删除后添加
        add(key, value);
    }
};
图式解法

  2.标准解法,map哈希+双端链表

    思路:map存key对应node节点,另外定义整数类型size表示链表节点数量。

    get:

      如果没有则-1,有则直接mp[key]->val,并且将该节点置于链表头。

    put:

      如果没有则新建,否则返回val并且置于表头。

      如果数量大于capacity,那么将链表末尾节点删除。

code:

class LRUCache
{
    struct Node
    {
        int key, val;
        Node *next, *prev;
        Node() : key(0), val(0), next(nullptr), prev(nullptr){};
        Node(int x, int y) : key(x), val(y), next(nullptr), prev(nullptr){};
    };
    map<int, Node *> mp;
    Node *head, *tail;
    int size, mx;

public:
    LRUCache(int capacity)
    {
        head = new Node();
        tail = new Node();
        head->next = tail;
        tail->prev = head;
        size = 0, mx = capacity;
    }
    void add(Node *node)
    {
        node->prev = head;
        node->next = head->next;
        head->next->prev = node;
        head->next = node;
    }
    void remove(Node *node)
    {
        node->prev->next = node->next;
        node->next->prev = node->prev;
    }
    void move(Node *node)
    {
        remove(node);
        add(node);
    }
    Node *Remove()
    {
        Node *node = tail->prev;
        remove(node);
        return node;
    }
    int get(int key)
    {
        if (mp.count(key) == 0)
            return -1;
        Node *node = mp[key];
        move(node);
        return node->val;
    }

    void put(int key, int value)
    {
        if (mp.count(key) == 0)
        {
            Node *node = new Node(key, value);
            mp[key] = node;
            add(node);
            ++size;
            if (size > mx)
            {
                Node *removed = Remove();
                mp.erase(removed->key);
                delete removed;
                --size;
            }
        }
        else
        {
            Node *node = mp[key];
            node->val = value;
            move(node);
        }
    }
};
Map哈希+双端链表

  3.优化解,时间戳哈希+双端链表

    思路:引入一个vector和一个整型变量num时间戳,记录key对应的num时间戳。

    限制于本题key数据范围为[0,1e4]。

code:

class LRUCache
{
    struct Node
    {
        int key, val;
        Node *next, *prev;
        Node() : key(0), val(0), next(nullptr), prev(nullptr){};
        Node(int x, int y) : key(x), val(y), next(nullptr), prev(nullptr){};
    };
    Node *head, *tail;
    int size, mx;
    vector<Node *> nums;
    vector<int> start; //存入每一个key对应的num
    int num;

public:
    LRUCache(int capacity)
    {
        head = new Node();
        tail = new Node();
        head->next = tail;
        tail->prev = head;
        size = 0, mx = capacity;

        start = vector<int>(1e4 + 9, -1);
        num = 0;
    }
    void add(Node *node)
    {
        node->prev = head;
        node->next = head->next;
        head->next->prev = node;
        head->next = node;
    }
    void remove(Node *node)
    {
        node->prev->next = node->next;
        node->next->prev = node->prev;
    }
    void move(Node *node)
    {
        remove(node);
        add(node);
    }
    Node *Remove()
    {
        Node *node = tail->prev;
        remove(node);
        return node;
    }
    int get(int key)
    {
        if (start[key] == -1)
            return -1;
        Node *node = nums[start[key]];
        move(node);
        return node->val;
    }

    void put(int key, int value)
    {
        if (start[key] == -1)
        {
            Node *node = new Node(key, value);
            start[key] = num++;
            nums.emplace_back(node);
            add(node);
            ++size;
            if (size > mx)
            {
                Node *removed = Remove();
                start[removed->key] = -1; //不用真删除nums内节点
                delete removed;
                --size;
            }
        }
        else
        {
            Node *node = nums[start[key]];
            node->val = value;
            move(node);
        }
    }
};
最优解

 

【Over

posted @ 2022-05-12 15:04  Renhr  阅读(43)  评论(0)    收藏  举报