408数据结构学习笔记——栈和队列的应用、特殊矩阵的压缩(一)

简介: 408数据结构学习笔记——栈和队列的应用、特殊矩阵的压缩

1.栈在括号匹配中的应用

eeaac62402e64838a417c4b9c0face8e.png

#include<iostream>
#include<string>
#define maxSize 10
using namespace std;
//定义顺序栈,采用静态数组
typedef struct sqStack {
  string data;
  int top;
}sqStack;
//初始化栈
bool initStack(sqStack& S) {
  S.top = -1;
  return true;
}
//进栈
bool push(sqStack& S, char e) {
  if (S.top == maxSize - 1) return false;
  S.data[++S.top] = e;
  return true;
}
//出栈
bool pop(sqStack& S, char& e) {
  if (S.top == -1) return false;
  e = S.data[S.top--];
  return true;
}
//判断栈空
bool emptyStack(sqStack S) {
  if (S.top == -1) return false;
  else return true;
}
//括号匹配
bool bracket(string str) {
  sqStack S;
  initStack(S);
    //获得字符串长度
  int length = str.length();
    //保存栈顶的元素
  char topElem;
    //遍历字符串
  for (int i = 0; i < length; i++) {
        //当前是'{'进栈
    if (str[i] == '{') push(S, str[i]);
        //当前是'}'出栈,进行匹配
    else if (str[i] == '}') {
      pop (S, topElem);
      if (topElem != '{') return false;
    }
        //当前是'['进栈
    else if (str[i] == '[') push(S, str[i]);
        //当前是']'出栈,进行匹配
    else if (str[i] == ']') {
      pop (S, topElem);
      if (topElem != '[') return false;
    }
        //当前是'('进栈
    else if (str[i] == '(') push(S, str[i]);
        //当前是')'出栈,进行匹配
    else if (str[i] == ')') {
      pop (S, topElem);
      if (topElem != '(') return false;
    }
  }
    //循环结束后,栈空则匹配成功
  if (emptyStack) return true;
  else return false;
}

2.栈在表达式求值中的运用

前缀表达式:运算符在两个操作数前面

+a b    //操作数1
* c d    //操作数2
 - + a b * c d  

中缀表达式:运算符在两个操作数中间

a + b - c * d

后缀表达式:运算符在两个操作数后面

a b +    //操作数1
c d *    //操作数2
a b + c d * -

2.1.中缀表达式转换后缀表达式

  1. 确定中缀表达式的各个运算符的运算顺序
  2. 选择下一个运算符,按照【左操作数 右操作数 运算符】的方式组成一个新的操作数(整体)
  3. 如果还有运算符,则重复2
  4. "左优先"原则:只要左边的运算符能先计算,则优先计算左边(转换后的后缀表达式不唯一,采用左优先原则可以保证后缀唯一)
中缀表达式:((15 / (7 - (1 + 1))) * 3) - (2 + (1 + 1))
后缀表达式:
(1)1 1 +
(2)7 1 1 + -
(3)15 7 1 1 + - /
(4)3 15 7 1 1 + - /  *    //左操作数
(5)1 1 +
(6)2 1 1 + +
(7)3 15 7 1 1 + - /  * 2 1 1 + + -

2.2.后缀表达式的计算方法

从左往右扫描,每遇到一个运算符,就让运算符前面最近的两个操作数执行对应运算,合并为一个操作数

cc7135f025fa48d2b31108333dfe9c82.png

//括号表示括号内为一个整体操作数
//3 15 7 1 1 + - /  * 2 1 1 + + -
(1)1 1 +
(2)7 (1 1 +) -
(3)15 (7 (1 1 +) -) /
(4)3 (15 (7 (1 1 +) -) /) *
(5)1 1 +
(6)2 (1 1 +)
(7)(3 (15 (7 (1 1 +) -) /) *) (2 (1 1 +)) -

e79beb0b3e524dfbb6152070d7307afd.png

//括号表示括号内为一个整体操作数
//A B C D - * + E F / -
(1)C D -
(2)B (C D -) *
(3)A B (C D -) * +
(4)E F /
(5)(A B (C D -) * +) (E F /) -

