python利用数组和链表实现栈和队列

引言

栈和队列是在程序设计中被广泛使用的两种重要的线性数据结构,都是在一个特定范围的存储单元中存储的数据。和线性表相比,它们多了很多的约束与限定,关于栈,它就像是一个底边封闭开口狭小的桶,先存进去的东西只能最后取出来,所以性质为LIFO(Last In First Out),即先进后出。而队列,就是一根引流的水管,进去的水往往最先流出来。所以性质为FIFO(First In First Out),即先进先出。我们可以看下图:(图片链接)

在这里插入图片描述

如何实现栈

栈作为一个先进后出的数据结构,具有压栈、弹栈、取栈顶元素、加入元素、判断为空以及获取栈中元素的方法。而为了实现这些功能,我们可以通过数组和链表来完成。

用数组实现栈

在这里插入图片描述

我们可以用Visio画出一个大致的图形,然后代码如下:

class MyStack(object):
    """模拟栈"""

    def __init__(self):
        self.items = []

    def is_empty(self):
        """判断是否为空"""
        return self.items == []

    def size(self):
        """返回栈的大小"""
        return len(self.items)

    def push(self, item):
        """压栈(加入元素)"""
        self.items.append(item)


    def pop(self):
        """弹栈(弹出元素)"""
        if len(self.items)>0:
            return self.items.pop()
        else:
            print("栈已经为空")
            return None

    def top(self):
        """返回栈顶元素"""
        if not self.is_empty():
            return self.items[len(self.items) - 1]
        else:
            return None

然后我们可以进行实验:

s = MyStack()
s.push(4)
print("栈顶元素为:"+str(s.top()))
print("栈大小为:"+str(s.size()))
s.pop()
print("弹栈成功")
s.pop()
"""
栈顶元素为:4
栈大小为:1
弹栈成功
栈已经为空
"""

用链表实现栈

在这里插入图片描述

如图,压栈操作就是将新元素放到链表的首部,见第二个数据域的(1)、(2)操作,而弹栈只需要删除链表的第一个元素就可以了,具体操作见(3)。然后我们可以写出代码:

class LNode(object):
    def __init__(self,x):
        self.data = x
        self.next = None

class MyStack(object):
    def __init__(self):
        #pHead = LNode
        self.data = None
        self.next = None

    def is_empty(self):
        """判断是否为空"""
        if self.next == None:
            return True
        return False

    def size(self):
        """返回栈的大小"""
        size=0
        p = self.next
        while p != None:
        # while p is not None:
            p = p.next
            size += 1
        return size

    def push(self, element):
        """压栈(加入元素)"""
        p = LNode(element)
        p.data = element
        p.next = self.next
        self.next = p

    def pop(self):
        """弹栈(弹出元素)"""
        tmp = self.next
        if tmp != None:
            self.next = tmp.next
        print("栈已经为空")
        return None

    def top(self):
        """返回栈顶元素"""
        if self.next != None:
            return self.next.data
        print("栈已经为空")
        return None

然后我们可以进行实验:

s = MyStack()
s.push(1)
print("栈顶元素为:"+str(s.top()))
print("栈大小为:"+str(s.size()))
s.pop()
print("弹栈成功")
s.pop()
"""
栈顶元素为:1
栈大小为:1
弹栈成功
栈已经为空
"""

两种方法的对比

  1. 采用数组实现栈的优点:一个元素值占用一个存储空间;它的缺点为:如果初始化申请的存储空间太大,会造成空间的浪费,如果申请的存储空间太小,后期会经常需要扩充存储空间,扩充存储空间是个费时的操作,这样会造成性能的下降。

  2. 采用链表实现栈的优点是:使用灵活方便,只有在需要的时候才会申请空间,它的缺点为:除了要存储元素外,还需要额外的存储空间存储指针信息。


如何实现队列

队列作为一个先进先出的数据结构,具有入队列、出队列、查看首元素以及大小的方法。而为了实现这些功能,我们同样可以通过数组和链表来完成。

用数组实现队列

在这里插入图片描述
和上面一样,我们可以用Visio总结一下思路,然后代码如下:

