数据结构之简单栈

本文介绍了栈的基本概念及其在括号匹配和算术表达式求值中的应用。详细讲解了栈的结构设计,并提供了完整的C++代码实现。

时间:2014.04.02

地点:基地

------------------------------------------------------------

一、简述

  栈是一种非常有名的数据结构,常言道是一种后进先出(LIFO)的存储器,我们只能在一端即栈顶对数据进行插入和删除。即栈是一种后进先出的数据结构,从栈中取出数据项的顺序与将它们插入栈的顺序相反。

------------------------------------------------------------

二、栈的结构设计

  在C++中栈的规范常有栈的构造函数和5个成员函数。最重要的成员函数有:

1.push() 在栈顶添加一项

2.pop() 从栈顶删除(弹出)一项

3.top() 获取栈顶数据项,但不删除

没有函数能访问除栈顶数据项的任何其他数据项。如果需要访问非栈顶的数据项,程序必须从栈顶逐个移除数据项,直至达到所想访问的数据项。

另一方面,如果程序试图从一个空栈中移除数据,这个操作不可能实现,这种错误为栈下溢,为避免下溢,栈类提供成员函数empty()用于检测栈是否为空。

还有就是有些栈的容量有限,如果程序试图往一个满栈压入数据会发生栈上溢错误,于是栈类提供有成员函数size()

4.empty()  检测当前栈是否为空

5.size()     检测当前栈的大小

小结:

栈下溢:当试图从空栈中访问数据项时,发生下溢。

栈上溢:当试图往满栈中压入数据项时,发生上溢。

------------------------------------------------------------

三。栈的一个简单应用——括号匹配

括号匹配程序用于检测表达式的左右括号是否能正确匹配,当然我们还可以类似的用这种程序去做任何左右匹配的事情。

思路:算法很简单,我们将表达式字符串从左到右扫描每个字符,遇到左括号压栈,遇到右括号时相应的右括号出栈。如果所有的工作顺利,表达式结束时栈应该为空。

程序实现如下:

#include<stack>
#include<string>
#include<iostream>
using namespace std;
bool IsBalanceed(const string& expression)
//Postcondition: Check the given string.If the prenthesis is matched 
//then return ture,else return false.
//Library facilities used:stack,string
{
	//Meaningful names for constants
	const char kLeftPrenthesis = '(';
	const char kLeftPrenthesis = ')';

	stack<char> store;
	for (auto ch : expression)
	{
		if (ch == kLeftPrenthesis)
			store.push(ch);
		else if ((ch == kLeftPrenthesis) && (!store.empty()))
			store.pop();
		else if ((ch == kLeftPrenthesis) && (store.empty()))
			return false;
	}
	return store.empty();
}
int main()
{
	string input_str;
	cin>>input_str;
	cout <<boolalpha<< IsBalanceed(input_str)<<noboolalpha << endl;;
	return 0;
}
------------------------------------------------------------

四。栈的一个略简单应用——算术表达式求值

  这里要用到两个栈,一个是字符栈,用于存储操纵符,一个数栈,用处存储数字

在对有括号的算术表达式求值时,我们常按最内层表达式即括号最里的一对开始,当然这里的最里是相对的,如果最里的括号对存在两处,我们选最左边的一对首先执行计算操作,在程序算法中表现为:当第一次遇到右括号时,我们从数栈中弹出两个操作数和从符号栈中弹出一个符号进行算术操作的组合,当然这里要注意两个操作数的顺序,因为数字压入数栈时分先后,左操作数先压入栈中,右操作数后压入栈中,那么出来时先弹出的数是右操作数,后弹出的是左操作数。该步算术操作完成后将计算结果压入数栈中,继续去前行,重复执行上面操作,直到结束。最后栈中只有一个数字,这就是我们想要得最终结果。

#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<stack>
using namespace std;

double ReadAndEvaluate(istream& ins);
//Precondition:
//Postcondition:
//library facilities used:

void EvaluateStackTop(stack<double>& numbers, stack<char>& operations);
//Precondition:
//Postcondition:
//library facilities used:

int main()
{
	double answer;
	cout << "Please input a fully parenthesized arithemetic expression: " << endl;
	answer=ReadAndEvaluate(cin);
	cout << "That evaluates to " << answer << endl;
	return EXIT_SUCCESS;
}

double ReadAndEvaluate(istream& ins)
{
	const char kDecimal = '.';
	const char kRightParenthesis = ')';
	stack<double> numbers;
	stack<char> operations;
	double number;
	char symbol;
	while (ins&&ins.peek() != '\n')
	{
		if (isdigit(ins.peek()) || (ins.peek() == kDecimal))
		{
			ins >> number;
			numbers.push(number);
		}
		else if (strchr("+-*/", ins.peek()) != NULL)
		{
			ins >> symbol;
			operations.push(symbol);
		}
		else if (ins.peek() == kRightParenthesis)
		{
			ins.ignore();
			EvaluateStackTop(numbers, operations);
		}
		else
			ins.ignore();
	}
	return numbers.top();
}
void EvaluateStackTop(stack<double>& numbers, stack<char>& operations)
{
	double left_operand, right_operand;
	right_operand = numbers.top();
	numbers.pop();
	left_operand = numbers.top();
	numbers.pop();
	switch (operations.top())
	{
	case '+':numbers.push(left_operand + right_operand); break;
	case '-':numbers.push(left_operand - right_operand); break;
	case '*':numbers.push(left_operand*right_operand); break;
	case '/':numbers.push(left_operand / right_operand); break;
	}
	operations.pop();
}
------------------------------------------------------------

五、程序测试与分析

  通常应该用最可能出现问题的边界值去测试程序。比如只包含一个数字没有操作符的边界值等。另外应该注意除以0的错误除法操作。该算法时间复杂度为O(n),,是一个线性算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值