python双向链表 du_Python中的链表之双向链表

< Data Structures andAlgorithms in Python > Michael T.Goodrich,Roberto Tamassia,Michael H.Goldwasser 学习笔记

双向链表的实现

和单向链表不同,双向链表添加了头节点和尾节点,这两个节点不存储元素。它们占了少许内存空间,但是极大地简化了操作逻辑。其实现示意图如下:

0adefce89b7618e997b71c97ff2aedaf.png

我们可以先定义一个实现的基本类,以便后续的拓展延伸,代码如下:

class Empty(Exception):

def __init__(self, m):

super().__init__(self)

self.message = m

def __str__(self):

return self.message

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._tailer = self._Node(None, None, None)

self._header._next = self._tailer

self._tailer._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

_insert_between()和_delete_node()是两个保护方法,由于里面涉及到保护的嵌套类,不可以被直接引用,主要是给子类继承和类对象使用。

双向链表实现双端队列

将上面的代码命名为DoubleLinkedBase放入Linked的文件夹,引入LinkedDeque.py文件继承_DoubleLinkedBase类,其具体代码如下:

from Linked.DoubleLinkedBase import Empty, _DoubleLinkedBase

class LinkedDeque(_DoubleLinkedBase):

def first(self):

if self.is_empty():

raise Empty('Deque is empty')

return self._header._next._element

def last(self):

if self.is_empty():

raise Empty('Deque is empty')

return self._tailer._prev._element

def insert_first(self, e):

self._insert_between(e, self._header, self._header._next)

def insert_last(self, e):

self._insert_between(e, self._tailer._prev, self._tailer)

def delete_first(self):

if self.is_empty():

raise Empty('Deque is empty')

return self._delete_node(self._header._next)

def delete_last(self):

if self.is_empty():

raise Empty('Deque is empty')

return self._delete_node(self._tailer._prev)

具有位置信息的双向链表

栈和队列是常见的数据类型,它们一般只能在数据结构的两端进行操作,现在我们定义一个更普遍的数据类型:不仅可以在两端进行操作,也可以实现内部的插入和删除。实现插入和删除操作需要知道元素的具体位置,就比如说索引能够很好的描述元素在列表中的位置,但是数字的索引不适合描述一个链表内部的位置。链表和列表不同:列表存储是在一块连续的内存上的,而且每次插入删除操作都会调整列表的索引,链表是分散存储的,如果使用索引,当插入或删除操作时,其索引就失效了。所以我们使用另一种方式实现链表的位置信息:在数据结构类中定义一个位置信息的嵌套类Position,其具体实现方式如下:

from Linked.DoubleLinkedBase import _DoubleLinkedBase

class PositionalList(_DoubleLinkedBase):

class Position:

def __init__(self, container, node):

self._container = container

self._node = node

def __eq__(self, other):

return type(self) is type(other) and other._node is self._node

def __ne__(self, other):

return not (self == other)

def element(self):

return self._node._element

def _validate(self, p):

if not isinstance(p, self.Position):

raise TypeError('p must be proper 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._tailer:

return None

else:

return self.Position(self, node)

def first(self):

return self._make_position(self._header._next)

def last(self):

return self._make_position(self._tailer._prev)

def before(self, p):

node = self._validate(p)

return self._make_position(node._prev)

def after(self, p):

node = self._validate(p)

return self._make_position(node._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._tailer._prev, self._tailer)

def add_before(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_value = original._element

original._element = e

return old_value

总结

总结一下使用列表和使用链表实现栈队列的优缺点:

列表可以使用整数索引,而链表只能使用我们上面讲到的嵌套类来表示,索引的查询效率明细地比链表要高;

添加删除操作中,不在底层数组的边界操作,其效率要比链表高的。因为在链表中添加元素需要考虑节点的实例化、节点的合适链接和整数的增量,但是链表支持任意位置的常数复杂度的插入操作;

在存储空间方面,由于列表底层数组都要比实际存储的要大,列表直觉上要比链表占更多的内存,其实不然,比如在单向链表中,单个节点不仅要存储自身元素,还要存储下个节点,那么一个长度为n nn的单向链表至少需要2 n 2n2n的空间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值