第三讲 栈与队列

理解!理解!理解!

记得看清楚 题目条件

1. 栈和队列的基本概念

2. 栈和队列的顺序存储结构

lj 理解为主,用猪头打游戏的男人,hhhh

(1) 栈:栈顶元素位置:指向最后一个元素、指向最后一个元素的下一个位置
    stk[N]
    指向最后一个元素  // top = -1
    // 添加
    stk[++top] = 1;
    // 删除
    top--;
    //栈顶
    stk[top]

    指向最后一个元素的下一个位置 // top = 0;
    // 添加
    stk[top++] = 1;
    // 删除
    top--;

    // 返回栈顶
    stk[top-1]

    // 判断是否为空
    top == 0  // top==初始值

(2) 队列:一般采用 循环队列 。
    (a) 队头元素位置:指向第一个元素、指向第一个元素的前一个位置。
    (b) 队尾元素位置:指向队尾元素、指向队尾元素的下一个位置。
    p[N]
    // front rear

    1.front=0 第一个元素,rear=0 最后一个元素的下一个元素
    // 判空 
    front == rear
    // 队满
    front = (rear+1)%N

    // 插入 
    q[rear++] = 1;
    rear %= N

    // 弹出
    front = (front + 1 )%N;

    // 弹出队头
    q[front]

2.front 第一个元素,rear=-1 最后一个元素
// 判空 
front == (rear+1)%N;
// 队满
front = (rear+2)%N

// 插入 
q[++rear] = 1;
rear %= N

// 弹出
front = (front + 1 )%N;

// 弹出队头
q[front]




3. 栈和队列的链式存储结构

头插 和 头删

top指向第一个元素

image-20210710112328076

image-20210711221927834

队列

front 第一个元素

rear 最后一个元素的下一个元素

image-20210710113728170

4. 栈和队列的应用

(1) 栈的应用:表达式求值(中缀表达式转后缀表达式、括号匹配)、DFS

DFS // 套娃?? 画树图来理解 计算机用栈来维护  深搜
不撞南墙不回头

image-20210710114909193

表达式求值(中缀表达式转后缀表达式、括号匹配)

重要!!!!!! 必考。

理解背,模板题

AcWing 3302. 表达式求值

笔试要求:

过程,选择题经常考

往年并没考大题,今年可能。

一个栈存符号( +-*/ 加减符号优先级)

一个栈存数字

image-20210710120238390

王道书解法:

王道P91-92 11题

双栈:运算符栈和操作数栈
那么操作符优先级怎么定义呢?
优先级分为栈内优先级(in stack priority)isp栈外优先级(in coming priority)icp
isp[op]表示该操作符op在栈内的优先数, icp[op]表示该操作符op在栈外的优先数,

对于isp和icp可以用一个map存储 char 到 int 的映射

image-20210710122637351

ps:a+b-a*((c+d)/e-f)+g

image-20210710122842214

按照王道书写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include<iostream>
#include<map>
#include<stack>
using namespace std;
map<char, int> isp, icp;
const char opers[6] = {'+', '-', '*', '/', '(', ')'};
const int isps[6] = {3, 3, 5, 5, 1, 6}, icps[6] = {2, 2, 4, 4, 6, 1};
void init() {
for(int i = 0; i < 6; ++i) isp[opers[i]] = isps[i], icp[opers[i]] = icps[i];
}

void calc(stack<char>& ops, stack<int>& nums) {
int b = nums.top(); nums.pop();
int a = nums.top(); nums.pop();
char op = ops.top(); ops.pop();
int t;
if(op == '+') t = a + b;
else if(op == '-') t = a - b;
else if(op == '*') t = a * b;
else t = a / b;
nums.push(t);
}

