【python】自定义类:双向链表+字典

list在索引、加入/删除队尾元素时是O(1)的,但是在删除元素时是O(n)的;
deque在list基础上,删除队头元素是O(1)的,但是删除中间元素是O(n)的;
dict在增、删、改、查都是O(1)的,但是由于内存地址不连续,无法通过下标索引,所以无法实现删除第一个和最后一个元素的功能;
链表增/删任意元素都是O(1)的,但是查询时是O(n)的。
因为本文结合双向链表字典实现增、删、改、查都是O(1)的数据结构。

首先定义一个双向链表,作为字典【键值对】的value,并记录之前和之后的元素,方便从两个方向增删。

class ListNode:
    def __init__(self,key=None,val=None):
        self.key = key        # 键
        self.val = val        # 值
        self.pre = None
        self.next = None

其次定义一个字典,通过键来查询对应的链表结点。
定义虚拟头结点和尾结点,实现在链表左侧和右侧插入/删除元素的功能,且时间复杂度为O(1);删除任意元素时,首先通过字典查到在链表中的位置,进而再在链表中删除该结点,时间复杂度都为O(1)。
需要注意的是,每次增加和删除元素既要在链表中操作,也要在字典中操作。

class ListMap:
    def __init__(self):
        self.hash = dict()
        self.head = ListNode() 
        self.tail = ListNode()
        self.head.next = self.tail
        self.tail.pre = self.head
    
    def pushleft(self, key, val): # 在链表左侧插入元素结点
        node = ListNode(key,val)
        self.hash.setdefault(key,node) # 在字典中加入该键值对
        tmp = self.head.next
        self.head.next = node   # 建立新结点和原先链表的关系
        node.next = tmp
        tmp.pre = node
        node.pre = self.head
    
    def pushright(self, key, val): # 在链表右侧插入元素结点
        node = ListNode(key,val)
        self.hash.setdefault(key,node)
        tmp = self.tail.pre
        self.tail.pre = node
        node.pre = tmp
        tmp.next = node
        node.next = self.tail

    def get(self, key): # 通过键来查询值
        if key in self.hash:
            return self.hash[key]
        else:
            return None

    def remove(self, key): # 删除任意存在的元素
    	if self.get(key):
	        node = self.hash[key]
	        node.pre.next = node.next
	        node.next.pre = node.pre
	        del self.hash[key]  
    
    def popleft(self): # 删除链表左侧元素,实现deque.popleft()的功能
        node = self.head.next
        self.head.next = node.next
        node.next.pre = self.head
        del self.hash[node.key]
        return node.val
    
    def popright(self): # 删除链表右侧元素,实现list.pop()的功能
        node = self.tail.pre
        self.tail.pre = node.pre
        node.pre.next = self.tail
        del self.hash[node.key]
        return node.val

    def size(self):  # 返回字典的长度
        return len(self.hash)

使用时需要先将ListMap实例化,之后就可以直接调用自定义类的函数实现增删改查了。

利用上述结构就实现了LRU 缓存

Guess you like

Origin blog.csdn.net/LoveJSH/article/details/130458147