栈的ADT实现——有空间限制的栈

本文介绍了如何在有限空间内实现栈数据结构,如LeakyStack,它通过丢弃最久远的元素来保证新元素的入栈。同时,文章还探讨了使用循环队列优化,以实现时间复杂度为O(1)的操作,降低了空间消耗。
摘要由CSDN通过智能技术生成

1、研究有空间限制的栈的原因

当我们使用很多软件时都有类似“undo”功能,比如Web浏览器的回退功能、文本编辑器的撤销编辑功能。这些功能都可以使用Stack实现,但是在现实中浏览器的回退功能也好,编辑器的撤销功能也好,都有一定的数量限制。因此我们需要的不是一个普通的Stack数据结构,而是一个空间有限制的Stack,虽然空间有限,但这样的Stack在入栈时从不会溢出,因为它会采用将最久远的记录丢掉的方式让新元素入栈,也就是说总是按照规定的数量要求保持最近的历史操作。比如栈的空间是5,当a,b,c,d,e 入栈之后,如果继续让元素f入栈,那么栈中的元素将是b,c,d,e,f。

2、实现

代码

在这里插入图片描述

class LeakyStack:
    def __init__(self, capacity):
        self.stack = [None] * capacity
        self.top = -1#初始化指针为-1,代表栈为空
        self.capacity = capacity
    def push(self, item):
        if self.is_full():
            self.pop_oldest()#如果栈满将最久远的元素pop,同时剩余的元素向下移动
        self.stack[self.top + 1] = item#将新元素压入栈
        self.top += 1#指针指向栈顶
    def pop(self):
        if self.is_empty():#栈空不能弹栈
            raise IndexError("pop from an empty LeakyStack")
        item = self.stack[self.top]#取当前指针指向的元素赋值给item
        self.stack[self.top] = None#把栈顶元素弹出
        self.top -= 1#指针下移一位
        return item#返回item
    def peek(self):
        if self.is_empty():#只获取栈顶元素而不弹栈
            raise IndexError("peek from an empty LeakyStack")
        return self.stack[self.top]
    def is_empty(self):
        return self.top == -1#当指针指向-1栈空
    def is_full(self):
        return self.top == self.capacity - 1#当top指针指向capacity-1使栈满
    def pop_oldest(self):#时间复杂度为O(n)
        self.stack[0] = None#把栈低元素清空
        for i in range(1, self.top + 1):#将栈中元素向下移动
            self.stack[i - 1] = self.stack[i]
        self.stack[self.top] = None
        self.top -= 1#top指针下移
    #双下划线方法/魔术方法:python能够识别并自动调用这个方法
    def __repr__(self):#显示栈中所有元素,数组切片左闭右开
        return str(self.stack[:self.top + 1])
# 测试
if __name__=='__main__':
    leakystack=LeakyStack(5)
    leakystack.push(0)
    leakystack.push(1)
    leakystack.push(2)
    leakystack.push(3)
    leakystack.push(4)
    print(leakystack)
    print(leakystack.__repr__())
    leakystack.push(5)
    print(leakystack)
    leakystack.pop_oldest()
    print(leakystack)
    leakystack.push(6)
    print(leakystack)
    print(leakystack.is_full())
    print(leakystack.peek())

测试结果

在这里插入图片描述

3、改进(在不以空间消耗增加为代价的前提下实现时间复杂度控制为O(1)):

要求该数据结构的每一个操作的时间复杂度在最坏情形下都必须满足O(1)。

(1)方法——循环队列

用循环队列这样一个逻辑结构,用取余法实现循环而不移动所有的元素

(2)图示

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/ed282117b5014c8e88654e6151b836cf.png
在这里插入图片描述

在这里插入图片描述

(3)代码实现、详解、时间复杂度分析

*要实现方法有:

压栈push
弹栈pop
显示栈顶元素peek
判空is_empty
判满is_full
__repr__显示栈中所有元素(方便验证我们之前的方法实现是否正确)

*初始化四个值

1 容量
2 数组
3 头指针
4 状态变量(判空、判满)
在这里插入图片描述

*各个方法详解

push

在这里插入图片描述

pop

在这里插入图片描述

peek

在这里插入图片描述

is_empty、is_full

在这里插入图片描述

(4)完整代码及测试示例

代码
#用循环数组达到时间复杂度降为O(1)的效果(不消耗额外空间)
class CircularStack:
    def __init__(self, capacity):
        self.capacity = capacity
        self.stack = [None] * capacity
        #生成数组:[None, None, None, None, None]
        #而[]*5生成:[]
        self.top = 0  # 初始时栈顶指针为0
        self.size=0#size变量跟踪栈状态

    def push(self, item):
        if self.is_full():#栈满丢掉最久的数据
            #用取余法实现循环,并用新元素覆盖(栈满后无需更新size值)
            self.top=(self.top+1)%self.capacity
            self.stack[self.top] = item
        elif self.is_empty():#栈为空直接压入元素,更新size值
            self.stack[self.top] = item
            self.size+=1
        else:#栈不为空且未满,指针+1,入栈元素,更新size
            self.top += 1
            self.stack[self.top] = item
            self.size+=1

    def pop(self):#弹栈同时显示弹栈元素
        item = self.stack[self.top]#显示元素
        self.stack[self.top] = None  # 清除元素,避免内存泄漏
        self.size -= 1#更新size
        self.top-=1#更新top
        return item

    def peek(self):
        return self.stack[self.top]

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

    def is_full(self):
        return self.size==self.capacity

    def __repr__(self):  # 显示栈中所有元素,数组切片左闭右开
        return str(self.stack[:self.capacity])

# 使用示例
if __name__=='__main__':
    mystack = CircularStack(5)  # 创建一个容量为5的循环栈
    mystack.push(0)
    mystack.push(1)
    mystack.push(2)
    mystack.push(3)
    mystack.push(4)
    print(mystack.is_full())
    mystack.push(5)
    print(mystack)
    print(mystack.pop())
    print(mystack)
    print(mystack.size)
    print(mystack.top)
    mystack.push(6)
    print(mystack)
测试示例:

在这里插入图片描述

测试结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值