LRU cache实现,还是使用伪头部和伪尾部节点写代码更加简单
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;
}

浙公网安备 33010602011771号