正在载入交互式动画窗口请稍等
栈-顺序表 可视化交互式动画版
什么是堆栈?
堆栈是一种线性数据结构,其中新元素的插入和现有元素的删除发生在表示为堆栈顶部的同一端。
为了实现栈,需要维护一个 指向栈顶的指针 ,栈顶是最后插入的元素,因为 我们只能访问栈顶的元素。
LIFO(后进先出):
该策略规定最后插入的元素将首先出现。 您可以将一堆相互叠放的盘子作为现实生活中的示例。 我们最后放置的盘子位于顶部,并且由于我们移除了顶部的盘子,所以我们可以说最后放置的盘子最先出现。
堆栈的基本操作
为了在堆栈中进行操作,向我们提供了某些操作。
- push() 将一个元素插入栈中
- pop() 从堆栈中删除一个元素
- top() 返回栈顶元素。
- 如果堆栈为空, isEmpty()返回 true,否则返回 false。
- size() 返回堆栈的大小。
推:
将一个项目添加到堆栈中。 如果堆栈已满,则称为 溢出情况。
推送算法:
开始 如果堆栈已满 返回 万一 别的 增量顶部 stack[top] 赋值 结束其他 结束程序
流行音乐:
从堆栈中删除一个项目。 项目的弹出顺序与推送顺序相反。 如果堆栈为空,则称为 下溢 条件。
流行算法:
开始 如果堆栈为空 返回 万一 别的 存储堆栈的值[top] 减少顶部 返回值 结束其他 结束程序
顶部:
返回栈顶元素。
顶部算法:
开始 返回堆栈[顶部] 结束程序
是空的:
如果堆栈为空则返回 true,否则返回 false。
isEmpty 的算法 :
开始 如果顶部 < 1 返回真 别的 返回错误 结束程序
实际理解堆栈:
现实生活中有很多堆栈的例子。 考虑一个简单的例子,在食堂里,盘子一个一个地叠在一起。 位于顶部的盘子是第一个被移除的盘子,即放置在最底部位置的盘子在堆叠中保留最长的时间。 因此,可以简单地看出遵循 LIFO/FILO 顺序。
复杂度分析:
- 时间复杂度
运营 | 复杂 |
---|---|
推() | 复杂度(1) |
流行音乐() | 复杂度(1) |
是空的() | 复杂度(1) |
尺寸() | 复杂度(1) |
堆栈类型:
- 固定大小堆栈 :顾名思义,固定大小堆栈具有固定的大小,不能动态增长或收缩。 如果堆栈已满并尝试向其中添加元素,则会发生溢出错误。 如果堆栈为空并且尝试从中删除元素,则会发生下溢错误。
- 动态大小堆栈 :动态大小堆栈可以动态增长或收缩。 当堆栈已满时,它会自动增加其大小以容纳新元素,而当堆栈为空时,它会减少其大小。 这种类型的堆栈是使用链表实现的,因为它允许轻松调整堆栈的大小。
除了这两种主要类型之外,堆栈还有其他几种变体,包括:
- 中缀到后缀堆栈 :这种类型的堆栈用于将中缀表达式转换为后缀表达式。
- 表达式计算堆栈 :这种类型的堆栈用于计算后缀表达式。
- 递归堆栈 :这种类型的堆栈用于跟踪计算机程序中的函数调用,并在函数返回时将控制权返回到正确的函数。
- 内存管理堆栈 :这种类型的堆栈用于存储计算机程序中程序计数器的值和寄存器的值,允许程序在函数返回时返回到先前的状态。
- 平衡括号堆栈 :这种类型的堆栈用于检查表达式中括号的平衡。
- 撤消重做堆栈 :这种类型的堆栈用于计算机程序中,允许用户撤消和重做操作。
栈的应用:
- 中缀到后缀 /前缀的转换
- 许多地方都有重做/撤消功能,例如编辑器、Photoshop。
- 网络浏览器中的前进和后退功能
- 用于许多算法,如 汉诺塔、 树遍历 、 股票跨度问题 和 直方图问题 。
- 回溯是算法设计技术之一。 回溯的一些例子包括骑士之旅问题、N-皇后问题、在迷宫中寻找出路以及所有这些问题中的类似国际象棋或西洋跳棋的问题,如果这种方式效率不高,我们会回到之前的问题状态并进入另一条道路。 为了从当前状态返回,我们需要存储以前的状态,为此我们需要一个堆栈。
- 在拓扑排序 和 强连通分量 等图算法中
- 在内存管理中,任何现代计算机都使用堆栈作为运行目的的主要管理。 计算机系统中运行的每个程序都有自己的内存分配
- 字符串反转也是栈的另一个应用。 这里每个字符都被一一插入到堆栈中。 因此,字符串的第一个字符位于堆栈底部,字符串的最后一个元素位于堆栈顶部。 在堆栈上执行弹出操作后,我们得到一个相反顺序的字符串。
- 堆栈还有助于在计算机中实现函数调用。 最后调用的函数总是最先完成。
- 堆栈还用于在文本编辑器中实现撤消/重做操作。
堆栈的实现:
堆栈可以使用数组或链表来实现。 在基于数组的实现中,推送操作是通过递增顶部元素的索引并将新元素存储在该索引处来实现的。 弹出操作是通过递减顶部元素的索引并返回存储在该索引处的值来实现的。 在基于链表的实现中,推送操作是通过使用新元素创建新节点并将当前顶节点的下一个指针设置为新节点来实现的。 出栈操作是通过将当前顶节点的next指针设置为下一个节点并返回当前顶节点的值来实现的。
堆栈在计算机科学中通常用于各种应用,包括表达式求值、函数调用和内存管理。 在表达式的计算中,堆栈可用于在处理操作数和运算符时存储它们。 在函数调用中,堆栈可用于跟踪函数调用的顺序,并在函数返回时将控制权返回到正确的函数。 在内存管理中,堆栈可用于存储计算机程序中的程序计数器的值和寄存器的值,从而允许程序在函数返回时返回到先前的状态。
总之,堆栈是一种按照 LIFO 原理运行的线性数据结构,可以使用数组或链表来实现。 可以在堆栈上执行的基本操作包括入栈、出栈和查看,并且堆栈在计算机科学中常用于各种应用,包括表达式求值、函数调用和内存管理。有两种方法实现一个堆栈 –
- 使用数组
- 使用链表
使用数组实现堆栈:
- C++
- C
- Java
- Python3
- C#
- JavaScript
C++
/* C++ program to implement basic stack operations */ #include <bits/stdc++.h> using namespace std; #define MAX 1000 class Stack { int
top; public : int
a[MAX]; // Maximum size of Stack
Stack() { top = -1; } bool push( int x); int
pop(); int
peek(); bool isEmpty(); }; bool Stack::push( int x) { if
(top >= (MAX - 1)) { cout << "Stack Overflow" ; return false ; } else { a[++top] = x; cout << x << " pushed into stack\n" ; return true ; } } int Stack::pop() { if
(top < 0) { cout << "Stack Underflow" ; return 0; } else { int x = a[top--]; return x; } } int Stack::peek() { if
(top < 0) { cout << "Stack is Empty" ; return 0; } else { int x = a[top]; return x; } } bool Stack::isEmpty() { return (top < 0); } // Driver program to test above functions int main() { class Stack s; s.push(10); s.push(20); s.push(30); cout << s.pop() << " Popped from stack\n" ; //print top element of stack after popping cout << "Top element is : " << s.peek() << endl; //print all elements in stack : cout << "Elements present in stack : " ; while (!s.isEmpty()) { // print top element in stack cout << s.peek() << " " ; // remove top element in stack s.pop(); } return 0; } |
C
Java
Python3
C#
Javascript
10 入栈 20 入栈 30 压入堆栈 30 从堆栈中弹出 顶部元素是:20 堆栈中存在的元素:20 10
数组实现的优点:
- 易于实施。
- 由于不涉及指针,因此节省了内存。
数组实现的缺点:
- 它不是动态的,即它不会根据运行时的需要而增长和收缩。 [但是对于动态大小的数组,例如 C++ 中的向量、Python 中的列表、Java 中的 ArrayList,堆栈也可以随着数组实现而增长和收缩]。
- 堆栈的总大小必须事先定义。
使用链表实现堆栈:
- C++
- C
- Java
- Python3
- C#
- JavaScript
C++
// C++ program for linked list implementation of stack #include <bits/stdc++.h> using namespace std; // A structure to represent a stack class StackNode { public : int
data; StackNode* next; }; StackNode* newNode( int data) { StackNode* stackNode = new StackNode(); stackNode->data = data; stackNode->next = NULL; return stackNode; } int isEmpty(StackNode* root) { return !root; } void push(StackNode** root, int data) { StackNode* stackNode = newNode(data); stackNode->next = *root; *root = stackNode; cout << data << " pushed to stack\n" ; } int pop(StackNode** root) { if
(isEmpty(*root)) return INT_MIN; StackNode* temp = *root; *root = (*root)->next; int
popped = temp->data; free (temp); return popped; } int peek(StackNode* root) { if
(isEmpty(root)) return INT_MIN; return root->data; } // Driver code int main() { StackNode* root = NULL; push(&root, 10); push(&root, 20); push(&root, 30); cout << pop(&root) << " popped from stack\n" ; cout << "Top element is " << peek(root) << endl; cout << "Elements present in stack : " ; //print all elements in stack : while (!isEmpty(root)) { // print top element in stack cout << peek(root) << " " ; // remove top element in stack pop(&root); } return 0; } // This is code is contributed by rathbhupendra |
C
Java
Python3
C#
Javascript
10 压入堆栈 20 压入堆栈 30 压入堆栈 30 从堆栈中弹出 顶部元素为 20 堆栈中存在的元素:20 10
链表实现的优点:
- 堆栈的链表实现可以根据运行时的需要进行增长和收缩。
- 它被用在许多虚拟机中,比如 JVM。
链表实现的缺点:
- 由于涉及指针,需要额外的内存。
- 堆栈中不可能进行随机访问。
相关文章:
- 使用单链表实现堆栈
- 堆栈的应用、优点和缺点