[C++] Simulation implementation of stack

Insert image description here


(1) Basic introduction

Before this, we have implemented the stack in C language. If you
are not familiar with the bottom layer of the stack, you can read this article.
The main feature is to followLast In First Out(LIFO)


1. Basic concepts

Next, let’s learn about it from the documentation and see how it is described in the documentation.

  1. From the above we see that stack is a container in the STL library. It is used to store data and follows the rules of Last In First Out (LIFO);

  2. A stack is a container adapter. Stack is implemented in the C++ STL library as a template class that provides a specific set of member functions to access its elements.


2. Container adapter

  • Container adapter (also called configuration machine) is a type of container in the STL library. It uses existing container classes to implement the functions of the adapter.
  • To put it simply, a certain requirement is achieved by encapsulating a sequence container (such as vector, deque, list, etc.) and recombining the member functions contained in the container.

There are three types of container adapters: stack, queueandpriority_queue

Container adapters have the following characteristics

    1. Use an existing container class as the underlying implementation
    1. Add and remove elements based on existing functions (such as push(), pop(), top(), etc.
    1. Usually limited and can be optimized

Generally speaking, container adapters are designed to facilitate the use of existing container classes in STL, and simplify the implementation of certain data structures through simple interfaces.


(2) Basic use

void test()
{
    
    
	stack<int> st;
 
	// 在栈顶添加元素
	st.push(1);
	st.push(2);
	st.push(3);
	st.push(4);
	st.push(5);
 
	//栈顶元素
	if (!st.empty())
		cout << st.top() << " " << st.size() << endl;
		
	// 从栈顶弹出元素
	st.pop();
 
	// 获取栈顶元素
	cout << st.top() << endl;
 
	// 检查栈是否为空
	if (st.empty())
		cout << "Stack is empty" << endl;
	else
		cout << "Stack is not empty" << endl;
		
	// 获取栈的大小
	cout << "Stack size is " << st.size() << endl;
}
  • stack is one 模板类, you need to specify the corresponding数据类型

(3) Stack simulation implementation

The underlying container of the stack can be 任何标准的容器类模板or some other specific container class

These container classes should support the following operations:

  • empty: empty operation
  • back: Get the tail element operation
  • push_back: tail insertion element operation
  • pop_back: tail deletion element operation

The standard containers vector, deque, and list all meet these requirements. By default, if no specific underlying container is specified for the stack, it will be used by default =deque

stack member function

Insert image description here

stack simulation implementation

For stack, we can use vector, list and deque to achieve it. We use deque by default.

  • 1️⃣push()
void push(const T& x)
{
    
    
	_con.push_back(x);
}
  • 2️⃣pop()
void pop()
{
    
    
	_con.pop_back();
}
  • 3️⃣top()
const T& top()
{
    
    
	return _con.back();
}
  • 4️⃣empty()
bool empty()
{
    
    
	return _con.empty();
}
  • 5️⃣size()
size_t size()
{
    
    
	return _con.size();
}

The complete code is as follows

#pragma once
#include<iostream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
using namespace std;
namespace mystack
{
    
    
	template<class T, class Container = deque<T>>
	class stack
	{
    
    
	public:
		void push(const T& val)
		{
    
    
			_con.push_back(val);
		}

		void pop()
		{
    
    
			_con.pop_back();
		}
		const T& top()
		{
    
    
			return _con.back();
		}
		
		bool empty()
		{
    
    
			return _con.empty();
		}

		size_t size()
		{
    
    
			return _con.size();
		}
	private:
		Container _con;
	};
}

So when we implement a sequential stack or a chained stack, we don’t need to write it from scratch. We can use an adapter to encapsulate it.

Of course, when we want to change the container for adaptation

stack<int, vector<int>> st; // vector做适配器
stack<int, list<int>> st;  // list做适配器
stack<int> st;             // 默认deque做适配器

(4) Evaluation of reverse Polish expression

Reverse Polish expression is also called a postfix expression. So what is a postfix expression?

  • The operator is located after the operand
  • brackets eliminated

The calculation method of the reverse Polish expression is to traverse from left to right, push it onto the stack when it encounters the operand, calculate the two elements on the top of the stack when it encounters the operator, and then push the calculation result onto the stack again, and the final calculation The result is the value of the top element of the stack

Evaluating the reverse Polish expression is relatively simple, so the question is how to convert our中缀表达式转换为后缀表达式


Idea:

  • Push the operator onto the stack and put the operand directly into the result
  • When the priority of the operator at this moment is lower than the priority of the top element of the stack, it means that the result at this time can be calculated first, so the top element of the stack will be popped and placed in the result.
  • When a left parenthesis is encountered, it is pushed directly onto the stack, or the priority of the top element of the stack at this time is less than the priority of the current symbol. The same is pushed onto the stack.
  • When a right bracket is encountered, pop out all the symbols between the brackets and put them into the result.
  • Deal with the small details. When -it is a negative sign, not an operator, it needs to be processed. It appears at the beginning of the expression and appears at the beginning within parentheses.
#include<string>
#include<unordered_map>

#include"Stack.h"
int main()
{
    
    
	unordered_map<char, int>m;
	m.insert(make_pair('+', 1));
	m.insert(make_pair('-', 1));
	m.insert(make_pair('*', 2));
	m.insert(make_pair('/', 2));
	m.insert(make_pair('(', 3));
	m.insert(make_pair(')', 3));

	mystack::stack<char>sympol;
	queue<string>ans;

	string str;
	cin >> str;
	int n = str.size();
	int pre = 1;

	int i = 0, start = 0;
	while (i < n)
	{
    
    
		//处理前置符号
		if (pre == 1 && (str[i] == '+' || str[i] == '-'))
		{
    
    
			if (str[i] == '+')
				start++;
			i++;
		}

		//当前是数字
		while (i < n && str[i] >= '0' && str[i] <= '9')
			i++;
		if (i > start)
		{
    
    
			ans.push(str.substr(start, i - start));
			pre = 0;
		}

		//当前是符号
		if (m.find(str[i]) != m.end())
		{
    
    
			if (str[i] == '(')
				pre = 1;
			//当前没有符号
			if (sympol.empty())
				sympol.push(str[i]);

			//当前有符号
			else
			{
    
    

				if (str[i] == ')')
				{
    
    
					while (!sympol.empty() && sympol.top() != '(')
					{
    
    
						string tmp;
						tmp.push_back(sympol.top());
						sympol.pop();
						ans.push(tmp);
					}
					sympol.pop();

				}
				else if (str[i] == '(' || m[str[i]] > m[sympol.top()])
					sympol.push(str[i]);
				else
				{
    
    
					//while的原因是前面是* / ,而此时是+ -
					while (!sympol.empty() && sympol.top() != '(' && m[sympol.top()] >= m[str[i]])
					{
    
    
						string tmp;
						tmp.push_back(sympol.top());
						sympol.pop();
						ans.push(tmp);
					}
					sympol.push(str[i]);
				}
			}
		}
		i++;
		start = i;
	}

	while (!sympol.empty())
	{
    
    
		string tmp;
		tmp.push_back(sympol.top());
		sympol.pop();
		ans.push(tmp);
	}
	return 0;
}

When the infix expression at this time is converted into a postfix expression, it is easy to calculate. You only need to traverse it from left to right to complete the calculation.

	vector<string> popexp;
	while (!ans.empty())
	{
    
    
		string front = ans.front();
		popexp.push_back(front);
		cout << front << " ";
		ans.pop();
	}
	mystack::stack<int> num;
	for (int i = 0; i < popexp.size(); i++)
	{
    
    
		if (popexp[i] == "+" || popexp[i] == "-" || popexp[i] == "*" || popexp[i] == "/")
		{
    
    
			int b = num.top(); num.pop();
			int a = num.top(); num.pop();
			int ret = 0;
			if (popexp[i] == "+")
				ret = a + b;
			else if (popexp[i] == "-")
				ret = a - b;
			else if (popexp[i] == "*")
				ret = a * b;
			else
				ret = a / b;
			num.push(ret);
		}
		else
			num.push(stoi(popexp[i]));
	}

	cout <<endl<< num.top() << endl;

Insert image description here


(Summarize)

  • 1. First, we learned about the basic introduction of the STL library and stack through the introduction of the document, and learned that there is a template class in the library.
  • 2. Secondly, Daji introduced the basic knowledge about container adapters.
  • 3. Next, we briefly used stack and learned how to use it.
  • 4. Immediately afterwards, we manually implemented a stack, which was very simple compared to the previous stack implementation.
  • 5. Convert the infix expression to a reverse Polish expression and then evaluate it
    Insert image description here

Guess you like

Origin blog.csdn.net/2201_76062618/article/details/134067970