python数据结构之栈的实现

前言:本篇只代表本人对于栈的理解,如有错误,烦请大家指出!

 栈是一种简单的线性数据结构,用来存放数据,其严格遵守了先进后出的原则,即first in last out,有关于栈的操作也十分简单,无非就是增删等。

这类简单的数据结构我们可以使用列表来实现相关的操作。

由于其先进后出的特性,不难想到利用列表相关的操作就可以解决掉一些问题,如append方法实现增加元素,pop方法实现删除元素,len方法实现统计栈内元素的个数,接下来我就用类来实现自己的一个栈以及相关的拓展功能。

class Stack:
    def __init__(self,size = 0):
        self.stack = []  # 创建栈,本质上是列表
        self.size = size  # 栈的大小,初始化为0

首先是利用私有方法init来初始化参数,在构建栈时,我们用列表去模拟并将栈内元素的个数初始化为0

一.增加元素功能

def push(self,element):  # element是待插入元素
        self.stack.append(element)
        self.size+=1

没什么需要过多注意的,element为待插入的元素,插入后需要将size更新。

二.删除元素功能

学到了数据结构这一部分,我们写代码就要相当谨慎,尤其是对删除需要相当敏感,我们在做删除操作时都需要考虑到,有没有可以删除的元素,如果栈内为空,那还怎么删除? 

因此我在这里设计了一个检查队内是否还有元素的查空功能。

def is_empty(self):
    # return len(self.stack) == 0
    return self.size == 0
    # 两种写法都可以

 有了这个函数,我们便可以将删除功能完善起来,分情况讨论即可。

def pop(self):
    if not self.is_empty:
        self.stack.pop(-1)
        self.size -= 1
        # 删除的写法还有很多种
        # del self.stack[-1]
    else:
        print("栈内没有元素可以删除!")
        raise IndexError

三.取栈顶元素功能

def get_top(self):
    if not self.is_empty:
        return self.stack[-1]
    else:
        raise IndexError

这些功能都十分简单,无需多说什么。

四.统计栈内元素个数功能

def count(self):
    return self.size

刷题时间 

 栈的内容十分简单,巧妙利用列表的功能即可,接下来我为了巩固一下栈的知识,给出几道十分经典的有关于栈的例题:

①括号匹配问题:

class Solution:
    def isValid(self, s: str) -> bool:
        stack = []
        if not s:
            return True  # 这是字符为空的情况
        for key in s:
            if (key == "[") or (key == "(") or (key == "{"):
                stack.append(key)
            else:
                if len(stack) == 0:  # 这是只有右括号
                    return False
                top = stack.pop(-1)
                if (key == "]" and top != "[") or (key == "}" and top != "{") or (key == ")" and top != "("):
                    return False  # 这是不匹配
        if len(stack) != 0:
            return False  # 这是还剩左括号在里面没匹配
        else:  
            return True  # 这是正确

这个问题没什么需要注意的,有几种特殊情况需要考虑,我已经标注在图上了。

②最小辅助栈问题

分析题目不难发现前四个功能都十分平常,利用基本的列表方法就可以实现,但是看到最后一个获取最小值且只能在常数时间内检索,这个问题就变得不一样了起来,因为纵观我们所有的方法(包括min函数和建堆,排序都做不到常数的时间复杂度),这时我们就需要考虑以空间换取时间,即再借助另外一个栈来存放最小值,这样便可以直接通过索引拿到最小值。

class MinStack:
    def __init__(self):
        self.temp=[]
        self.stack = []

    def push(self, val: int) -> None:
        self.stack.append(val)
        if not self.temp:
            self.temp.append(val)
        else:
            if val <= self.temp[-1]:
                self.temp.append(val)
        return None

    def pop(self) -> None:
        is_min = self.stack.pop(-1)
        if self.temp and is_min == self.temp[-1]:
            self.temp.pop(-1)
        return None

    def top(self) -> int:
        return self.stack[-1]

    def getMin(self) -> int:
        return self.temp[-1]

在初始化时构建两个栈,temp栈用来取最小值。(保证temp栈顶元素最小

在push功能中,若temp内没有元素,就将这个val追加进入temp,若temp内已经有元素,那便与其栈顶的元素比较,如果比栈顶的元素值还要小,就让新的元素为栈顶。

在pop功能中,如果删除的就是当前的最小值,那么在temp列表中,也需要将栈顶元素删除。

这样就保证的了temp的栈顶元素是最小的,且时间复杂度为O(1),但是空间复杂度就是O(N)。

 ③行星碰撞问题

这一题的关键在于边界的处理,首先我们必须搞清楚何时会碰撞何时肯定不会正负代表着右左,

只有前一个为右且自身为左时会碰撞,若前一个为左且自身为右,他们永远不会相碰撞

同时应该注意碰撞后,会有行星爆炸,爆炸后,我们需要重新判断前面的能否在有行星爆炸了之后,能否继续相碰,每一次的判断都需要注意边界,尤其是两个行星都爆炸了,需要考虑的情况较多,一方面是到顶了,一方面是向左越界了。

本题中continue的妙用值得思考,即爆炸后重新的判断,同时也带给我了一点启示,每一次的判断都需要注意边界的控制,若下标在增加我们需要注意是否会右边越界,若下标在减小我们需要注意是否会左边越界,因此我的建议是每一次有关于下标变化的判断都加上越界的判断,这样就万无一失了。

class Solution:
    def asteroidCollision(self, asteroids: List[int]) -> List[int]:
        i = len(asteroids)-1
        while i > 0:
            if i<=len(asteroids)-1 and asteroids[i-1]>0 and asteroids[i]<0:
                if abs(asteroids[i-1]) > abs(asteroids[i]):
                    asteroids.pop(i)
                    continue
                elif i<=len(asteroids)-1 and asteroids[i-1]+asteroids[i] == 0:
                    asteroids.pop(i)
                    asteroids.pop(i-1)
                    i = i-2
                    if i >= 0 and asteroids[i] > 0:
                        i += 1
                        continue
                else:
                    asteroids.pop(i-1)
                    i-=1
            elif i<=len(asteroids)-1 and asteroids[i-1]<0 and asteroids[i]>0:
                i-=1
            else:
                i-=1

        return asteroids

  • 15
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值