栈和队列
栈
栈(Stack)是一种仅在表末进行插入和删除的线性表。对栈来说,表尾称为栈顶,表头称为栈底。不包含元素的空表称为空栈。
栈的ADT
//栈的ADT
ADT Stack{
数据对象:D={ai|ai ∈ Elemset , i=1,2,3...n,n>=0}
数据关系:R1={<ai-1,ai>|ai-1,ai∈D,i=2,3...n},约定an为为栈顶,a1为栈底
基本操作:
InitStack(&S)
操作结果:构造一个空的栈。
DestroyStack(&S)
初始条件:栈S已存在。
操作结果:销毁栈S的存储空间。
ClearStack(&S)
初始条件:栈S已存在。
操作结果:将S重置为空栈。
IsEmpty(S)
初始条件:栈S已存在。
操作结果:若S为空栈,返回True,否则返回false。
IsFull(S)
初始条件:栈S已存在。
操作结果:若S已满,返回True,否则返回false。
StackLength(S)
初始条件:栈S已存在。
操作结果:返回S中已经存放数据元素的个数。
GetTop(S,&e)
初始条件:栈S已存在。
操作结果:用e返回栈顶数据元素。
Push(&S,e)
初始条件:栈S已存在。
操作结果:将元素e压入栈中,成功则返回true,如果栈满打印错误信息并返回false。
Pop(&S,&e)
初始条件:栈S已存在。
操作结果:将栈顶元素出栈并赋值给e,成功则返回true,如果栈空打印错误信息并返回false。
StackTraverse(S)
初始条件:栈S已存在。
操作结果:从栈底到栈顶依次输出栈中的数据元素。
}
栈的表示和实现
这里对栈的实现使用顺序结构进行实现。
//栈的定义
#define MAXSIZE 100 //栈所能容纳的最多元素个数
using namespace std;
typedef int Elem; //栈内元素类型
typedef struct SqStack{
Elem *base; //栈底指针,指向分配的连续的数组空间
Elem *top; //栈顶指针,指向栈顶元素的后一个位置
int size; //栈的大小
}SqStack;
//元素的打印函数,用于输出Elem,对数据元素的访问进行封装
void PrintData(Elem x){
printf("%d",x);
}
栈的常用函数实现
//初始化栈,分配栈空间,并初始化栈顶指针
bool InitStack(SqStack &S){ //分配MAXSIZE+1个空间,栈顶指针指向栈顶元素的后一个位置
S.base=(Elem*)malloc(sizeof(Elem)*(MAXSIZE+1));
if(S.base==NULL) return false; //如果分配空间失败
S.top=S.base; //初始化栈顶指针
S.size=MAXSIZE;
return true;
}
//销毁栈,释放栈所占有的内存空间
void DestoryStack(SqStack &S){
free(S.base);
}
//清空栈,将S清除为空栈
void ClearStack(SqStack &S){
S.top=S.base; //惰性删除,直接将栈顶指针对齐到栈底
}
//判断栈空
bool IsEmpty(SqStack S){
return S.top==S.base; //如果栈顶和栈底相同,则是空栈
}
//判断栈满
bool IsFull(SqStack S){
return S.top-S.base==MAXSIZE; //如果栈顶这栈底的距离为MAXSIZE就是栈满
}
//返回栈的长度,即栈中现有的元素个数
int StackLength(SqStack S){
return S.top-S.base;
}
//读取栈顶元素,并用e返回
void GetTop(SqStack S,Elem &e){
if(IsEmpty(S)){ //如果栈空,打印错误信息并返回
printf("Stack is empty!\n");
return;
}
e=*(S.top-1); //top指向栈顶元素的后一个位置,因此-1 取元素
}
//入栈
bool Push(SqStack &S,Elem e){
if(IsFull(S)){ //如果栈满,无法入栈,打印错误信息
printf("Stack is full!\n");
return false;
}
*S.top++=e; //栈顶指针的位置进行填装,然后栈顶指针后移
return true;
}
//出栈
bool Pop(SqStack &S,Elem &e){
if(IsEmpty(S)){ //如果栈空,无法出栈,打印错误信息
printf("Stack is empty!\n");
return false;
}
e=*--S.top; //因为top指向栈顶元素的后一个位置,先将top减一,再读取栈顶的元素
}
//从栈底到栈顶依次输出栈中元素
void StackTraverse(SqStack S){
printf("栈中元素个数:%d,栈底到栈顶元素依次为:\n栈底 ",StackLength(S));
for(Elem *p=S.base;p!=S.top;p++){
PrintData(*p); putchar(' ');
}
printf("栈顶\n");
}
用于测试栈的main函数
int main(void){
Elem temp;
SqStack S;
printf("-------------------------------------\n");
printf("初始化栈,把0-25压入栈中.\n");
InitStack(S);
for(int i=0;i<=25;i++){
temp=i;
Push(S,temp);
}
StackTraverse(S);
printf("-------------------------------------\n");
printf("读取并打印栈顶元素:");
GetTop(S,temp);
PrintData(temp); putchar('\n');
printf("-------------------------------------\n");
printf("出栈并打印出栈元素:");
Pop(S,temp);
PrintData(temp); putchar('\n');
StackTraverse(S);
printf("-------------------------------------\n");
printf("空栈出栈测试:");
ClearStack(S);
Pop(S,temp);
printf("-------------------------------------\n");
printf("满栈入栈测试:");
for(int i=0;i<101;i++){
temp=i;
Push(S,temp);
}
printf("-------------------------------------\n");
return 0;
}
测试结果:
-------------------------------------
初始化栈,把0-25压入栈中.
栈中元素个数:26,栈底到栈顶元素依次为:
栈底 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 栈顶
-------------------------------------
读取并打印栈顶元素:25
-------------------------------------
出栈并打印出栈元素:25
栈中元素个数:25,栈底到栈顶元素依次为:
栈底 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 栈顶
-------------------------------------
空栈出栈测试:Stack is empty!
-------------------------------------
满栈入栈测试:Stack is full!
-------------------------------------
栈的应用
使用栈进行括号的匹配
一个算术表达式中包含
三种英文括号,编写一个算法来判别运算表达式中的三种括号是否匹配。() [] {}
//这里直接使用了C++的stl中的stack,为了使得代码更加简短,并且可以直接复制使用
//需要包含stack头文件
#include<iostream>
#include<stack>
#include<string>
using namespace std;
bool BracketCheck(string str){
stack<char> s;
int i=0;
while(i<str.size()){
if(s.empty()){
s.push(str[i++]); continue; //如果是[])))这种情况中间可能遇到栈空,所以加此特判
}
switch(str[i]){
case '{':
case '[':
case '(': s.push(str[i]); break; //左括号则入栈
case '}': if(s.top()!='{') return false; //如果是右括号则和栈顶元素进行匹配,如果不匹配返回false
s.pop();break; //如果匹配,则出栈并继续循环
case ']': if(s.top()!='[') return false;
s.pop();break;
case ')': if(s.top()!='(') return false;
s.pop();break;
default : break;
}
i++;
}
if(s.empty()) return true; //如果字符串遍历完毕后栈中没有剩余,则说明匹配
else return false; //如果有剩余,则说明不匹配
}
int main(void){
string str;
cout<<"请输入一串带括号的表达式,进行表达式括号匹配的检测(输入q 结束):";
while(1){
cin>>str;
if(str=="q") break;
if(BracketCheck(str)) cout<<"括号匹配!"<<endl;
else cout<<"括号不匹配!"<<endl;
cout<<"请继续输入要进行括号匹配检测的表达式(输入q 结束):";
}
cout<<"Bye!";
return 0;
}
运行可测试结果:
请输入一串带括号的表达式,进行表达式括号匹配的检测(输入q 结束):(){}[]
括号匹配!
请继续输入要进行括号匹配检测的表达式(输入q 结束):{{{}}}((([[[]]])))
括号匹配!
请继续输入要进行括号匹配检测的表达式(输入q 结束):{{()[]
括号不匹配!
请继续输入要进行括号匹配检测的表达式(输入q 结束):()[]]]
括号不匹配!
请继续输入要进行括号匹配检测的表达式(输入q 结束):(3+1)
括号匹配!
请继续输入要进行括号匹配检测的表达式(输入q 结束):(4+6]
括号不匹配!
请继续输入要进行括号匹配检测的表达式(输入q 结束):q
Bye!
栈的知识点补充
栈的性质
1.栈的出栈和入栈
由于栈的操作方式,如果已知入栈序列和出栈序列,则对于出栈序列来说,某个元素之前的只能是在其之前进栈的元素。
【例题】:
如果已知入栈序列是1,2,3,4,5...n,出栈序列为p1,p2,p3...pn;若p2=3,则p1可能是1和2,因为在3后边的元素不可能比3更早出栈。
2.进出栈的序列个数
n个不同的元素进栈,出栈序列的个数为:
Comments | NOTHING