2.3.中缀表达式转换前缀表达式

  1. 确定中缀表达式的各个运算符的运算顺序
  2. 选择下一个运算符,按照【 运算符 左操作数 右操作数】的方式组成一个新的操作数(整体)
  3. 如果还有运算符,则重复2
  4. "右优先"原则:只要右边的运算符能先计算,则优先计算右边(转换后的后缀表达式不唯一,采用右优先原则可以保证后缀唯一)
1.中缀表达式:A + B * (C - D) - E / F
前缀表达式:
(1)/ E F
(2)- C D 
(3)* B - C D 
(4)+ A * B - C D 
(5)- + A * B - C D / E F

2.4. 中缀表达式转后缀表达式(机算——栈)

  1. 初始化一个栈,用于保存暂时还不能确定运算顺序的运算符
  2. 从左到右依次处理各个元素。有三种情况

     a.遇到操作数。直接加入到后缀表达式

     b.遇到界限符。遇到"("直接入栈;遇到")"依次弹出站内运算符并且假如后缀表达式,直到弹出"("为止。注意:"("不加入后缀表达式

    c.遇到运算符。依次弹出栈中优先级高于或等于当前运算符的所有运算符,并加入后缀表达式。若碰到"("或栈空则停止。之后再把当前运算符入栈

3.按照上述方法处理完所有字符后,依次弹出栈中剩余运算符,并假如后缀表达式中

