美文网首页
链表Linked List, since 2022-05-04

链表Linked List, since 2022-05-04

作者: Mc杰夫 | 来源:发表于2022-05-04 14:00 被阅读0次

    (2022.05.04 Wed)

    Doubly Linked List双向链表

    采用基于array形式的链表,如Python list,为找到某特定元素只需要知道该元素的index即可,查找方便,但在非array链表实现过程中查找某特定元素需要从表头开始遍历链表直到找到,效率低下。在这里给链表实现引入了定位(position),相当于对某特定元素a加标签,保留该标签可随时找到a,不管链表如何变化,方便了定位。

    为了理解定位信息,可设想这样一种情况:多人排队做活宣,Jack身在其中,Jack前面的人会减少,后面的人会增加,前面也有可能有人插队,但不管队伍怎么变化,Jack总能在队伍中被轻易认出。好像Jack头上有个标志牌,只要看到该牌子就能找到Jack。链表中加入的定位信息,相当于这个标志牌。

    这里使用双向链表Doubly Linked List,即表头表尾加占位符号header和trailer,这样保证除header和trailer外的所有节点都有prevnext属性,便于执行对链表的修改。header和trailer不保存链表信息。

    实现

    这里我们给出带位置的双向链表PositionalList的实现过程。

    首先设置双向链表基类_DoubleLinkedBase
    在基类中定义基本方法,即插入和删除。设置嵌入类nested class,即_Node用于封装节点信息,封装内容包括,1.节点所代表的元素, 2.节点前置点, 3.节点后置点。基类的header和trailer都初始化为空值None,且互为后置前置节点。加入__slots__可在实例化时减少内存的使用,特别是大量实例化的时候。

    class _DoubleLinkedBase:
    
        class _Node:
            __slots__ = '_element', '_prev', '_next'
            def __init__(self, element, prev, next):
                self._element = element
                self._prev = prev
                self._next = next
    
        def __init__(self):
            self._header = self._Node(None, None, None)
            self._trailer = self._Node(None, None, None)
            self._header._next = self._trailer
            self._trailer._prev = self._header
            self._size = 0
    
        def __len__(self):
            return self._size
    
        def is_empty(self):
            return self._size == 0
    
        def _insert_between(self, e, predecessor, successor):
            newest = self._Node(e, predecessor, successor)
            predecessor._next = newest
            successor._prev = newest
            self._size += 1
            return newest
    
        def _delete_node(self, node):
            predecessor = node._prev
            successor = node._next
            predecessor._next = successor
            successor._prev = predecessor
            self._size -= 1
            element = node._element
            node._prev = node._next = node._element = None
            return element
    

    接下来创建带位置信息的类PositionalList,其继承自_DoubleLinkedBase。在该类中,创建nested class Position,该类包含了节点的信息和所在的容器(即链表)。该链表的内置方法包括

    • _make_position: 将输入节点封装为Position类,对header和trailer不执行该操作
    • _validate: 验证输入的对象p是否,1. 是Position类,2. 在同一个容器(链表)中,3. 其下一个节点为None,即是否可用。验证通过,返回该输入对象的节点信息,即p._node
    • _insert_between: 在两个节点间插入新节点,继承了_DoubleLinkedBase的中方法,返回封装后的Position类对象
    • 查询first last before after: 如名字所示,查询链表的首、尾元素,和指定元素的前、后元素。返回结果是经过封装的Position类对象。注意,链表的首元素非header元素,而是header的下一个元素,尾元素同理。
    • 更新add_first add_last add_before add_after: 更新,返回都是经过封装的Position类对象
    • 删除替换delete replace: 略
    class PositionalList(_DoubleLinkedBase):
    
        #------------------------ nested Position class --------------------------
        class Position:
    
            def __init__(self, container, node):
                self._container = container
                self._node = node
    
            def element(self):
                return self._node._element
    
            def __eq__(self, other):
                return type(self) is type(other) and other._node is self._node
    
            def __ne__(self, node):
                return not (self == node)
        #---------------------------- utility method -------------------------------
        def _validate(self, p):
            '''Return position s node, or raise appropriate error if invalid.'''
            if not isinstance(p, self.Position):
                raise TypeError('p must be of Position type')
            if p._container is not self:
                raise ValueError('P does not belong to this container')
            if p._node._next is None:
                raise ValueError('p is no longer valid')
            return p._node
    
        def _make_position(self, node):
            if node is self._header or node is self._trailer:
                return None
            else:
                return self.Position(self, node)
    
        def first(self):
            # first node is NOT header, but the first after header
            return self._make_position(self._header._next)
    
        def last(self):
            return self._make_position(self._trailer._prev)
    
        def before(self, p):
            n = self._validata(p)
            return self._make_position(n._prev)
    
        def after(self, p):
            n = self._validate(p)
            return self._make_position(n._next)
    
        def __iter__(self):
            cursor = self.first()
            while cursor is not None:
                yield cursor.element()
                cursor = self.after(cursor)
    
        def _insert_between(self, e, predecessor, successor):
            node = super()._insert_between(e, predecessor, successor)
            return self._make_position(node)
    
        def add_first(self, e):
            return self._insert_between(e, self._header, self._header._next)
    
        def add_last(self, e):
            return self._insert_between(e, self._trailer._prev, self._trailer)
    
        def add_before(self, p, e):
            original = self._validate(p)
            return self._insert_between(e, original._prev, original)
    
        def add_after(self, p, e):
            original = self._validate(p)
            return self._insert_between(e, original, original._next)
    
        def delete(self, p):
            original = self._validate(p)
            return self._delete_node(original)
    
        def replace(self, p, e):
            original = self._validate(p)
            old_old = original._element
            original._elemenet = e
            return old_value
    

    应用如下

    >>> pl = PositionalList()
    >>> pl._header._element
    >>> pl._trailer._element
    >>> pl._header._next._element
    >>> a1 = pl.add_first(365) # 首元素365
    >>> a2 = pl.add_after(a1, 10086) # 在365后加入10086
    >>> a3 = pl.add_before(a2, 1314) # 在10086前计入1314
    # 此时该链表中元素顺序是365->1314->10086,位置顺序为a1->a3->a2
    >>> a3.element()
    1314
    >>> a3._node._next._element
    10086
    >>> a3._node._prev._element
    365
    >>> print(a1._node._prev._element)
    None
    

    复杂度分析

    O(1)

    Reference

    1 Goodrich and etc., Data Structures and Algorithms in Python

    相关文章

      网友评论

          本文标题:链表Linked List, since 2022-05-04

          本文链接:https://www.haomeiwen.com/subject/fcwwyrtx.html