Stack--栈

       

       最近复习到栈。这是一种小巧有用的数据结构,是功能特化的链表。一句话概括:LIFO(last in first out)

       

基本概念:


       实现方式:1)链式实现 2)顺序实现。

       链表的 "addLast" 和 " removeLast" 操作相当于栈的 "push" 和 "pop"操作。


1)链式实现的话,各节点占用的内存空间不一定连续,我前面的一篇博文:"LinkedList--链表" 的代码中,"addLast" 和 " removeLast" 函数就相当于栈的 "push" 和 "pop"函数,这里就不赘述了。


2)顺序实现的话,各节点占用的内存空间连续,下面的参考代码我用静态数组来实现。


(注:C/C++中的malloc/new既可以用于链式实现申请节点空间,也可以用于顺序实现申请节点空间。只不过,链式实现的时候,一次只申请一个节点空间(下次申请的节点空间就可能连不上了)顺序实现的时候,一次申请一段连续的节点空间。另外,不用malloc/new,直接使用静态数组的话,其效果相当于申请了一段连续的内存空间


栈的实现:

#ifndef STACK_H_
#define STACK_H_

#include <stdexcept>
#include <iostream>
using namespace std;

const int MAXN = 100;

template<typename T>
class Stack
{
private:
	T array[MAXN];
	int rear;
public:
	Stack();
	Stack(T list[], int len);
	void push_back(T element);
	T pop_back();
	T top();
	int getSize();
	void print();
};

template<typename T>
Stack<T>::Stack() {
	rear = 0;
}

template<typename T>
Stack<T>::Stack(T list[] , int len) {
	rear = 0;
	if(len <= 1 || len >= MAXN)
	{
		throw runtime_error("Index out of range");
	}
	for(int i = 0 ; i < len ; i ++)
		push_back(list[i]);
}

template<typename T>
void Stack<T>::push_back(T element) {
	array[rear++] = element;
}

template <typename T>
T Stack<T>::pop_back() {
	if(rear == 0)
		throw runtime_error("Index out of range");
	return array[--rear-1];
}

template <typename T>
T Stack<T>::top() {
	if(rear == 0)
		throw runtime_error("Index out of range");
	return array[rear-1];
}

template <typename T>
int Stack<T>::getSize() {
	return rear;
}

template <typename T>
void Stack<T>::print() {
	if(getSize() == 0)
	{
		cout << "Empty stack\n";
		return;
	}
	int i = 0;
	while(i<rear)
		cout << array[i++] << " ";
	cout << endl;
}

#endif


下面是栈的几个简单应用的代码:1. 括号匹配、2. 表达式求值


栈的应用:


括号匹配

/**************************************
 *
 * copyright:   ace_yom (Peizhen Zhang)
 * author:      ace_yom (Peizhen Zhang)
 * date:        2015-8-18
 * description: 链表实现
 * 
 **************************************/
#include <iostream>
#include <stack>
using namespace std;

stack<char> st;
string str;

int main() {
	int i = 0;
	cin >> str;
	while(i < str.length())
	{
		if(st.empty())
		{
			st.push(str[i]);
		}
		else
		{
			char ch = st.top();
			if((ch == '[' && str[i] == ']') || (ch == '(' && str[i] == ')'))
				st.pop();
			else
				st.push(str[i]);
		}
		if(!st.empty() && (st.top()==')'|| st.top()==']'))
			break;
		++ i;
	}
	cout << (st.empty() ? "Yes" : "No") << endl;
	return 0;
}


表达式求值

       表达式求值有两种问题,一种是后缀表达式求值,单栈就可以操作;一种为中序表达式求值,需要使用 “算法优先分析法” 来确定运算符的优先级,并且需要双栈。下面仅介绍第一种--后缀表达式求值。第二种问题--中序表达式求值,读者可以参考文献[1]。


后缀表达式,又称逆波兰表达式。逆波兰表达式可以表示出所有的表达式,且本身不带括号:

如 a-b-c,其逆波兰表达式为:ab-c-;((a+b)*c - d/e) -f,其逆波兰表达式为:ab+c*de/-f-


给定一个输入序列(初始化为后缀表达式,一个指针指向输入序列的),和栈(初始化为空), '@' 为取负号操作,它是一个单目运算符,用于本身就是负数的情况,和双目运算符 '-' 减号分开来。


算法如下所示:

1. 若输入序列的指针指向一个数字(变量名也表示一个数字),则将它压入栈。

2. 若输入序列的指针指向一个操作符:

    1. 若操作符为 ‘@’,则取出栈顶的数字,取反,再压栈。输入序列的指针往后移。

    2. 若操作符不是 '@',则取出栈顶的两个数字,做这个操作,然后把结果压入栈。输入序列的指针往后移。


用栈求后缀表达式:

/***********************************
 *
 * copyright:    ace_yom (Peizhen Zhang)
 * author:       ace_yom (Peizhen Zhang)
 * date:         2015-8-20
 * description:  栈求后缀表达式的值
 *
 **********************************/
#include <iostream>
#include <string>
#include <stack>
using namespace std;

string str;
stack<int> st;

//算法仅支持一位整数,因为重点在于“用栈求后缀表达式的值”
//至于多位整数、浮点数的情况,需要作一些小处理,读者可自行解决

int main() {
	cin >> str;
	bool tag = true;
	if(str[0] < '0' || str[0] > '9')
		tag = false;	
	else
	{
		int i = 0;
		int tmp1,tmp2;
		while(i<str.length())
		{
			char ch = str[i];
			if(ch >= '0' && ch <= '9')
			{
				st.push(int(str[i]-'0'));
				cout << int(str[i]-'0') << endl;
			}
			else
			{
				switch (ch)
				{
					case '@':
						tmp1 = st.top();
						st.pop();
						st.push(-1*tmp1);
						cout << "middle result: " << -1*tmp2<< endl;
						break;
					case '-':
						tmp1 = st.top();
						st.pop();
						tmp2 = st.top();
						st.pop();
						st.push(tmp2-tmp1);
						break;
					case '+':
						tmp1 = st.top();
						st.pop();
						tmp2 = st.top();
						st.pop();
						st.push(tmp2+tmp1);
						break;
					case '*':
						tmp1 = st.top();
						st.pop();
						tmp2 = st.top();
						st.pop();
						st.push(tmp2*tmp1);
						break;
					case '/':
						tmp1 = st.top();
						st.pop();
						tmp2 = st.top();
						st.pop();
						st.push(tmp2/tmp1);
						break;
					default:
						tag = false;
						break;
				}
			}
			i ++;
			if(tag == false)
				break;
		}
	}
	if(!tag)
		cout << "Invalid Expression !\n";
	else
	{
		cout << "The result is " << st.top() << endl;
		st.pop();
	}
	return 0;
}




References:

[1] 数据结构(C 语言版) 严蔚敏 吴伟民 编著--3.2.5 表达式求值

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值