Sword Pointer Offer II 031. Least Recently Used Cache

insert image description here
Idea:
    This is equivalent to building a doubly linked list. The value part of the linked list is a hash table. Its function is to use the hash table to quickly find the specified node of the linked list.
(1) Build a linked list

class DLinkNode {
    
    
public:
    int key, value;
    DLinkNode* prev, * next;
    DLinkNode() : key(0), value(0), prev(nullptr), next(nullptr) {
    
    }
    DLinkNode(int _key, int _value) : key(_key), value(_value), prev(nullptr), next(nullptr) {
    
    }
};

(2) The initialization parameter
    uses capacity to save the capacity, and size to control the capacity after each addition. head and tail are used to control the head and tail of the linked list, head always points to the head, and tail always points to the end.

int size, capacity;
DLinkNode* head, * tail;
unordered_map<int, DLinkNode*> hash;

(3) Initialize the linked list

LRUCache(int capacity) :
    size(0), capacity(capacity)
{
    
    
    // 初始化双向链表
    head = new DLinkNode();
    tail = new DLinkNode();
    head->next = tail;
    tail->prev = head;
}

(4) Two operations
    The first operation is to get a key and return its value. The second operation is put, which modifies the value of the corresponding key. If it does not exist, create a new one. If it exceeds the upper limit, remove the first one (the one with the lowest usage rate). So we have the following operations on the linked list
    ① delete a node at a certain position. void deleteNode(int key)
    ② Add a node at the end. void add2Tail(int key)
    ③When the upper limit is exceeded, delete the first node. void deleteHead()

    When operating, first understand the logic:

    get(): Determine whether this value already exists, if so, return the corresponding value, and move this node to the end.

int get(int key) {
    
    
    // 若不存在 key
    if (hash.count(key) == 0) {
    
    
        return -1;
                  }
    move2Tail(key); // 最近访问的 key 挪到链尾
    return hash[key]->value;
}

    put(): If there is a key, modify the value and move at the same time, which is similar to put here. If it does not exist, create a new node and insert the end of the chain, size++. If the size exceeds the capacity, delete the chain head node.

void put(int key, int value) {
    
    
    // 若已存在 key
    if (hash.count(key) != 0) {
    
    
        // 修改已有 key 所对应的 value
        hash[key]->value = value;
        move2Tail(key); // 挪到链尾
        return;
    }
    // 若不存在则 new
    DLinkNode* newNode = new DLinkNode(key, value);
    hash[key] = newNode;
    // 插入链尾
    add2Tail(key);
    size++;
    // 若超出规定容量                                                                                           
    if (size > capacity) {
    
    
        deleteHead();
        size--;
    }
}

(5) Operate the linked list

void deleteNode(int key) {
    
    
    // key 的前驱 next 指向 key 的后继  
    hash[key]->prev->next = hash[key]->next;
    // key 的后继 prev 指向 key 的前驱 
    hash[key]->next->prev = hash[key]->prev;
}

void add2Tail(int key) {
    
    
    // tail 的前驱 next 指向 key   
    tail->prev->next = hash[key];
    // key 的 prev 指向 tail 的前驱
    hash[key]->prev = tail->prev;
    // tail 的 prev 指向 key
    tail->prev = hash[key];
    // key 的 next 指向 tail
    hash[key]->next = tail;
}
void move2Tail(int key) {
    
    
    deleteNode(key);
    add2Tail(key);
}

void deleteHead() {
    
    
    DLinkNode* deleted = head->next;
    // head 的 next 指向 head 的后继 next
    head->next = deleted->next;
    // head 后继的 prev 指向 head
    deleted->next->prev = head;
    // 同时也从 hash 中注销
    hash.erase(deleted->key);
    delete deleted;
}

Guess you like

Origin blog.csdn.net/daweq/article/details/130502391