Python中的链表之单向链表实现栈和队列

< Data Structures andAlgorithms in Python > Michael T.Goodrich,Roberto Tamassia,Michael H.Goldwasser 学习笔记
Python中除了列表,还有链表这样的基础数据结构,之前我们都是介绍用列表实现栈、队列这样的数据结构的,接下来我们看一下用链表实现的栈和队列。

既然列表已经可以实现栈和队列了,那么链表又有什么存在的意义呢?当然是因为列表有一些明细的缺点:

  • 内存的分配:底层数组大小要比实际列表的大;
  • 摊销的边界:底层数组已满时,继续向列表中添加元素,由于要换底层数组并转移数据,这时的时间复杂度明显要比之前添加元素的要高。
  • 插入的代价:在尾部插入数据,时间复杂度摊销下来只要 O ( 1 ) O(1) ,但是在中间甚至在头部插入,后面的数据都需要后移来给新添加的数据腾出空间。(删除操作同理)

链表就很好的避免了以上列表的三个缺点,但是链表也有自己的缺点:无法通过索引来寻找链表中的元素。

单向链表

在这里插入图片描述
       单向链表的结构图如上图所示。在单项链表中实现插入删除元素时,唯一需要注意的是在单向链表中间或者尾部删除元素:当我们确定要删除的节点的时候,我们可以查询到当前节点下一个节点,却无法查询到上一个节点,要想知道上一个节点,则需要遍历整个链表,这明显不可取。

单向链表实现栈

       单向链表实现栈,规定栈的顶部使用链表的头部,因为只有在头部才可以有效的插入和删除。
       为了表示列表中的单个节点,定义一个嵌套类_Node类。具体实现如下代码:

class Empty(Exception):
    def __init__(self, m):
        super().__init__(self)
        self.message = m

    def __str__(self):
        return self.message


class LinkedStack:

    class _Node:
        __slots__ = '_element', '_next'

        def __init__(self, e, n):
            self._element = e
            self._next = n

    def __init__(self):
        self._head = None
        self._size = 0

    def __len__(self):
        return self._size

    def is_empty(self):
        return self._size == 0

    def top(self):
        if self.is_empty():
            raise Empty('Stack is empty.')
        return self._head._element

    def push(self, e):
        self._head = self._Node(e, self._head)
        self._size += 1

    def pop(self):
        if self.is_empty():
            raise Empty('Stack is empty.')

        data = self._head._element
        self._head = self._head._next
        self._size -= 1
        return data

       显然,用链表实现的栈无论出栈入栈,其时间复杂度都是 O ( 1 ) O(1) ,并不需要摊销计算。

单向链表实现队列

根据前面提到的单向链表的注意点,对于队列,只能是链表的头部出队列,链表的尾部入队列,代码如下:

class Empty(Exception):
    def __init__(self, m):
        super().__init__(self)
        self.message = m

    def __str__(self):
        return self.message


class LinkedQueue:

    class _Node:
        __slots__ = '_element', '_next'

        def __init__(self, e, n):
            self._element = e
            self._next = n

    def __init__(self):
        self._head = None
        self._tail = None
        self._size = 0

    def __len__(self):
        return self._size

    def is_empty(self):
        return self._size == 0

    def first(self):
        if self.is_empty():
            raise Empty('Queue is empty')
        return self._head._element

    def dequeue(self):
        if self.is_empty():
            raise Empty('Queue is empty')

        data = self._head._element
        self._head = self._head._next
        self._size -= 1
        if self.is_empty():
            self._tail = None
        return data

    def enqueue(self, e):
        new = self._Node(e, None)
        if self.is_empty():
            self._head = new
        else:
            self._tail._next = new
        self._tail = new
        self._size += 1

队列与栈实现不同的地方就是:队列需要多考虑一个尾部。性能方面,用链表实现的队列和栈类似,都是常数时间复杂度。

猜你喜欢

转载自blog.csdn.net/zhisuihen6347/article/details/84496891