堆和栈的区别以及栈的顺序存储和链式存储—Python数据结构(三)

一、栈

1. 定义

栈是限制在一端进行插入操作和删除操作的线性表(俗称堆栈),

允许进行操作的一端称为”栈顶“,另一固定端称为”栈底“,当栈中没有元素时称为”空栈“。

2. 特点

  • 栈只能在一端进行操作。

  • 栈模型具有先进后出,或者叫后进先出的规律。

在这里插入图片描述

3. 对象和引用

Python中有对象和引用的概念,他们是两个重要的概念,并且它们之间存在着密切的关系。例如
a = 456
b=789
c=knm


变量a是对对象456的引用
变量b是对对象789的引用
变量c是对对象knm的引用
在这里插入图片描述
简单来说,
对象是Python中存储数据和执行操作的基本单位。可以将对象看作是内存中分配的一块区域,包含了数据值以及与该对象相关的操作和方法。在Python中,几乎所有的数据都是以对象的形式存在,包括整数、浮点数、字符串、列表、字典等。

每个对象都有一个唯一的标识符(ID),可以通过id()函数来获取。这个标识符在对象的生命周期内是不变的,它类似于对象在内存中的地址。两个对象的标识符相同,则表明它们指向同一个对象。

引用是指向对象的指针或者名称,用于访问和操作对象。在Python中,我们可以使用变量来创建引用。当我们将一个对象赋值给一个变量时,实际上是将该对象的引用赋给了这个变量。多个变量可以引用同一个对象,即多个引用可以指向同一个对象。

4. 堆和栈的区别与联系

堆的定义:

堆是一种动态分配内存的方式,用于存储对象和数据结构。堆中的内存空间是动态分配的,它可以在程序运行时申请和释放。堆中存储的对象通常由引用变量来访问,而引用本身存储在栈中。在堆中申请的内存需要手动释放,否则可能导致内存泄露。
简单说

栈是用来存储局部变量和函数调用信息的,即存放的是对象的地址,而不是对象本体
堆是用来存储动态分配的对象的,即存放的是具体的对象,在堆中,Python为其分配内存空间,此地址就是对象在内存中的地址。

在这里插入图片描述

堆和栈的区别
  • 数据结构:
    堆:堆是一种动态分配的内存结构,存储的是对象和数据结构。在堆中存储的对象可以通过引用来访问和操作。
    栈:栈是一种后进先出(LIFO)的数据结构。它用于存储局部变量、函数调用信息和临时数据等。栈的大小是固定的,由操作系统预先定义。
  • 分配方式:
    堆:堆内存的分配和释放是动态的,通过特定的内存管理机制(如垃圾回收器)进行管理。堆内存的分配通常使用new关键字或者其他动态内存分配函数。
    栈:栈内存的分配和释放是自动的,由编译器和运行时环境负责管理。每当有一个函数被调用时,该函数的局部变量会被分配到栈上,函数执行完毕后会自动释放。
  • 大小限制:
    堆:堆的大小是相对较大的,并且受到可用内存的限制。在堆中可以动态地分配和释放内存空间。
    栈:栈的大小是固定的,在程序运行前就已经确定。通常由操作系统设置,默认情况下较小。
  • 生命周期:
    堆:在堆上创建的对象可以长时间存在,直到被垃圾回收器回收。因此,堆上的对象的生命周期相对较长。
    栈:栈上的变量的生命周期较短。当一个函数调用结束后,其局部变量会被自动销毁。
  • 访问方式:
    堆:堆中的对象通过引用来访问和操作。多个引用可以指向同一个堆上的对象。
    栈:栈中的对象通过栈指针(ESP)来访问。栈指针会随着函数的调用和返回而不断变化。

总结起来,堆和栈是两种不同的内存结构。堆用于存储对象和数据结构,具有动态分配和释放内存的能力;而栈用于存储局部变量、函数调用信息等,具有固定大小和自动管理内存的特性。了解堆和栈的区别有助于编写高效、安全的代码,并且更好地理解Python中的内存管理机制。

5. 栈的代码实现

栈的操作有入栈(压栈),出栈(弹栈),判断栈的空满等操作。

  • 顺序存储代码实现sstack.py

  • 链式存储代码实现lstack.py

栈的顺序存储模型

"""
栈模型的顺序存储
思考总结:
1. 列表即顺序存储,但功能多,不符合栈的模型特征
2. 利用列表,将其封装,提供接口方法
"""


# 自定义异常
class StackError(Exception):
    pass


# 顺序栈类
class SStack:
    def __init__(self):
        self._elems = []

    # 判断列表为空
    def is_empty(self):
        return self._elems == []

    # 入栈
    def push(self, val):
        self._elems.append(val)

    # 出栈
    def pop(self):
        if self.is_empty():
            raise StackError("Stack is empty")
        return self._elems.pop()

    # 查看栈顶元素
    def top(self):
        if self.is_empty():
            raise StackError("Stack is empty")
        return self._elems[-1]


if __name__ == "__main__":
    s1 = SStack()  # 初始化
    s1.push(10)
    s1.push(30)
    s1.push(50)
    while not s1.is_empty():
        print(s1.pop())

'''
面试题:已知,一个堆栈的入栈顺序是1,2,3,下列不可能出现的出栈的顺序的是:
3,1,2


'''

栈的链式存储模型
"""
栈的链式栈
思路分析:
1. 源于链表结构
2. 封装栈的操作方法 | 入栈出栈,栈空,栈顶元素。
3. 链表的开头作为栈顶?(不用每次遍历)
"""


# 自定义异常
class StackError(Exception):
    pass


# 创建节点类
class Node:
    def __init__(self, val, next=None):
        self.val = val
        self.next = next


# 链式栈操作
class LStack:
    def __init__(self):
        # 标记栈的栈顶位置
        self._top = None

    def is_empty(self):
        return self._top is None

    def push(self, val):
        self._top = Node(val, self._top)

    def pop(self):
        if self._top is None:
            raise StackError("Stack is empty")
        value = self._top.val
        self._top = self._top.next
        return value


if __name__ == "__main__":
    ls = LStack()
    ls.push(20)
    ls.push(30)
    ls.push(10)
    print(ls.pop())


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值