其他分享
首页 > 其他分享> > LeetCode 146. LRU 缓存机制

LeetCode 146. LRU 缓存机制

作者:互联网

146. LRU 缓存机制

运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制

实现 LRUCache 类:

在这里插入图片描述

思路:上图是我打开app的顺序,从左到右,从上到下。最近打开的app是天气,往后依次是小黑盒,微博,tim。如果我切换到tim,那么tim就会插入到最前面,其他所有的应用都要往后挪。

设计一个链表与哈希表结合的数据结构,链表的结点Node既保存key又保存value,而哈希表只保存key和对应的Node。

这样频繁使用到链表头和链表尾的操作,双向链表是一个非常适合的数据结构。

代码:

struct Node {
    int key;// 链表的键
    int val;// 链表的值
    Node* prev;// 指向前一个结点的指针
    Node* next;// 指向后一个结点的指针
    Node(int key, int val) :key(key), val(val), prev(nullptr), next(nullptr) {}
};
struct my_list {
    Node* head;
    int size;
    my_list() {//链表初始化时,prev和next都指向头结点,形成环状,形成循环链表
        size = 0;
        head = new Node(-1, -1);
        head->next = head;
        head->prev = head;
    }
};
// 添加一个结点   prev--->node--->next
//				prev<---node<---next
// 这里的prev和next都代表一个结点,node是要添加的结点
void _add_node(Node* prev, Node* next, int key, int val) {
    Node* node = new Node(key, val);
    node->prev = prev;
    prev->next = node;

    node->next = next;
    next->prev = node;
}

// 和上面的函数同理
void _add_node(Node* prev, Node* next, Node* node) {
    node->prev = prev;
    prev->next = node;

    node->next = next;
    next->prev = node;
}

// 链表头添加
void add_head(my_list* list, int key, int val) {
    _add_node(list->head, list->head->next, key, val);
    list->size++;
}

// 链表尾添加
void add_tail(my_list* list, int key, int val) {
    _add_node(list->head->prev, list->head, key, val);
    list->size++;
}

// 把一个结点node移动,先让node的前一个结点的next指针指向node的下一个结点
// 然后让node的下一个结点的prev指针指向node的前一个结点
void _move(Node* node) {
    node->prev->next = node->next;
    node->next->prev = node->prev;
}

// 将一个结点移动到链表末尾
void move_to_tail(my_list* list, Node* node) {
    _move(node);
    _add_node(list->head->prev, list->head, node);
}

// 将一个链表中的结点删除
void delete_node(my_list *list,Node* node) {
    _move(node);
    list->size--;
}

// 删除头节点
void delete_head(my_list* list) {
    delete_node(list, list->head->next);
}

class LRUCache {
private:
    my_list* list;
    int capacity;
    unordered_map<int, Node*>umap;
public:
    LRUCache(int capacity):capacity(capacity) {
        list = new my_list();
    }

    int get(int key) {
        // 如果链表中键为key的结点,说明应用链表中存在这个app,现在把它打开
        // 它就在链表的最前面了(这里把链表尾作为最前面)
        if (umap.count(key)) {
            int val = umap[key]->val;
            move_to_tail(list, umap[key]);// 移动到末尾
            return val;
        }
        return -1;
    }

    void put(int key, int value) { 
        // 如果链表中存在键key的结点,此时要更新它的值
        // 然后将它移动到链表的最前面
        if (umap.count(key)) {
            umap[key]->val = value;
            move_to_tail(list, umap[key]);
            return;
        } 
        // 如果超过了容量,则删除最末尾的app(最久没有使用的),然后把新开的app
        // 添加到最前面
        if (list->size >= capacity) {
            umap.erase(list->head->next->key);
            delete_head(list);
        }
        add_tail(list, key, value);
        umap[key] = list->head->prev;
    }
};

标签:146,node,int,list,next,LRU,key,prev,LeetCode
来源: https://blog.csdn.net/qq_33894666/article/details/120246714