本文介绍: 栈(stack),有些地方称为堆栈,是一种容器,可存入数据元素访问元素删除元素,它的特点在于只能允许在容器的一端(称为栈顶指标英语top)进行加入数据英语push)和输出数据英语pop)的运算没有位置概念,保证任何时候可以访问删除元素都是此前最后存入的那个元素确定了一种默认访问顺序。由于栈数据结构只允许在一端进行操作,因而按照后进先出(LIFO, Last In First Out)的原理运作。

【一】堆与栈

【 1 】简介

        栈(stack),有些地方称为堆栈,是一种容器,可存入数据元素访问元素、删除元素,它的特点在于只能允许在容器的一端(称为栈顶指标英语top)进行加入数据英语push)和输出数据(英语pop)的运算没有了位置概念,保证任何时候可以访问删除的元素都是此前最后存入的那个元素,确定了一种默认访问顺序

由于栈数据结构只允许在一端进行操作,因而按照后进先出(LIFO, Last In First Out)的原理运作。

1、栈区(stack)— 由编译器自动分配释放 ,存放函数参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

2、堆区heap) — 一般由程序员分配释放, 若程序员不释放,程序结束可能由OS回收注意它与数据结构中的堆是两回事,分配方式倒是类似于链表

3、全局区(静态区)(static)—,全局变量静态变量存储是放在一块的,初始化全局变量静态变量在一块区域, 未初始化全局变量和未初始化静态变量相邻的另一块区域。 – 程序结束后有系统释放 。。

4、文字常量区—常量字符串就是放在这里的。 程序结束后由系统释放。

5、程序代码区—存放函数体的二进制代码

【 2 】堆与栈的区别

        堆与栈实际上是操作系统进程占用内存空间的两种管理方式,主要有如下几种区别
(1)管理方式不同。栈由操作系统自动分配释放,无需我们手动控制;堆的申请和释放工作程序员控制,容易产生内存泄漏

(2)空间大小不同。每个进程拥有的栈大小要远远小于堆大小。理论上,进程可申请的堆大小虚拟内存大小进程栈的大小 64bits 的 Windows 默认 1MB,64bits 的 Linux 默认 10MB;

(3)生长方向不同。堆的生长方向向上内存地址由低到高;栈的生长方向向下,内存地址由高到低。

(4)分配方式不同。堆都是动态分配的,没有静态分配的堆。栈有 2 种分配方式静态分配动态分配静态分配是由操作系统完成的,比如局部变量的分配。动态分配由alloca()函数分配,但是栈的动态分配和堆是不同的,它的动态分配是由操作系统进行释放,无需我们手工实现

(5)分配效率不同。栈由操作系统自动分配,会在硬件层级对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是由C/C++提供的库函数运算符完成申请与管理实现机制较为复杂,频繁的内存申请容易产生内存碎片。显然,堆的效率比栈要低得多。

(6)存放内容不同。栈存放的内容函数返回地址相关参数局部变量寄存器内容等。当主函数调用另外一个函数的时候,要对当前函数执行断点进行保存需要使用栈来实现,首先入栈的是主函数下一条语句地址,即扩展指针寄存器内容(EIP),然后当前栈帧的底部地址,即扩展基址指针寄存器内容(EBP),再然后是被调函数的实参等,一般情况下是按照从右向左的顺序入栈,之后是被调函数的局部变量,注意静态变量是存放在数据段或者BSS段,是不入栈的。出栈顺序正好相反,最终栈顶指向主函数下一条语句的地址,主程序又从该地址开始执行。堆,一般情况堆顶使用一个字节空间来存放堆的大小,而堆中具体存放内容是由程序员填充的。

从以上可以看到,堆和栈相比,由于大量malloc()/free()或new/delete使用,容易造成大量的内存碎片,并且可能引发用户态和核心态的切换效率较低。栈相比于堆,在程序中应用较为广泛,最常见的是函数的调用过程由栈来实现,函数返回地址、EBP、实参和局部变量采用栈的方式存放。虽然栈有众多的好处,但是由于和堆相比不是那么灵活,有时候分配大量的内存空间,主要还是用堆。

