Python-数据结构与算法(七、链表栈以及与数组栈的性能比较)

保证一周更两篇吧,以此来督促自己好好的学习!代码的很多地方我都给予了详细的解释,帮助理解。好了,干就完了~加油!
声明:本python数据结构与算法是imooc上liuyubobobo老师java数据结构的python改写,并添加了一些自己的理解和新的东西,liuyubobobo老师真的是一位很棒的老师!超级喜欢他~
如有错误,还请小伙伴们不吝指出,一起学习~
No fears, No distractions.

一、链表栈

由于在链表头处的插入与删除操作的时间复杂度都是O(1)的,因此可以被用作栈来使用。具体实现也很简单。

二、链表栈的实现

# -*- coding: utf-8 -*-
# Author:           Annihilation7
# Data:             2018-09-28
# Python version:   3.6

import linkedlist   # LinkedList类写在这个py文件中了

class LinkedListStack:
    def __init__(self):
        self.stack = linkedlist.LinkedList()    # 初始化一个链表就好
        # 这时就不需要self._capacity了,因为并不需要扩容/缩容神马的

    def getSize(self):
        """
        获得栈内有效元素的个数
        :return: 有效元素的个数
        """
        return self.stack.getSize()     # 直接调用链表的getSize方法

    def isEmpty(self):
        """
        判断栈是否为空
        :return: bool值,空为True
        """
        return self.stack.isEmpty()     # 调用链表的isEmpty方法

    def push(self, elem):
        """
        入栈操作
        tip:在这里我们将链表的表头当做栈顶,因为此时栈顶的入栈与出栈操作的时间复杂度都是O(1)的
        时间复杂度:O(1)
        :param elem: 将要入栈的元素
        """
        return self.stack.addFirst(elem)    # 调用链表的addFirst方法

    def pop(self):
        """
        栈顶元素的出栈操作,同理,也在表头进行出栈操作
        时间复杂度:O(1)
        :return: 出栈的元素
        """
        return self.stack.removeFirst()     # 调用链表的removeFirst方法

    def peek(self):
        """
        看一眼栈顶元素是谁
        时间复杂度:O(1)
        :return: 栈顶的元素
        """
        return self.stack.getFirst()        # 调用链表的getFirst方法

    def printLinkListStack(self):
        """对链表栈进行打印操作"""
        print('Stack: Top--- ', end=' ')  # 左边为栈顶
        cur = self.stack._dummyhead.next
        while cur != None:
            cur.printNode()
            cur = cur.next
        print('---bottom')  # 右边为栈底
        print('Size: ', self.getSize())  # 有效元素数目

三、测试

import linkedlistStack		# 链表栈写在这个Py文件中
import numpy as np

np.random.seed(7)
a = linkedlistStack.LinkedListStack()
print(a.getSize())
print(a.isEmpty())
for i in range(15): # 入栈15次
    a.push(np.random.randint(10))
a.printLinkListStack()
for i in range(4):      # 出栈4次
    a.pop()  # 就不用pop函数的返回值了
a.printLinkListStack()
print(a.peek())

四、输出

0
True
Stack: Top---  4  6  7  8  9  8  7  9  7  7  3  3  6  9  4  ---bottom
Size:  15
Stack: Top---  9  8  7  9  7  7  3  3  6  9  4  ---bottom
Size:  11
9

五、与数组栈的性能比较

数组栈就是我们前面实现的那个栈哦,它是基于我们的Arr类实现的栈。

测试代码

from Stack.arrayStack import ArrayStack                 # 数组栈
from linklist.linkedlistStack import LinkedListStack    # 链表栈
from queue.testQueueAndLoopqueue import count_time      # 运行时间测试函数
import numpy as np

np.random.seed(7)
nums = 200000    # 入/出栈次数
arrayStack = ArrayStack()               # 数组栈对象
linkedlistStack = LinkedListStack()     # 链表栈对象

@count_time
def compute_arrayStack():
    global nums, arrayStack
    for i in range(nums):
        arrayStack.push(np.random.randint(10))
    for i in range(nums):
        arrayStack.pop()            # 两个操作都是O(1)的

@count_time
def compute_linkedlistStack():
    global nums, linkedlistStack
    for i in range(nums):
        linkedlistStack.push(np.random.randint(10))
    for i in range(nums):
        linkedlistStack.pop()

if __name__ == '__main__':
    print('总操作数:%d' % (nums))
    print('数组栈:', end=' ')
    compute_arrayStack()
    print('链表栈:', end=' ')
    compute_linkedlistStack()

输出结果

总操作数:200000
数组栈: 共用时: 1.717325 秒
链表栈: 共用时: 1.300426 秒
总操作数:10000000
数组栈: 共用时: 76.546684秒
链表栈: 共用时: 82.714655

可以看到总共测试两次,操作数分别为200000和10000000次,用时几乎相差无几。在操作数较少的情况下,数组栈需要不停的拓展存储空间、转移元素,这样消耗时间比较多。在操作数较大的情况下,链表栈需要不停的创建存储Node的内存空间,相对耗时(注意数组栈的扩容方式是乘以2哦),所以此时链表栈用时稍多。不过这些差别可以忽略不计啦,都是O(1)的时间复杂度。
当然这些在你的机器上进行测试可能与我的结果不一致,这是很正常的,因为测试结果与很多因素有关呢。

若有还可以改进、优化的地方,还请小伙伴们批评指正!

猜你喜欢

转载自blog.csdn.net/Annihilation7/article/details/82875556