c++数据结构→栈

栈结构简介

1.栈其实也是一种线性表,而线性表有两种结构,一种是物理上的线性,另一种是逻辑上的线性
2.准确的定义 : 栈是限定仅在表尾进行插入和删除操作的线性表
3.我们把语序删除和插入的一端称为栈顶,另一端称为栈底
4.栈又称为后进先出的线性表,简称LIFO结构(Last in First Out)

栈的相关基本操作
1.插入操作 :void push(type val);
2.删除操作 :void pop();
3.返回栈顶元素:type top();
4.判断是否为空:bool empty();
5.输出当前栈内元素的个数:int size();

下面是自己手动实现的一个模板类,包含了这些基本操作

template<class type>
class Stack {
private:
	struct Stack_node{
		type val;
		Stack_node* next = NULL;
		Stack_node* last = NULL;
	};
	int length;
	Stack_node* top;//栈顶元素的指针

public:
	Stack() {
		length = 0;
		Stack_node* head = new Stack_node;
		top = head;
	}//栈的初始化操作
	void push(type val);//栈的压入操作
	void pop();//栈的删除操作
	type first();//返回栈顶元素
	int size();//返回栈的长度
	bool empty();//判断栈是否为空的操作
};

template<class type>
void Stack<type>::push(type val) {
	Stack_node* node = new Stack_node;
	node->val = val;
	top->next = node;
	node->last = top;
	top = top->next;
	length++;
}

template<class type>
void Stack<type>::pop() {
	top = top->last;
	delete top->next;
	top->next = NULL;
	length--;
}

template<class type>
type Stack<type>::first() {
	return top->val;
}

template<class type>
int Stack<type>::size() {
	return length;
}

template<class type>
bool Stack<type>::empty() {
	if (length != 0)return true;
	else return false;
}

显然这是使用了逻辑上的线性,也就是链式结构

当然每次都这样实现栈实在是太麻烦了,c++的STL中给出了模板,可供直接使用

需要包含头文件< stack >,下面给出相关的操作

	stack<int>s;
	for (int i = 0; i < 10; i++) {
		s.push(i + 1);
	}
	cout << s.size() << endl;
	while (!s.empty()) {
		cout << s.top() << " ";
		s.pop();
	}
	cout << endl << s.size();
	运行结果 : 
	10
	10 9 8 7 6 5 4 3 2 1
	 0
应用举例 :

1.寻找栈中的最小元素
题目描述 :
现在有一个栈,你现在不停的在里面插入和删除元素( int ),而且我时不时的会问你,栈中的最小元素是多少
输入方式 :
第一行一个整数n,表示接下来的操作数。
接下来n行,每行一个指令,可能的指令如下:
1 num :表示压入元素 num
2 :表示删除栈顶元素
3 :表示输出当前栈内的最小值
输出方式 :
对于每次询问最小值的操作,单独输出一行。

示例 :

输入 : 			输出 :
17
1 20
3					20
1 10
3					10
1 15
1 17
3					10
2
2
1 9
1 11
3					9
2
3					9
2
2
3					20

1<= n <= 2*10^7
|num| <= 10^9
代码实现 :
由于数据较大,所以采用快速读写的方法

#include<iostream>
#include<stack>
#include<cstdio>
using namespace std;
namespace fast_IO {
	inline int read() {
		int x = 0, f = 1; char ch = getchar();
		while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
		while (isdigit(ch)) x = x * 10 + (ch ^ 48), ch = getchar();
		return x * f;
	}
	inline void write(int x) {
		if (x < 0) {
			putchar('-');
			x = -x;
		}
		if (x > 9) write(x / 10);
		putchar(x % 10 + '0');
	}
};
using namespace fast_IO;
//快速读写