无论是堆还是栈,在内存使用时都要防止非法越界,越界导致的非法内存访问可能会摧毁程序的堆、栈数据,轻则导致程序运行处于不确定状态获取不到预期结果,重则导致程序异常崩溃,这些都是我们编程时与内存打交道时应该注意的问题

【 二 】什么是堆和栈,它们在哪儿?

        总的来说,栈和堆是计算机内存中两种重要的数据结构,它们分别用于不同的目的和场景。栈主要用于存储函数调用信息,而堆主要用于动态分配内存以存储复杂数据结构。在编程中,了解栈和堆的特点对于有效管理内存和理解程序的执行过程非常重要。

【 三 】栈结构实现

使用

        可以顺序表实现,也可以用链表实现。

栈的操作

  1. Stack() 创建一个新的空栈
  2. push(item添加一个新的元素item栈顶
  3. pop() 弹出栈顶元素
  4. peek() 返回栈顶元素
  5. is_empty() 判断是否为空
  6. size() 返回栈的元素个数
1 class Stack(object):
 2     """栈"""
 3     def __init__(self):
 4          self.items = []
 5 
 6     def is_empty(self):
 7         """判断是否为空"""
 8         return self.items == []
 9 
10     def push(self, item):
11         """加入元素"""
12         self.items.append(item)
13 
14     def pop(self):
15         """弹出元素"""
16         return self.items.pop()
17 
18     def peek(self):
19         """返回栈顶元素"""
20         return self.items[len(self.items)-1]
21 
22     def size(self):
23         """返回栈的大小"""
24         return len(self.items)
25 if __name__ == "__main__":
26     stack = Stack()
27     stack.push("hello")
28     stack.push("world")
29     stack.push("itcast")
30     print stack.size()
31     print stack.peek()
32     print stack.pop()
33     print stack.pop()
34     print stack.pop()

利用python列表方法实现数据结构堆栈的“后进先出”的性质

列表方法使得列表可以很方便的作为一个堆栈来使用,堆栈作为特定的数据结构,最先进入的元素最后一个被释放(后进先出)。

 用 append() 方法可以把一个元素添加到堆栈顶。用不指定索引的 pop() 方法可以把一个元素从堆栈顶释放出来。例如

>>> stack = [1, 2, 3]
>>> stack.append(4)
>>> stack.append(5)
>>> stack
[1, 2, 3, 4, 5]
>>> stack.pop()
5
>>> stack
[1, 2, 3, 4]
>>> stack.pop()
4
>>> stack.pop()
3
>>> stack
[1, 2]

【 四 】堆结构实现

使用

        在 Python 中,可以使用 heapq 模块来实现堆结构。heapq 提供了一些函数和工具,可以方便地进行堆操作

以下是使用 heapq 模块实现最小堆示例代码:

import heapq

class MinHeap:
    def __init__(self):
        self.heap = []

    def insert(self, item):
        heapq.heappush(self.heap, item)

    def extract_min(self):
        if self.is_empty():
            return None
        return heapq.heappop(self.heap)

    def is_empty(self):
        return len(self.heap) == 0

    def get_min(self):
        if self.is_empty():
            return None
        return self.heap[0]

这个示例中,我们定义了一个 MinHeap 类,并使用 heapq 模块提供的函数来实现堆操作:

  1. __init__(): 初始化一个空堆。
  2. insert(item): 向堆中插入元素。
  3. extract_min(): 弹出并返回堆中的最小元素。
  4. is_empty(): 判断是否为空
  5. get_min(): 返回堆中的最小元素,但不弹出。

可以使用以下代码测试上述实现的最小堆

h = MinHeap()
print(h.is_empty())  # True

h.insert(5)
h.insert(3)
h.insert(8)
h.insert(2)
print(h.extract_min())  # 2

print(h.is_empty())  # False
print(h.extract_min())  # 3
print(h.extract_min())  # 5
print(h.extract_min())  # 8
print(h.is_empty())  # True

  heapq 模块内部使用了优化的堆操作算法,可以高效地进行堆操作。你可以根据需要在代码中添加其他操作,比如获取堆顶元素或者删除指定元素,以满足具体的需求

原文地址:https://blog.csdn.net/m0_58310590/article/details/134784012

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_45492.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注