LRU cache实现,还是使用伪头部和伪尾部节点写代码更加简单

发布时间 2024-01-11 22:31:22作者: bonelee
class Node:
    def __init__(self, key, val):
        self.key = key
        self.val = val
        self.prev = None
        self.next = None

class LRUCache:
    def __init__(self, capacity):
        self.capacity = capacity
        self.hashmap = {}
        # 使用伪头部和伪尾部节点
        self.head = Node(0, 0)
        self.tail = Node(0, 0)
        self.head.next = self.tail
        self.tail.prev = self.head

    def get(self, key):
        if key in self.hashmap:
            node = self.hashmap[key]
            self._remove(node)
            self._add(node)
            return node.val
        return -1

    def put(self, key, value):
        if key in self.hashmap:
            self._remove(self.hashmap[key])
        node = Node(key, value)
        self._add(node)
        self.hashmap[key] = node
        if len(self.hashmap) > self.capacity:
            node = self.head.next
            self._remove(node)
            del self.hashmap[node.key]

    def _remove(self, node):
        prev = node.prev
        next = node.next
        prev.next = next
        next.prev = prev

    def _add(self, node):
        prev = self.tail.prev
        prev.next = node
        self.tail.prev = node
        node.prev = prev
        node.next = self.tail

# 创建一个容量为2的LRU缓存
cache = LRUCache(2)

# 插入键值对("192.168.1.1", 1)
cache.put("192.168.1.1", 1)
assert cache.get("192.168.1.1") == 1  # 返回1

# 插入键值对("192.168.1.2", 2)
cache.put("192.168.1.2", 2)
assert cache.get("192.168.1.2") == 2  # 返回2

# 再次访问键"192.168.1.1"
assert cache.get("192.168.1.1") == 1  # 返回1

# 插入键值对("192.168.1.3", 3),这会导致键"192.168.1.2"被删除,因为它是最近最少使用的键
cache.put("192.168.1.3", 3)
assert cache.get("192.168.1.2") == -1  # 返回-1,因为键"192.168.1.2"已经被删除

# 再次访问键"192.168.1.1"
assert cache.get("192.168.1.1") == 1  # 返回1

# 插入键值对("192.168.1.4", 4),这会导致键"192.168.1.3"被删除,因为它是最近最少使用的键
cache.put("192.168.1.4", 4)
assert cache.get("192.168.1.3") == -1  # 返回-1,因为键"192.168.1.3"已经被删除

  

核心:

(1)只要访问过,或者新节点,就将节点放到tail,区别无非是访问的节点修改前后link;

(2)只要是删除,就将节点从head里remove。

void lru_add_to_tail(struct brief_asset_info *node)
{
    // 将对应的节点添加到双向链表的尾部,作为LRU的最新节点
    node->prev = g_asset_portray_lru.dummy_tail->prev;
    node->next = g_asset_portray_lru.dummy_tail;
    g_asset_portray_lru.dummy_tail->prev->next = node;
    g_asset_portray_lru.dummy_tail->prev = node;
}

void lru_move_to_tail(struct brief_asset_info *node)
{
    // 移动节点到到双向链表的尾部,作为LRU的最新节点
    node->prev->next = node->next;
    node->next->prev = node->prev;
    lru_add_to_tail(node);
}

struct brief_asset_info *lru_delete_head()
{
    struct brief_asset_info *node = g_asset_portray_lru.dummy_head->next;
    g_asset_portray_lru.dummy_head->next = node->next;
    node->next->prev = g_asset_portray_lru.dummy_head;
    return node;
}

  

实际C代码应用伪代码:

struct asset_nlog_ua *asset_check_iot_xxx(struct asset_info *info, bool *is_counterfeit)
{
    struct ip_mac ip_mac_key = {0};
    ip_mac_key.ip = info->ip;
    ip_mac_key.mac = info->mac;
    struct ase_hash *asset_portray = g_asset_portray_lru.asset_portray_map;
    struct brief_asset_info *found_info = asset_find_iot_portray(&ip_mac_key, asset_portray);
    struct asset_nlog_ua *event = NULL;
    if (found_info != NULL) {
        if (check_asset_conflict(found_info, info)) {
            // 误报检查,非误报才生成事件
            if (!asset_check_counterfeit_false_alarm(&found_info->ip_mac_key.ip, &found_info->ip_mac_key.mac)) {
                *is_counterfeit = true;
                event = asset_generate_iot_event(found_info, info);
                // 刷新LRU cache,更新访问的最新资产
                lru_move_to_tail(found_info);
                return;
            }
        }

        // 资产属性不冲突,或者冲突但属于误报,更新已经存在的画像
        asset_update_iot_portray(info, found_info, asset_portray);
        // 刷新LRU cache,更新修改后的最新资产
        lru_move_to_tail(found_info);
    } else {
        // 新建画像,需要考虑是否满规格,满规格情况下需要删除LRU中的老资产
        if (g_asset_portray_lru.asset_portray_map->n_entry >= g_asset_portray_lru.capacity) {
            ASE_INFO(ASE_CATE_ASSET, "[iot] asset_portray_map exceed max capacity, will asset_delete_oldest_portray.");
            asset_delete_oldest_portray(asset_portray);
        }

        struct brief_asset_info *new_info = asset_insert_iot_portray(info, asset_portray);
        // 刷新LRU cache,更新新建的最新资产
        lru_add_to_tail(new_info);
    }
    return event;
}