栈(Stack)

简介(Introduction)

限定仅在表尾进行插入和删除操作的线性表,这一端被称为栈顶(Top),另一端称为栈底(Bottom)



描述(Description)

  • 栈是一个 先入后出 —— FILO-First In Last Out 的有序列表,先放进去的最后拿出来,而后放入的先拿出来。
  • 向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素
  • 从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。



示例(Example)

image

image

image



代码(Code)

  • 入栈

    void push(int x) {
    	stk[ ++ tt ] = x;//tt一开始为0
    }
    

  • 出栈

    void pop() {
    	-- tt;
    }
    

  • 判断是否栈空

    bool empty() {
    	if (tt == 0) return true;
    	return false;
    }
    

  • 查询栈顶元素

    int query() {
    	return stk[tt];
    }
    



应用(Application)



单调栈


给定一个长度为N的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出-1

输入格式

第一行包含整数N,表示数列长度。
第二行包含N个整数,表示整数数列。

输出格式

共一行,包含N个整数,其中第i个数表示第i个数的左边第一个比它小的数,如果不存在则输出-1

数据范围

\(1 \le N \le 10^5\)
\(1 \le 数列中元素 \le10^9\)

输入样例:

5
3 4 2 7 5

输出样例:

-1 3 -1 2 2
  • 题解:

    // C++ Version
    
    #include <iostream>
    
    using namespace std;
    
    const int N = 1e6 + 10;
    
    int n,  tt;
    int stk[N];
    
    int main()  {
    	cin >> n;
    	for (int i = 0; i < n; i ++ ) {
    		int x;
    		cin >> x;
    		while (tt && stk[tt] >= x) tt -- ; // 如果栈顶元素大于当前待入栈元素,则出栈
    		if (tt) cout << stk[tt] << ' '; // 输出栈顶元素———第一个小于x的值
    		else cout << "-1" << ' '; // 如果栈空,则没有比该元素小的值
    		stk[ ++ tt ] = x;
    	}
    	return 0;
    }
    


中缀表达式求和


image
image

  • 分析:先转化为 后缀表达式,然后通过进行存储并求和(后缀表达式中忽略了括号)

  • 题解:

    // C++ Version
    
    #include <iostream>
    #include <unordered_map>
    #include <stack>
    
    using namespace std;
    
    //设置优先级
    unordered_map<char, int> h = {{'-', 1}, {'+', 1}, {'*', 2}, {'/', 2}};
    stack<int> num;  // 用于存所有数字
    stack<char> op;  // 用于存储运算符
    
    
    void calc() {
    	int b = num.top();  // 取出第二个数
    	num.pop();
    	int a = num.top();  // 取出第一个数
    	num.pop();
    	int c = op.top();  // 取出一个操作符
    	op.pop();
    
    	int res;
    	//计算结果
    	if (c == '-') res = a - b;
    	else if (c == '+') res = a + b;
    	else if (c == '*') res = a * b;
    	else if (c == '/') res = a / b;
    	num.push(res);  // 将计算后的结果加入结果集
    }
    
    int main() {
    	string s; cin >> s;
    	for (int i = 0; i < s.size(); i ++ ) {
    		auto c = s[i];
    		if (isdigit(c)) { // 将数字入栈
    			int x = 0, j = i;
    			while (j < s.size() && isdigit(s[j]))  // 可能出现多位数
    				x = x * 10 + s[j ++ ] - '0';
    			num.push(x);  // 将 >= 1 位的数添加至num中
    			i = j - 1;  // 更新i的位置移动到多位数的最后一位
    		}
    		else if (c == '(') op.push(c);  // 如果左括号直接加入op
    		else if (c == ')') {   // 遇到右括号计算括号里面的
    			while (op.size() && op.top() != '(') calc(); // 一直计算到左括号的位置
    			op.pop();   // 将左括号删除
    		} 
    		else {
    			while (op.size() && h[op.top()] >= h[c]) calc(); //根据优先级进行计算
    			op.push(c); // 将本次的操作符进行入栈
    		}
    	}
    
    	while (op.size()) calc();   // 计算所有剩余的数字
    
    	cout << num.top() << endl;  // 最后一个数即为答案
    	return 0;
    }
    


中缀转后缀表达式


image

  • 题解
    #include <iostream>
    #include <unordered_map>
    #include <stack>
    
    using namespace std;
    
    stack<char> op;
    
    void calc() {
    	char 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.size() && op.top() != '(') calc();
    			op.pop();
    		}
    		else {
    			while (op.size() && op.top() != '(' && pr[op.top()] >= pr[s[i]]) calc();
    			op.push(s[i]);
    		}
    	}
    
    	while (op.size()) calc();
    
    	return 0;
    }
    

posted @ 2023-05-01 00:28  FFex  阅读(8)  评论(0编辑  收藏  举报