int main() {
	stack<int>Stack_Data;//数据栈
	stack<int>Stack_Min;//较小值栈
	int n, temp, str;
	n = read();
	for (int i = 0; i < n; i++) {
		str = read();
		switch (str){
		case 1:
			temp = read();
			Stack_Data.push(temp);
			if (Stack_Min.empty()) {
				Stack_Min.push(temp);
			}
			else if (temp <= Stack_Min.top()) {
				Stack_Min.push(temp);
			}
			//向Min栈push数据的两个条件
			break;

		case 2:
			if (Stack_Data.top() == Stack_Min.top())Stack_Min.pop();
			//当满足这个条件的时候才Stack_Min.pop()
			Stack_Data.pop();
			//当pop时,Data栈是必须pop
			break;

		case 3:
			write(Stack_Min.top());
			putchar('\n');
			break;
		}
	}
	return 0;
}

实现思路:
建立一个Stack_Data来保存输入的数据,一个Stack_Min来保存最小值。
当Stack_Min为空时向里面push数据,或者,当向Stack_Data里面push数据的时候,将这个数据与Min的栈顶进行比较,如果小于或者等于该栈顶,则push。这样就保证了,Min栈顶是整个数据的最小值,而且输出的复杂度是O(1)

2.验证表达式
题目背景:
验证表达式有两种方式 :
第一种 : 只考虑优先级,即大括号{}应在最外层,接着是中括号[],然后是小括号(),尖括号<>应在最内层。应当注意的是,同级括号可以同时出现。
第二种 : 不考虑括号之间的优先级,括号的个数是否左右匹配
应当注意的是:无论哪一种匹配方式,只有相同的括号才可以匹配

输入方式:
第一行一个数字n,表示接下来要验证的表达式的个数
接下来n行,一行一个字符串和一个数字
要注意的是
字符串中不包含空格,仅包含数字、大小写字母、加(+)减(-)乘(*)除(/)取模(%)乘方(^)和四种括号;
数字表示检验标准:
1 表示你需要按照第一种标准检验;
2 表示你需要按照第二种标准检验;

输出方式:

输入:													输出:
6
{5+{4+{3*(2-(1*<<6-4>+<3-2>>))}}-9} 1						Yes
{5+{4+{3*(2-(1*<<6-4>+(3-2)>))}}-9} 1						No
{5+{4+{3*(2-(1*<<6-4>+(3-2)>))}}-9} 2						Yes
{5+{4+{3*(2-(1*<<6-4>+(3-2)>))}-9} 2						No
[1+(1+2]+3) 2												No
<([{[]}])> 2												Yes

代码实现:

#include <stack>
#include <string>
#include <iostream>
using namespace std;
char h[128];	//全局变量默认初始化为0
stack<int> s;	//定义一个栈用来验证表达式

bool check(string str, int opt) {
	while(!s.empty()) s.pop();//因为只有一个栈,所以每次用的时候都要清空这个栈
	for (int k = 0; k < str.length(); ++k) {
		int t = h[str[k]];
		//t > 0 表示是左括号
		if(t > 0) {
		//第一种方式验证表达式,满足该条件就判断为No
			if(opt == 1 && !s.empty() && t > s.top()) return false;
			s.push(t);
		}
		if(t < 0) {
		//右括号进入时没有左括号,就No
			if(s.empty()) return false;
		//括号不匹配就No
			if(t + s.top()) return false;
		//否则栈顶元素,即匹配的左括号弹出
			s.pop();
		}
	}
	//匹配结束后,如果是空栈,表明括号全部匹配
	if(s.empty()) return true;
	return false;
}

int main() {
	h['<'] = 1; h['>'] = -1;
	h['('] = 2; h[')'] = -2;
	h['['] = 3; h[']'] = -3;
	h['{'] = 4; h['}'] = -4;
	//将这些要匹配的括号一一赋值
	int n; cin >> n;
	while(n--) {
		string str; int opt;
		cin >> str >> opt;
		cout << (check(str, opt) ? "Yes" : "No") << endl;
	}
	return 0;
}

补充:

int a, b;
a = 1; b = -1;
if(a + b) cout<<"Yes"<<endl;
else cout<<"No"<<endl;

输出结果: No

原因:if(a + b)表示如果 a + b != 0 的话
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值