您的位置:首页 > 理论基础 > 数据结构算法

数据结构(1)——顺序栈的实现,以及括号匹配的应用

2014-07-26 08:07 507 查看
为什么从堆栈开始?因为我觉得线性部分比较简单的是堆栈和队列,用得也比较多,有不少人觉得链表才简单啊,其实链表简单吗?链表可以派生的东西反而很多,不是一时半会可以理解的,还记得在一篇微软的招聘心得回顾文上看到,微软的面试官就问他怎样用两个链表实现一个栈。当然,现在打乱顺序是因为早在大一就学过数据结构,现在只是更深入更多样的讨论,所以就不再在意一开始教学所用的结构,这不是新手教程。

废话不多说,开始堆栈的学习。

首先,堆栈是线性表的拓展——只能在一头进行修改,所以如果是用高级语言实现的话,可以直接继承LinearList然后进行派生,但是这种方法会产生效率问题,具体看到代码以及注释。

所以我们还是选择直接实现,即自定义一个Stack基类。
/*template<class T>
class Stack::private LinearList<T>{
//LIFO对象
//没有为Stack类定义析构函数,因此当Stack类型的对象被删除时,自动调用LinearList的析构函数
public:
Stack(int MaxStackSize = 10) :LinearList<T>(MaxStackSize) {}
bool IsEmpty() const{
return LinearList<T>::IsEmpty();
}
bool IsFull() const{
return (Length() == GetMaxSize());//可以在LinearList增加一个保护成员GetMaxSize(),
}
T Top() const{
if (IsEmpty()) throw OutOfBounds();
T x;
Find(Length(), x);
return x;
}
Stack<T>& Add(const T& x){
Insert(Length(), x);
return *this;
}
Stack<T>& Delete(T& x){
LinearList<T>::Delete(Length(), x);
return *this;
}
};
不幸的是,这类操作会但是一个效率问题。例如:
为了向堆栈中添加一个元素,首先要确定堆栈的长度length(),然后调用函数Insert()。而Insert函数首先必须判断插入操作是否会越界,然后需要付出一个for循环的开销来执行0个元素的移动
而操作符也必须要重载
所以可以把Stack定义成一个基类,而不是派生类
*/

template<class T>
class Stack{
//LIFO对象
public:
Stack(int MaxStackSize = 10);
~Stack(){ delete[] stack; }
bool IsEmpty() const { return top == -1; }
bool IsFull() const { return top == MaxTop; }
T Top() const;
Stack<T>& Add(const T& x);
Stack<T>& Delete(T& x);
private:
int top;//栈顶
int MaxTop;//最大的栈顶值
T *stack;//堆栈元素数组
};

template<class T>
Stack<T>::Stack(int MaxStackSize){
//Stack类构造函数
MaxTop = MaxStackSize - 1;
stack = new T[MaxStackSize];
top = -1;
}

template<class T>
T Stack<T>::Top() const{
//返回栈顶元素
if (IsEmpty()) throw OutOfBounds();
else return stack[top];
}

template<class T>
Stack<T>& Stack<T>::Add(const T& x){
//添加元素x
if (IsFull()) throw NoMem();
stack[++top] = x;
return *this;
}

template<class T>
Stack<T>& Stack<T>::Delete(T& x){
//删除元素x
if (IsEmpty()) throw OutOfBounds();
x = stack[top--];
return *this;
}

class OutOfBounds{
public:
OutOfBounds() {}
};

class NoMem{
public:
NoMem(){}
};
//使new引发NoMem异常而不是xalloc异常
void my_new_handler(){
throw NoMem();
}
std::new_handler Old_Handler_=std::set_new_handler(my_new_handler);
程序使用模板函数来定义,和以往的方法不同。说过了这是一次回顾、总结、拓展以及深入,所以和之前的定义不同是难免的。后面的章节还会有不同方法、不同定义的实现,卖关子在这里先。

接着就来实现括号匹配。括号匹配方法也很多,仅供参考。

#include<iostream>
#include<string.h>
#include<stdio.h>
#include"stack.h"
using std::cout;
using std::cin;
using std::endl;
const int MaxLength=100;//最大的字符串长度
void PrintMatchedPairs(char *expr){
//括号匹配
Stack<int> s(MaxLength);
int j,length=strlen(expr);
//从表达式中搜索(和)
for(int i=1;i<=length;i++){
if(expr[i-1]=='(') s.Add(i);
else if(expr[i-1]==')'){
try{s.Delete(j);
cout<<j<<' '<<i<<endl;}
catch(OutOfBounds){
cout<<"No match for right parenthesis at "<<i<<endl;}
}
}
//堆栈中所剩下的(都是未匹配的
while(!s.IsEmpty()){
s.Delete(j);
cout<<"No match for left parenthesis at "<<j<<endl;
}
}

void main(void){
char expr[MaxLength];
cout<<"Type an expression of length at most "<<MaxLength<<endl;
cin.getline(expr,MaxLength);
cout<<"The pairs of matching parentheses in"<<endl;
puts(expr);
cout<<"are"<<endl;
PrintMatchedPairs(expr);
}


因为这个程序不是太复杂,实现的图片就不放上来了(ps:CSDN的传图片功能让人捉急)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