原文: https://www.programiz.com/dsa/stack

在本教程中,您将学习什么是栈。 此外,您还将发现使用 C,C++ ,Java 和 Python 实现栈的实现。

栈是编程中有用的数据结构。 就像一堆板子彼此叠放。

栈 - 图1

栈表示一堆板子

想一想用这样一堆板子可以做的事情

  • 在上面放一个新板
  • 卸下顶板

如果要使板位于底部,则必须先卸下顶部的所有板。 这种安排称为后进先出-放置的最后一个项目是第一个要出去的项目。


编程术语中的栈

用编程术语来说,将一个项目放在栈的顶部称为“推入”,而将一个项目删除则称为“弹出”。

栈 - 图2

栈操作

在上图中,尽管项目 2 保留在最后,但它首先被移除-因此它遵循后进先出(LIFO)原则。

我们可以用任何编程语言(例如 C,C++ ,Java,Python 或 C# )实现栈,但是规范几乎相同。


栈的规范

栈是一个对象,或更具体地说,是一个允许执行以下操作的抽象数据结构(ADT):

  • Push:将元素添加到栈顶部
  • Pop:从栈顶部删除元素
  • IsEmpty:检查栈是否为空
  • IsFull:检查栈是否已满
  • Peek:获取顶部元素的值而不删除它

栈如何工作

操作如下:

  1. 称为TOP的指针用于跟踪栈中的顶部元素。
  2. 初始化栈时,我们将其值设置为 -1,以便我们可以通过比较TOP == -1来检查栈是否为空。
  3. 推入元素时,我们增加TOP的值,然后将新元素放置在TOP指向的位置。
  4. 弹出元素时,我们返回TOP指向的元素并减小其值。
  5. 推入之前,我们检查栈是否已满
  6. 弹出之前,我们检查栈是否已为空

栈 - 图3

栈操作


Python,Java 和 C/C++ 示例

最常见的栈实现是使用数组,但也可以使用列表来实现。

  1. # Stack implementation in python
  2. # Creating a stack
  3. def create_stack():
  4. stack = []
  5. return stack
  6. # Creating an empty stack
  7. def check_empty(stack):
  8. return len(stack) == 0
  9. # Adding items into the stack
  10. def push(stack, item):
  11. stack.append(item)
  12. print("pushed item: " + item)
  13. # Removing an element from the stack
  14. def pop(stack):
  15. if (check_empty(stack)):
  16. return "stack is empty"
  17. return stack.pop()
  18. stack = create_stack()
  19. push(stack, str(1))
  20. push(stack, str(2))
  21. push(stack, str(3))
  22. push(stack, str(4))
  23. print("popped item: " + pop(stack))
  24. print("stack after popping an element: " + str(stack))
  1. // Stack implementation in Java
  2. class Stack {
  3. private int arr[];
  4. private int top;
  5. private int capacity;
  6. // Creating a stack
  7. Stack(int size) {
  8. arr = new int[size];
  9. capacity = size;
  10. top = -1;
  11. }
  12. // Add elements into stack
  13. public void push(int x) {
  14. if (isFull()) {
  15. System.out.println("OverFlow\nProgram Terminated\n");
  16. System.exit(1);
  17. }
  18. System.out.println("Inserting " + x);
  19. arr[++top] = x;
  20. }
  21. // Remove element from stack
  22. public int pop() {
  23. if (isEmpty()) {
  24. System.out.println("STACK EMPTY");
  25. System.exit(1);
  26. }
  27. return arr[top--];
  28. }
  29. // Utility function to return the size of the stack
  30. public int size() {
  31. return top + 1;
  32. }
  33. // Check if the stack is empty
  34. public Boolean isEmpty() {
  35. return top == -1;
  36. }
  37. // Check if the stack is full
  38. public Boolean isFull() {
  39. return top == capacity - 1;
  40. }
  41. public void printStack() {
  42. for (int i = 0; i <= top; i++) {
  43. System.out.println(arr[i]);
  44. }
  45. }
  46. public static void main(String[] args) {
  47. Stack stack = new Stack(5);
  48. stack.push(1);
  49. stack.push(2);
  50. stack.push(3);
  51. stack.push(4);
  52. stack.pop();
  53. System.out.println("\nAfter popping out");
  54. stack.printStack();
  55. }
  56. }
  1. // Stack implementation in C
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #define MAX 10
  5. int count = 0;
  6. // Creating a stack
  7. struct stack {
  8. int items[MAX];
  9. int top;
  10. };
  11. typedef struct stack st;
  12. void createEmptyStack(st *s) {
  13. s->top = -1;
  14. }
  15. // Check if the stack is full
  16. int isfull(st *s) {
  17. if (s->top == MAX - 1)
  18. return 1;
  19. else
  20. return 0;
  21. }
  22. // Check if the stack is empty
  23. int isempty(st *s) {
  24. if (s->top == -1)
  25. return 1;
  26. else
  27. return 0;
  28. }
  29. // Add elements into stack
  30. void push(st *s, int newitem) {
  31. if (isfull(s)) {
  32. printf("STACK FULL");
  33. } else {
  34. s->top++;
  35. s->items[s->top] = newitem;
  36. }
  37. count++;
  38. }
  39. // Remove element from stack
  40. void pop(st *s) {
  41. if (isempty(s)) {
  42. printf("\n STACK EMPTY \n");
  43. } else {
  44. printf("Item popped= %d", s->items[s->top]);
  45. s->top--;
  46. }
  47. count--;
  48. printf("\n");
  49. }
  50. // Print elements of stack
  51. void printStack(st *s) {
  52. printf("Stack: ");
  53. for (int i = 0; i < count; i++) {
  54. printf("%d ", s->items[i]);
  55. }
  56. printf("\n");
  57. }
  58. // Driver code
  59. int main() {
  60. int ch;
  61. st *s = (st *)malloc(sizeof(st));
  62. createEmptyStack(s);
  63. push(s, 1);
  64. push(s, 2);
  65. push(s, 3);
  66. push(s, 4);
  67. printStack(s);
  68. pop(s);
  69. printf("\nAfter popping out\n");
  70. printStack(s);
  71. }
  1. // Stack implementation in C++
  2. #include <stdlib.h>
  3. #include <iostream>
  4. using namespace std;
  5. #define MAX 10
  6. int size = 0;
  7. // Creating a stack
  8. struct stack {
  9. int items[MAX];
  10. int top;
  11. };
  12. typedef struct stack st;
  13. void createEmptyStack(st *s) {
  14. s->top = -1;
  15. }
  16. // Check if the stack is full
  17. int isfull(st *s) {
  18. if (s->top == MAX - 1)
  19. return 1;
  20. else
  21. return 0;
  22. }
  23. // Check if the stack is empty
  24. int isempty(st *s) {
  25. if (s->top == -1)
  26. return 1;
  27. else
  28. return 0;
  29. }
  30. // Add elements into stack
  31. void push(st *s, int newitem) {
  32. if (isfull(s)) {
  33. printf("STACK FULL");
  34. } else {
  35. s->top++;
  36. s->items[s->top] = newitem;
  37. }
  38. size++;
  39. }
  40. // Remove element from stack
  41. void pop(st *s) {
  42. if (isempty(s)) {
  43. printf("\n STACK EMPTY \n");
  44. } else {
  45. printf("Item popped= %d", s->items[s->top]);
  46. s->top--;
  47. }
  48. size--;
  49. cout << endl;
  50. }
  51. // Print elements of stack
  52. void printStack(st *s) {
  53. printf("Stack: ");
  54. for (int i = 0; i < size; i++) {
  55. cout << s->items[i] << " ";
  56. }
  57. cout << endl;
  58. }
  59. // Driver code
  60. int main() {
  61. int ch;
  62. st *s = (st *)malloc(sizeof(st));
  63. createEmptyStack(s);
  64. push(s, 1);
  65. push(s, 2);
  66. push(s, 3);
  67. push(s, 4);
  68. printStack(s);
  69. pop(s);
  70. cout << "\nAfter popping out\n";
  71. printStack(s);
  72. }

栈复杂度

对于基于数组的栈实现,推入和弹出操作需要固定时间,即O(1),因为在两种情况下都只有指针移动。


栈应用

尽管栈是一个易于实现的简单数据结构,但它非常强大。 栈最常见的用途是:

  • 反转单词 - 将所有字母叠放并弹出。 由于栈的 LIFO 顺序,您将获得相反顺序的字母。
  • 在编译器中 - 编译器使用栈通过将表达式转换为前缀或后缀形式来计算2 + 4 / 5 * (7 - 9)之类的表达式的值。
  • 在浏览器中 - 浏览器中的“后退”按钮会将您以前访问过的所有 URL 保存在栈中。 每次您访问新页面时,它都会被添加到栈顶部。 当您按下“后退”按钮时,当前 URL 从栈中删除,并访问前一个 URL。