A + B - C * D / E + F
(1)
扫描到'A':'A'是操作数,直接加入后缀表达式
后缀表达式:A
栈:空
(2)
扫描到'+':'+'是运算符,此时栈空,入栈
后缀表达式:A
栈:+
(3)
扫描到'B':'B'是操作数,直接加入后缀表达式
后缀表达式:A B
栈:+
(4)
扫描到'-':'-'是运算符,因为栈顶元素为'+',与'-'同优先级,因此,弹出'+'加入后缀表达式后,将'-'入栈
后缀表达式:A B +
栈:-
(5)
扫描到'C':'C'是操作数,直接加入后缀表达式
后缀表达式:A B + C
栈:-
(6)
扫描到'*':'*'是运算符,因为栈顶元素为'-',优先级<'*',因此,将'*'入栈
后缀表达式:A B + C
栈:- *
(7)
扫描到'D':'D'是操作数,直接加入后缀表达式
后缀表达式:A B + C D
栈:- *
(8)
扫描到'/':'/'是运算符,因为栈顶元素为'*',与'/'同优先级 && 优先级>'-',因此,弹出'*'加入后缀表达式后,将'/'入栈
后缀表达式:A B + C D *
栈:- /
(9)
扫描到'E':'E'是操作数,直接加入后缀表达式
后缀表达式:A B + C D * E
栈:- /
(10)
扫描到'+':'+'是运算符,因为栈顶元素为'/',优先级<'/' && 优先级 = '-',因此,依次弹出'/''-'加入后缀表达式后,将'+'入栈
后缀表达式:A B + C D * E / -
栈:+
(11)
扫描到'F':'F'是操作数,直接加入后缀表达式
后缀表达式:A B + C D * E / - F
栈:+
(12)
所有符号全部扫描完毕,清空栈中元素,并使其加入后缀表达式中
后缀表达式:A B + C D * E / - F +
栈:空
A + B * (C - D) - E / F
(1)
扫描到'A':'A'是操作数,直接加入后缀表达式
后缀表达式:A
栈:空
(2)
扫描到'+':'+'是运算符,此时栈空,入栈
后缀表达式:A
栈:+
(3)
扫描到'B':'B'是操作数,直接加入后缀表达式
后缀表达式:A B
栈:+
(4)
扫描到'*':'*'是运算符,栈中元素'+' < '*','*'入栈
后缀表达式:A B
栈:+ *
(5)
扫描到'(':'('是界限符,入栈
后缀表达式:A B
栈:+ * (
(6)
扫描到'C':'C'是操作数,直接加入后缀表达式
后缀表达式:A B C
栈:+ * (
(7)
扫描到'-':'-'是运算符,此时栈顶元素为'(',入栈
后缀表达式:A B C
栈:+ * ( -
(8)
扫描到'D':'D'是操作数,直接加入后缀表达式
后缀表达式:A B C D
栈:+ * ( -
(9)
扫描到')':')'是界限符,出栈直到出栈元素为'(',加入出栈元素中的运算符
后缀表达式:A B C D -
栈:+ * 
(10)
扫描到'-':'-'是运算符,优先级<'*' && 优先级 = '+',依次出栈,并将'-'入栈
后缀表达式:A B C D - * +
栈:-
(11)
扫描到'E':'E'是操作数,直接加入后缀表达式
后缀表达式:A B C D - * + E
栈:-
(12)
扫描到'/':'/'是运算符,优先级>'-',入栈
后缀表达式:A B C D - * + E
栈:- /
(13)
扫描到'F':'F'是操作数,直接加入后缀表达式
后缀表达式:A B C D - * + E F
栈:- /
(14)
扫描完所有字符,依次弹出栈中元素,并将其加入后缀表达式中
后缀表达式:A B C D - * + E F / -
栈:空

2.5.中缀表达式的计算(机算)

用栈实现:

  1. 初始化两个栈,操作数栈运算符栈
  2. 若扫描到操作数,压入操作数栈
  3. 若扫描到运算符或界限符,则按照“中缀转后缀”相同的逻辑压入运算符栈(期间也会弹出运算符,每当弹出一个运算符时,就需要再弹出两个操作数栈的栈顶元素并执行相应运算,运算结果再压回操作数栈
A + B - C * D / E + F
(1)
扫描到'A':进操作数栈
操作数栈:A
运算符栈:空
(2)
扫描到'+':运算符栈空,因此,进入运算符栈
操作数栈:A 
运算符栈:+
(3)
扫描到'B':进入操作数栈
操作数栈:A B
运算符栈:+
(4)
扫描到'-':运算符栈顶元素为'+',优先级相等,因此,弹出'+'和操作数栈的两个元素计算,计算结果压回操作数栈,后'-'进运算符栈
操作数栈:(A B +)
运算符栈:-
(5)
扫描到'C':进入操作数栈
操作数栈:(A B +) C
运算符栈:-
(6)
扫描到'*':运算符栈顶元素为'-',优先级<'*',因此,'*'进栈
操作数栈:(A B +) C
运算符栈:- *
(7)
扫描到'D':进入操作数栈
操作数栈:(A B +) C D
运算符栈:- *
(8)
扫描到'/':运算符栈顶元素为'*',优先级相等,因此,弹出'*'和操作数栈的两个元素计算,计算结果压回操作数栈,后'/'进运算符栈
操作数栈:(A B +) (C D *)
运算符栈:- /
(9)
扫描到'E':进入操作数栈
操作数栈:(A B +) (C D *) E
运算符栈:- /
(10)
扫描到'+':运算符栈中优先级都>='+',因此依次弹出,并将计算结果压入操作数栈中,后将'+'入运算符栈
操作数栈:(A B + C D * E / -)
运算符栈:+
(11)
扫描到'F':进入操作数栈
操作数栈:(A B + C D * E / -) F
运算符栈:+
(12)
扫描完全部字符,弹出运算符栈中所有元素,并计算
A B + C D * E / - F +


目录
打赏
0
1
1
0
19
分享
相关文章
|
5月前
|
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
487 9
数据结构实验之矩阵的运算器(二维数组)
本实验旨在通过团队合作,掌握数组和矩阵相关运算的代码实现,包括矩阵的加减、数乘、转置、乘法、n次方及行列式的计算。实验过程中,成员们需分工协作,解决编程难题,最终实现一个功能完备的矩阵计算器。通过本实验,不仅锻炼了编程能力,还加深了对数学概念的理解,同时培养了团队合作精神。
102 4
|
3月前
|
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
178 77
|
2月前
|
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
32 11
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
3月前
|
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
84 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
3月前
|
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
64 9
|
3月前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
66 7
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
119 5
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!