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

本文回顾了栈的基本概念及其在高级语言中的实现方式,并详细解释了如何使用栈来实现括号匹配算法。通过实例代码展示了栈的实用性和效率问题,并提供了具体的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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

首先,堆栈是线性表的拓展——只能在一头进行修改,所以如果是用高级语言实现的话,可以直接继承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:优快云的传图片功能让人捉急)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值