• 【数据结构】栈(stack)


    栈的基本概念

    • 概念

    栈是一个线性表,栈元素具有线性关系,即前驱后继关系,但是是一种特殊的线性表,在线性表的表尾进行插入和删除操作,表尾是指栈顶表头是指栈底

    • 特性

    先进后出的规则

    始终只进行栈顶操作,想访问栈底数据,就需要将上面数据一个一个出栈


    栈的顺序存储

    • 基本概念

    栈的顺序存储结构简称顺序栈,它是运算受限制的顺序表。顺序栈的存储结构是:利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针 top (只是栈顶元素在顺序表的位置)


    顺序存储栈栈

    • 框架及函数声明
    1. #ifndef SEQSTACK_H
    2. #define SEQSTACK_H
    3. #define _CRT_SECURE_NO_WARNINGS 1
    4. #include
    5. #include
    6. #include
    7. // 数组模拟栈的顺序存储
    8. #define MAX_SIZE 1024
    9. #define SEQSTACK_TURE 1
    10. #define SEQSTACK_FALSE 0
    11. typedef struct SEQSTACK {
    12. void* data[MAX_SIZE];
    13. int size;
    14. }SeqStack;
    15. // 初始化栈
    16. SeqStack* Init_Stack();
    17. // 入栈
    18. void Push_Stack(SeqStack* stack, void* data);
    19. // 返回栈顶元素
    20. void* Top_Stack(SeqStack* stack);
    21. // 出栈
    22. void Pop_Stack(SeqStack* stack);
    23. // 判断是否为空
    24. int IsEmpty_Stack(SeqStack* stack);
    25. // 返回栈中元素个数
    26. int Size_Stack(SeqStack* stack);
    27. // 清空栈
    28. void Clear_Stack(SeqStack* stack);
    29. // 销毁
    30. void FreeSpace_Stack(SeqStack* stack);
    31. #endif
    • 函数实现
    1. #include"SeqStack.h"
    2. // 初始化栈
    3. SeqStack* Init_Stack(){
    4. //(SeqStack*)Stack = (SeqStack*)malloc(sizeof(SeqStack));
    5. SeqStack* stack = (SeqStack*)malloc(sizeof(SeqStack));
    6. for (int i = 0; i < MAX_SIZE; i++) {
    7. stack->data[i] = NULL;
    8. }
    9. stack->size = 0;
    10. return stack;
    11. }
    12. // 入栈
    13. void Push_Stack(SeqStack* stack, void* data){
    14. if (stack->size == MAX_SIZE) return;
    15. if (stack == NULL) return;
    16. if (data == NULL) return;
    17. stack->data[stack->size] = data;
    18. stack->size++;
    19. }
    20. // 返回栈顶元素
    21. void* Top_Stack(SeqStack* stack){
    22. if (stack == NULL) return NULL;
    23. if (stack->size == 0) return NULL;
    24. return stack->data[stack->size - 1];
    25. }
    26. // 出栈
    27. void Pop_Stack(SeqStack* stack){
    28. if (stack == NULL) return;
    29. if (stack->size == 0) return;
    30. stack->data[stack->size - 1] = NULL;
    31. stack->size--;
    32. }
    33. // 判断是否为空
    34. int IsEmpty_Stack(SeqStack* stack){
    35. if (stack->data == NULL) return -1;
    36. if (stack->size == 0) return SEQSTACK_TURE;
    37. return SEQSTACK_FALSE;
    38. }
    39. // 返回栈中元素个数
    40. int Size_Stack(SeqStack* stack){
    41. if (stack == NULL) return 0;
    42. return stack->size;
    43. }
    44. // 清空栈
    45. void Clear_Stack(SeqStack* stack){
    46. if (stack == NULL) return;
    47. for (int i = 0; i < stack->size; i++) {
    48. stack->data[i] = NULL;
    49. }
    50. stack->size = 0;
    51. }
    52. // 销毁
    53. void FreeSpace_Stack(SeqStack* stack){
    54. if (stack == NULL) return;
    55. free(stack);
    56. }
    • 测试代码
    1. #include"SeqStack.h"
    2. typedef struct PERSON {
    3. char name[64];
    4. int age;
    5. }Person;
    6. void test() {
    7. SeqStack* stack = Init_Stack();
    8. Person p1, p2, p3, p4, p5;
    9. strcpy(p1.name, "张三");
    10. strcpy(p2.name, "李四");
    11. strcpy(p3.name, "王五");
    12. strcpy(p4.name, "李华");
    13. strcpy(p5.name, "赵六");
    14. p1.age = 10;
    15. p2.age = 20;
    16. p3.age = 30;
    17. p4.age = 40;
    18. p5.age = 50;
    19. // 判断栈是否为空
    20. if (IsEmpty_Stack(stack)) printf("栈为空\n");
    21. else printf("栈非空\n");
    22. // 入栈
    23. Push_Stack(stack, (void*)&p1);
    24. Push_Stack(stack, (void*)&p2);
    25. Push_Stack(stack, (void*)&p3);
    26. Push_Stack(stack, (void*)&p4);
    27. Push_Stack(stack, (void*)&p5);
    28. // 判断栈是否为空
    29. if (IsEmpty_Stack(stack)) printf("栈为空\n");
    30. else printf("栈非空\n");
    31. while (Size_Stack(stack)) {
    32. // 访问栈顶元素
    33. Person* person = (Person*)Top_Stack(stack);
    34. printf("name: %s age: %d\n", person->name, person->age);
    35. Pop_Stack(stack);
    36. }
    37. FreeSpace_Stack(stack);
    38. }
    39. int main() {
    40. test();
    41. return 0;
    42. }

    运行结果:


    链式存储的栈

    • 框架及函数声明
    1. #ifndef LINKSTACK_H
    2. #define LINKSTACK_H
    3. #define _CRT_SECURE_NO_WARNINGS 1
    4. #include
    5. #include
    6. #include
    7. // 结点
    8. typedef struct STACKNODE {
    9. struct STACKNODE* next;
    10. }StackNode;
    11. // 链式 栈
    12. typedef struct LINKSTACK {
    13. StackNode head;
    14. int size;
    15. }LinkStack;
    16. // 初始化
    17. LinkStack* Init_Stack();
    18. // 入栈
    19. void Push_Stack(LinkStack* stack, StackNode* data);
    20. // 出栈
    21. void Pop_Stack(LinkStack* stack);
    22. // 返回栈顶
    23. StackNode* Top_Stack(LinkStack* stack);
    24. // 返回栈中元素个数
    25. int Size_Stack(LinkStack* stack);
    26. // 清空栈
    27. void Clear_Stack(LinkStack* stack);
    28. // 释放栈
    29. void Free_Stack(LinkStack* stack);
    30. #endif // !LINKSTACK_H
    • 函数实现
    1. #include "LinkStack.h"
    2. // 初始化
    3. LinkStack* Init_Stack() {
    4. LinkStack* stack = (LinkStack*)malloc(sizeof(LinkStack));
    5. stack->head.next = NULL;
    6. stack->size = 0;
    7. return stack;
    8. }
    9. // 入栈
    10. void Push_Stack(LinkStack* stack, StackNode* data) {
    11. if (stack == NULL) return;
    12. if (data == NULL) return;
    13. data->next = stack->head.next;
    14. stack->head.next = data;
    15. stack->size++;
    16. }
    17. // 出栈
    18. void Pop_Stack(LinkStack* stack) {
    19. if (stack == NULL) return;
    20. if (stack->size == 0) return;
    21. // 第一个有效结点
    22. StackNode* pNext = stack->head.next;
    23. stack->head.next = pNext->next;
    24. stack->size--;
    25. }
    26. // 返回栈顶
    27. StackNode* Top_Stack(LinkStack* stack) {
    28. if (stack == NULL) return NULL;
    29. if (stack->size == 0) return NULL;
    30. return stack->head.next;
    31. }
    32. // 返回栈元素个数
    33. int Size_Stack(LinkStack* stack) {
    34. if (stack == NULL) return 0;
    35. return stack->size;
    36. }
    37. // 清空栈
    38. void Clear_Stack(LinkStack* stack) {
    39. if (stack == NULL) return;
    40. stack->head.next = NULL;
    41. stack->size = 0;
    42. }
    43. // 释放栈
    44. void Free_Stack(LinkStack* stack) {
    45. if (stack == NULL) return;
    46. free(stack);
    47. }
    • 测试代码
    1. #include "LinkStack.h"
    2. typedef struct PERSON {
    3. StackNode node;
    4. char name[64];
    5. int age;
    6. }Person;
    7. void test() {
    8. // 创建栈
    9. LinkStack* stack = Init_Stack();
    10. // 创建数据
    11. Person p1, p2, p3, p4, p5;
    12. strcpy(p1.name, "aaa");
    13. strcpy(p2.name, "bbb");
    14. strcpy(p3.name, "ccc");
    15. strcpy(p4.name, "ddd");
    16. strcpy(p5.name, "eee");
    17. p1.age = 10;
    18. p2.age = 20;
    19. p3.age = 30;
    20. p4.age = 40;
    21. p5.age = 50;
    22. // 入栈
    23. Push_Stack(stack, (StackNode*)&p1);
    24. Push_Stack(stack, (StackNode*)&p2);
    25. Push_Stack(stack, (StackNode*)&p3);
    26. Push_Stack(stack, (StackNode*)&p4);
    27. Push_Stack(stack, (StackNode*)&p5);
    28. // 返回栈中元素个数
    29. printf("栈中元素个数: %d\n", Size_Stack(stack));
    30. // 出栈
    31. while (Size_Stack(stack) > 0) {
    32. Person* p = (Person*)Top_Stack(stack); // 返回栈顶
    33. printf("name: %s age: %d\n", p->name, p->age);
    34. Pop_Stack(stack); // 弹出栈顶
    35. }
    36. Free_Stack(stack);
    37. }
    38. int main() {
    39. test();
    40. return 0;
    41. }

    运行结果:


    栈的应用

    就近匹配

    匹配左右括号,找到字符串中不匹配的位置

    • 框架及函数声明
    1. #ifndef LINKSTACK_H
    2. #define LINKSTACK_H
    3. #include
    4. #include
    5. #include
    6. // 结点
    7. typedef struct STACKNODE {
    8. struct STACKNODE* next;
    9. }StackNode;
    10. // 链式栈
    11. typedef struct LINKSTACK {
    12. StackNode head;
    13. int size;
    14. }LinkStack;
    15. // 初始化栈
    16. LinkStack* Init_Stack();
    17. // 入栈
    18. void Push_Stack(LinkStack* stack, StackNode* data);
    19. // 出栈
    20. void Pop_Stack(LinkStack* stack);
    21. // 获取栈顶
    22. StackNode* Top_Stack(LinkStack* stack);
    23. // 返回栈元素个数
    24. int Size_Stack(LinkStack* stack);
    25. // 清空栈
    26. void Clear_Stack(LinkStack* stack);
    27. // 释放栈
    28. void Free_Stack(LinkStack* stack);
    29. #endif // !LINKSTACK_H
    • 函数实现
    1. #include "LinkStack.h"
    2. // 初始化栈
    3. LinkStack* Init_Stack() {
    4. LinkStack* stack = (LinkStack*)malloc(sizeof(LinkStack));
    5. stack->head.next = NULL;
    6. stack->size = 0;
    7. return stack;
    8. }
    9. // 入栈
    10. void Push_Stack(LinkStack* stack, StackNode* data) {
    11. if (stack == NULL) return;
    12. if (data == NULL) return;
    13. data->next = stack->head.next;
    14. stack->head.next = data;
    15. stack->size++;
    16. }
    17. // 出栈
    18. void Pop_Stack(LinkStack* stack) {
    19. if (stack == NULL) return;
    20. if (stack->size == 0) return;
    21. // 记录第一个有效的结点
    22. StackNode* pNext = stack->head.next;
    23. stack->head.next = pNext;
    24. stack->size--;
    25. }
    26. // 获取栈顶
    27. StackNode* Top_Stack(LinkStack* stack) {
    28. if (stack == NULL) return NULL;
    29. return stack->head.next;
    30. }
    31. // 返回栈元素个数
    32. int Size_Stack(LinkStack* stack) {
    33. if (stack == NULL) return 0;
    34. return stack->size;
    35. }
    36. // 清空栈
    37. void Clear_Stack(LinkStack* stack) {
    38. if (stack == NULL) return;
    39. stack->size = 0;
    40. }
    41. // 释放栈
    42. void Free_Stack(LinkStack* stack) {
    43. if (stack == NULL) return;
    44. free(stack);
    45. }
    • 测试代码
    1. #include "LinkStack.h"
    2. typedef struct MyChar {
    3. StackNode node;
    4. char* str;
    5. int index;
    6. }MyChar;
    7. int IsLeft(char c) {
    8. return c == '(';
    9. }
    10. int IsRight(char c) {
    11. return c == ')';
    12. }
    13. void ShowError(char* str, int pos) {
    14. printf("%s\n", str);
    15. for (int i = 0; i < pos; i++) {
    16. printf(" ");
    17. }
    18. printf("A\n");
    19. }
    20. void test() {
    21. char* str = "((1+2)+)()(())";
    22. char* p = str;
    23. int index = 0;
    24. // 创建栈
    25. LinkStack* stack = Init_Stack();
    26. while (*p != '\0') {
    27. // 左括号 ( 进栈
    28. if (IsLeft(*p)) {
    29. // 创建字符数据
    30. MyChar* mychar = (MyChar*)malloc(sizeof(MyChar));
    31. mychar->str = p;
    32. mychar->index = index;
    33. Push_Stack(stack, (StackNode*)mychar);
    34. free(mychar);
    35. }
    36. // 右括号 ) 出栈
    37. if (IsRight(*p)) {
    38. // 栈内要有括号
    39. if (Size_Stack(stack) > 0) {
    40. Pop_Stack(stack); // 弹出栈顶元素
    41. }
    42. else {
    43. printf("右括号没有匹配的左括号\n");
    44. ShowError(str, index);
    45. break;
    46. }
    47. }
    48. p++;
    49. index++;
    50. }
    51. if (Size_Stack(stack) > 0) {
    52. MyChar* mychar = (MyChar*)Top_Stack(stack);
    53. printf("左括号没有匹配的右括号\n");
    54. ShowError(str, (mychar->index) - Size_Stack(stack) + 1);
    55. Pop_Stack(stack);
    56. free(mychar);
    57. }
    58. else {
    59. printf("括号匹配成功\n");
    60. }
    61. Free_Stack(stack);
    62. }
    63. int main() {
    64. test();
    65. return 0;
    66. }

    运行结果:


    中缀表达式

    后缀表达式中缀表达式

    • 将运算符放在数字后面叫后缀表达式 ---> 符合及计算机运算
    • 平时所写的数学表达式叫中缀表达式 ---> 符合直观思维逻辑

    实例(中缀表达式 转化为 后缀表达式)

    • 1 + 2      --->  1 2 +
    • 1 + 2 * 3 --->  1 2 3 * +

    中缀表达式算法

    遍历中缀表达式中所有的数字和符号

    • 对于数字:直接输出
    • 对于符号:
    1. 左括号:直接进栈
    2. 运算符号:与栈顶符号进行优先级比较        
      • 该符号优先级高:该运算符入栈(默认栈底为左括号,左括号优先级最低)
      • 该符号优先级不高:将栈顶符号弹出并输出(直到满足条件1),之后该符号进栈
    • 对于右括号:将栈顶符号弹出并输出,直到匹配左括号

    遍历结束:将栈中的所有符号弹出并输出                        

    • 代码示例
    1. #include "LinkStack.h"
    2. typedef struct Mychar {
    3. StackNode node;
    4. char* str;
    5. }MyChar;
    6. // 创建 MyChar
    7. MyChar* CreateMyChar(char* p) {
    8. MyChar* mychar = (MyChar*)malloc(sizeof(MyChar));
    9. if (mychar != NULL) {
    10. mychar->str = p;
    11. return mychar;
    12. }
    13. else return NULL;
    14. }
    15. // 数字
    16. int Is_Number(char c) {
    17. return (c >= '0' && c <= '9');
    18. }
    19. // 数字操作
    20. void Number_Operate(char* p) {
    21. printf("%c", *p);
    22. }
    23. // 左括号
    24. int Is_Left(char c) {
    25. return (c == '(');
    26. }
    27. // 左括号操作
    28. void Left_Operate(LinkStack* stack, char* p) {
    29. // 进栈
    30. Push_Stack(stack, (StackNode*)CreateMyChar(p));
    31. }
    32. // 右括号
    33. int Is_Right(char c) {
    34. return (c == ')');
    35. }
    36. // 右括号操作
    37. void Right_Operate(LinkStack* stack) {
    38. // 先判断栈中有没有元素
    39. while (Size_Stack(stack) > 0) {
    40. MyChar* mychar = (MyChar*)Top_Stack(stack);
    41. // 匹配到左括号
    42. if (Is_Left(*(mychar->str))) {
    43. // 左括号出栈
    44. Pop_Stack(stack);
    45. // 结束
    46. break;
    47. }
    48. // 输出
    49. printf("%c", *(mychar->str));
    50. // 弹出
    51. Pop_Stack(stack);
    52. }
    53. }
    54. // 运算符
    55. int Is_Opertaor(char c) {
    56. return (c == '+' || c == '-' ||
    57. c == '*' || c == '/');
    58. }
    59. // 返回运算符优先级
    60. int GetPriority(char c) {
    61. if (c == '*' || c == '/') {
    62. return 2;
    63. }
    64. if (c == '+' || c == '-') {
    65. return 1;
    66. }
    67. return 0;
    68. }
    69. // 运算符操作
    70. void Operator_Operate(LinkStack* stack, char* p) {
    71. // 取出栈顶符号
    72. MyChar* mychar = (MyChar*)Top_Stack(stack);
    73. // 栈顶没有符号,该符号入栈
    74. if (mychar == NULL) {
    75. Push_Stack(stack, (StackNode*)CreateMyChar(p));
    76. return;
    77. }
    78. // 栈顶优先级低于当前符号优先级,该符号入栈
    79. if (GetPriority(*(mychar->str)) < GetPriority(*p)) {
    80. Push_Stack(stack, (StackNode*)CreateMyChar(p));
    81. return;
    82. }
    83. // 栈顶优先级不低于当前符号优先级
    84. else {
    85. while (Size_Stack(stack) > 0) {
    86. MyChar* mychar2 = (MyChar*)Top_Stack(stack);
    87. // 直到栈顶符号优先级低于该符号,该符号入栈
    88. if (GetPriority(*(mychar2->str)) < GetPriority(*p)) {
    89. Push_Stack(stack, (StackNode*)CreateMyChar(p));
    90. break;
    91. }
    92. printf("%c", *(mychar2->str));
    93. Pop_Stack(stack);
    94. }
    95. }
    96. }
    97. // 弹出剩余的符号
    98. void Left_Over_Stack(LinkStack* stack) {
    99. while (Size_Stack(stack) > 0) {
    100. MyChar* mychar = (MyChar*)Top_Stack(stack);
    101. printf("%c", *(mychar->str));
    102. Pop_Stack(stack);
    103. }
    104. }
    105. void test() {
    106. char* str = "3+(2-1)*5/6";
    107. char* p = str;
    108. LinkStack* stack = Init_Stack();
    109. while (*p != '\0') {
    110. // 数字(输出)
    111. if (Is_Number(*p)) {
    112. Number_Operate(p);
    113. }
    114. // 左括号(入栈)
    115. if (Is_Left(*p)) {
    116. Left_Operate(stack, p);
    117. }
    118. // 右括号(出栈直到左括号)
    119. if (Is_Right(*p)) {
    120. Right_Operate(stack);
    121. }
    122. // 运算符(与栈顶比较)
    123. if (Is_Opertaor(*p)) {
    124. Operator_Operate(stack, p);
    125. }
    126. p++; // 字符指针移动
    127. }
    128. // 循环结束直接弹出所有符号
    129. while (Size_Stack(stack) > 0) {
    130. MyChar* mychar = (MyChar*)Top_Stack(stack);
    131. printf("%c", *(mychar->str));
    132. Pop_Stack(stack);
    133. }
    134. // 释放栈
    135. FreeStack(stack);
    136. }
    137. int main() {
    138. test();
    139. return 0;
    140. }

    运行结果:


    后缀表达式计算

    后缀转中缀

    遍历后缀表达式中的数字和符号

    • 对于数字:进栈
    • 对于符号:
      • 从栈中弹出右操作数
      • 从栈中弹出左操作数
      • 根据符号进行运算
      • 将运算结果压入栈中

    结束遍历:栈中的唯一数字为计算结果

    图方便直接C++的 stack 和 list 

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. int isNumber(char c) {
    7. return (c >= '0' && c <= '9');
    8. }
    9. int isOperate(char c) {
    10. return (c == '+' || c == '-' || c == '*' || c == '/');
    11. }
    12. int priorityOperate(char c) {
    13. if (c == '*' || c == '/') return 2;
    14. if (c == '+' || c == '-') return 1;
    15. return 0;
    16. }
    17. int isLeft(char c) {
    18. return (c == '(');
    19. }
    20. int isRight(char c) {
    21. return (c == ')');
    22. }
    23. void printList(const list<char>& clist) {
    24. for (list<char>::const_iterator it = clist.begin(); it != clist.end(); it++) {
    25. cout << *it;
    26. }
    27. cout << endl;
    28. }
    29. int main() {
    30. char str[] = "3+(2-1)*5/6";
    31. char* p = str;
    32. list<char>cList;
    33. stack<char>cStack;
    34. while (*p != '\0') {
    35. // 数字
    36. if (isNumber(*p)) {
    37. cList.push_back(*p);
    38. }
    39. // 操作符
    40. if (isOperate(*p)) {
    41. if (cStack.size() == 0) {
    42. cStack.push(*p);
    43. }
    44. else {
    45. if (priorityOperate(*p) > priorityOperate(cStack.top())) {
    46. cStack.push(*p);
    47. }
    48. else {
    49. while (cStack.size() > 0) {
    50. if (priorityOperate(*p) > priorityOperate(cStack.top())) {
    51. cStack.push(*p);
    52. break;
    53. }
    54. cList.push_back(cStack.top());
    55. cStack.pop();
    56. }
    57. }
    58. }
    59. }
    60. // 左括号
    61. if (isLeft(*p)) {
    62. cStack.push(*p);
    63. }
    64. // 右括号
    65. if (isRight(*p)) {
    66. // 出栈直到遇到左括号
    67. while (cStack.size() > 0) {
    68. if (cStack.top() == '(') {
    69. cStack.pop();
    70. break;
    71. }
    72. cList.push_back(cStack.top());
    73. cStack.pop();
    74. }
    75. }
    76. p++;
    77. }
    78. while (cStack.size() > 0) {
    79. cList.push_back(cStack.top());
    80. cStack.pop();
    81. }
    82. printList(cList);
    83. // 波兰表达式处理完
    84. // 对 cList 中处理
    85. // 数字压栈
    86. // 运算符,将栈顶数字弹出,先弹出右操作数再弹出左操作数
    87. // 遍历
    88. for (list<char>::const_iterator cit = cList.begin(); cit != cList.end(); cit++) {
    89. if (isNumber(*cit)) {
    90. cStack.push(*cit);
    91. }
    92. else {
    93. char right = cStack.top();
    94. cStack.pop();
    95. char left = cStack.top();
    96. cStack.pop();
    97. switch (*cit) {
    98. case '+':
    99. cStack.push(left + right);
    100. break;
    101. case '-':
    102. cStack.push(left - right);
    103. break;
    104. case '*':
    105. cStack.push(left * right);
    106. break;
    107. case '/':
    108. cStack.push(left / right);
    109. break;
    110. default:
    111. break;
    112. }
    113. }
    114. }
    115. if (cStack.size() == 1) {
    116. printf("ret = %c", cStack.top());
    117. cStack.pop();
    118. }
    119. else {
    120. printf("error");
    121. printf("%zu", cStack.size());
    122. }
    123. system("pause");
    124. return 0;
    125. }

  • 相关阅读:
    Ubuntu Minkowski Engine安装
    PHP8的数据封装(数据隐藏)-PHP8知识详解
    【开发工具】git服务器端安装部署+客户端配置
    jsbridge实战1:xcode swift 构建iOS app
    【面试】虚拟机栈面试题
    1.3 统计学习方法的三要素
    GetQueuedCompletionStatus返回为0,GetLastError()错误号是234
    目标检测俯瞰总览资料汇总
    万字详解Spring相关组件配置原理
    多元宇宙算法求解多目标优化问题附matlab代码(Multi-VerseOptimizer,MVO)
  • 原文地址:https://blog.csdn.net/xuan3215/article/details/126377624