class MyQueue(object):
    """队列"""
    def __init__(self):
        self.items = []
        self.front = 0  # 队列头
        self.rear = 0   # 队列尾

    def is_empty(self):
        """判断队列是否为空"""
        return self.items == self.rear

    def enQueue(self, item):
        """进队列,从队尾加入"""
        self.items.append(item)
        self.rear += 1
        # self.items.insert(0,item)     # 从对头进

    def deQueue(self):
        """出队列,从队头出"""
        if self.rear > self.front:
            self.front += 1
        else:
            print("队列已经为空")
        # return self.items.pop()   # 从对尾出

    def getFront(self):
        if self.is_empty():
            return None
        return self.items[self.front]

    def getBack(self):
        if self.is_empty():
            return None
        return self.items[self.rear-1]

    def size(self):
        """返回大小"""
        return self.rear - self.front
        # return len(self.items)	# 看大小

然后我们可以试验:

queue = MyQueue()
queue.enQueue(1)
queue.enQueue(2)

print("队列头元素为:"+str(queue.getFront()))
print("队列尾元素为:"+str(queue.getBack()))
print("队列的大小为:"+str(queue.size()))

queue.deQueue()
# queue.deQueue()
print("队列头元素为:"+str(queue.getFront()))
print("队列尾元素为:"+str(queue.getBack()))
print("队列的大小为:"+str(queue.size()))
"""
队列头元素为:1
队列尾元素为:2
队列的大小为:2
队列头元素为:2
队列尾元素为:2
队列的大小为:1
"""

用链表实现队列

在这里插入图片描述

class LNode(object):
    def __init__(self,x):
        self.data = x
        self.next = None

class MyQueue(object):
    def __init__(self):
        """分配头结点"""
        self.pHead = None
        self.pEnd = None

    def is_empty(self):
        """判断是否为空"""
        if self.pHead == None:
            return True
        return False

    def size(self):
        """获取队列的大小"""
        size=0
        p = self.pHead
        while p != None:
        # while p is not None:
            p = p.next
            size += 1
        return size

    def enQueue(self, element):
        """入队列,从队尾加"""
        p = LNode(element)
        p.data = element
        p.next = None
        if self.pHead == None:
            self.pHead = self.pEnd=p
        else:
            self.pEnd.next = p
            self.pEnd = p

    def deQueue(self):
        """出队列,删除首元素"""
        if self.pHead == None:
            print("出队列失败,队列已经为空")
        self.pHead = self.pHead.next
        if self.pHead == None:
            self.pEnd = None

    def getFront(self):
        """返回队列首元素"""
        if self.pHead == None:
            print("获取队列首元素失败,队列已经为空")
            return None
        return self.pHead.data

    def getBack(self):
    	"""返回队列尾元素"""
        if self.pEnd == None:
            print("获取队列尾元素失败,队列已经为空")
            return None
        return self.pEnd.data

然后我们同样拿上一份数据进行试验:

queue = MyQueue()
queue.enQueue(1)
queue.enQueue(2)

print("队列头元素为:"+str(queue.getFront()))
print("队列尾元素为:"+str(queue.getBack()))
print("队列的大小为:"+str(queue.size()))

queue.deQueue()
print("队列头元素为:"+str(queue.getFront()))
print("队列尾元素为:"+str(queue.getBack()))
print("队列的大小为:"+str(queue.size()))
"""
队列头元素为:1
队列尾元素为:2
队列的大小为:2
队列头元素为:2
队列尾元素为:2
队列的大小为:1
"""

两种方法的对比

和栈中的优缺点类似,但与栈不同的是,对于队列,用链表的方式比数组更好,因为指针空间在这里的发挥空间更大。

总结

大致总结了一下栈和列表的基础,如果要深入的话还远远不止这些,在书中《python程序员算法面试宝典》里还提及了用循环链表的方式来定义队列,这个我还没有时间实现,本篇博文的代码思路引用也出自这本书,另外就是错误稍微有点多,我在这里也一一修改并成功执行了,日后可能还会总结一下链表,毕竟现在开始刷剑指offer了,概念一定要熟悉。

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

submarineas

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值