栈
一、栈
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())