int calculate(string s) {
s = "(" + s + ")";
stack<char> ops;
stack<int> nums;
int n = s.size();
for(int i = 0; i < n; ++i) {
if('0' <= s[i] && s[i] <= '9') {
int t = s[i] - '0';
for(int j = i + 1; j < n; ++j) {
if('0' <= s[j] && s[j] <= '9') t = t * 10 + (s[j] - '0');
else {
i = j - 1;
nums.push(t);
break;
}
}
} else if(s[i] == ' ') continue;
else {
if(ops.empty() || isp[ops.top()] < icp[s[i]]) ops.push(s[i]);
else if(isp[ops.top()] == icp[s[i]]) ops.pop();
else {
calc(ops, nums);
i--;
}
}
}
return nums.top();
}

int main() {
init();
string s;
cin >> s;
cout << calculate(s);
return 0;
}

表达式求值,推荐

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
#include <stack>

using namespace std;

stack<char> op;
stack<int> num;

void eval()
{
auto b = num.top(); num.pop();
auto a = num.top(); num.pop();
auto c = op.top(); op.pop();

int x;
if (c == '+') x = a + b;
else if (c == '-') x = a - b;
else if (c == '*') x = a * b;
else x = a / b;
num.push(x);
}

int main()
{
string s;
cin >> s;

unordered_map<char, int> pr{{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
for (int i = 0; i < s.size(); i ++ )
{
if (isdigit(s[i]))
{
int j = i, x = 0;
while (j < s.size() && isdigit(s[j]))
x = x * 10 + s[j ++ ] - '0';
num.push(x);
i = j - 1;
}
else if (s[i] == '(') op.push(s[i]);
else if (s[i] == ')')
{
while (op.top() != '(') eval();
op.pop();
}
else
{
while (op.size() && op.top() != '(' && pr[op.top()] >= pr[s[i]])
eval();
op.push(s[i]);
}
}

while (op.size()) eval();
cout << num.top() << endl;

return 0;
}

中缀表达式转后缀表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
#include <stack>

using namespace std;

stack<char> op;

void eval()
{
auto c = op.top(); op.pop();
cout << c << ' ';
}

int main()
{
string s;
cin >> s;

unordered_map<char, int> pr{{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
for (int i = 0; i < s.size(); i ++ )
{
if (isdigit(s[i]))
{
int j = i, x = 0;
while (j < s.size() && isdigit(s[j]))
x = x * 10 + s[j ++ ] - '0';
cout << x << ' ';
i = j - 1;
}
else if (s[i] == '(') op.push(s[i]);
else if (s[i] == ')')
{
while (op.top() != '(') eval();
op.pop();
}
else
{
while (op.size() && op.top() != '(' && pr[op.top()] >= pr[s[i]])
eval();
op.push(s[i]);
}
}

while (op.size()) eval();

return 0;
}

(2) 队列的应用:BFS

宽搜 层次遍历

5. 考题:2011-2、2011-3、2012-2、2013-2、2014-2、2014-3、2015-1、2016-3、2017-2、2018-1、2018-2、2019-42、2020-2

2011-2

image-20210710155710532

栈: a b c d

d e c b a

d c e b a

d c b e a

d c b a e

4种

2011-3

image-20210710155727855

循环队列

rear 添加一个元素后移一个 当n-1时添加一个元素 才会到 0 A[0]

image-20210710160938339

2012-2

image-20210710155749687

A

image-20210710122842219

2013-2

image-20210710155806016

B

2014-2

image-20210710155820207

B

2014-3

image-20210710155828999

A

2015-1

image-20210710155936385

A

2016-3

image-20210710155954641

C

image-20210710164603717

2017-2

image-20210710160019021

1.尾递归可以不用栈

C

2018-1

image-20210710160034552

B

2018-2

image-20210710160046832

C 模拟即可

队列 Q 123456

队列输出 ,队列输出压栈,栈输出

2019-42

image-20210710160111572

设计一个循环队列 , O(1)时间只能使用链式

不用代码,只写设计思想即可

front 对头,rear 最后一个下一个元素

image-20210710170252466

(3)画出第一个元素入队后的队列状态。

image-20210710170447918

(4)给出入队操作和出队操作的基本过程。

image-20210710170922595

2020-2

image-20210710160206948

6. 押题:AcWing 3302

AcWing 3302