浏览器 “回退” 功能的实现,底层使用的就是栈存储结构。当你关闭页面 A 时,浏览器会将页面 A 入栈;同样,当你关闭页面 B 时,浏览器也会将 B入栈。因此,当你执行回退操作时,才会首先看到的是页面 B,然后是页面 A,这是栈中数据依次出栈的效果。
不仅如此,栈存储结构还可以帮我们检测代码中的括号匹配问题。多数编程语言都会用到括号(小括号、中括号和大括号),括号的错误使用(通常是丢右括号)会导致程序编译错误,而很多开发工具中都有检测代码是否有编辑错误的功能,其中就包含检测代码中的括号匹配问题,此功能的底层实现使用的就是栈结构。
同时,栈结构还可以实现数值的进制转换功能。例如,编写程序实现从十进制数自动转换成二进制数,就可以使用栈存储结构来实现。
1、栈(Stack)是一种线性存储结构,它具有如下特点:
(1)栈中的数据元素遵守“先进后出"(First In Last Out)的原则,简称FILO结构。
(2)限定只能在栈顶进行插入和删除操作。
2、栈的常用操作为:
(1)弹栈,通常命名为pop
(2)压栈,通常命名为push
(3)求栈的大小
(4)判断栈是否为空
(5)获取栈顶元素的值
3.使用标准库的栈时, 应包含相关头文件,在栈中应包含头文件: #include< stack > 。定义:stack< int > stk;
stk.empty(); //如果栈为空则返回true, 否则返回false;
stk.size(); //返回栈中元素的个数
stk.top(); //返回栈顶元素, 但不删除该元素
stk.pop(); //弹出栈顶元素, 但不返回其值
stk.push(); //将元素压入栈顶
顺序栈4要素:
栈空条件:top=-1
栈满条件:top=MaxSize-1
进栈e操作:top++; 将e放在top处
退栈操作:从top处取出元素e; top–;
3.在顺序栈中实现栈的基本运算算法。
(1)初始化栈initStack(&s)
建立一个新的空栈s,实际上是将栈顶指针指向-1即可。对应算法如下:
csharp void InitStack(SqStack *&s) { s=(SqStack *)malloc(sizeof(SqStack)); s->top=-1; }
2)销毁栈ClearStack(&s)
释放栈s占用的存储空间。对应算法如下:
void DestroyStack(SqStack *&s) { free(s); }
(3)判断栈是否为空StackEmpty(s)
栈S为空的条件是s->top==-1。对应算法如下:
bool StackEmpty(SqStack *s) { return(s->top==-1); }
(4)进栈Push(&s,e)
在栈不满的条件下,先将栈指针增1,然后在该位置上插入元素e。对应算法如下:
bool Push(SqStack *&s,ElemType e)
{
if (s->top==MaxSize-1) //栈满的情况,即栈上溢出
return false;
s->top++; //栈顶指针增1
s->data[s->top]=e; //元素e放在栈顶指针处
return true;
}
(5)出栈Pop(&s,&e)
在栈不为空的条件下,先将栈顶元素赋给e,然后将栈指针减1。对应算法如下:
bool Pop(SqStack *&s,ElemType &e)
{
if (s->top==-1) //栈为空的情况,即栈下溢出
return false;
e=s->data[s->top]; //取栈顶指针元素的元素
s->top--; //栈顶指针减1
return true;
}
6)取栈顶元素GetTop(s)
在栈不为空的条件下,将栈顶元素赋给e。对应算法如下:
bool GetTop(SqStack *s,ElemType &e)
{
if (s->top==-1) //栈为空的情况,即栈下溢出
return false;
e=s->data[s->top]; //取栈顶指针元素的元素
return true;
}
例:编写一个算法利用顺序栈判断一个字符串是否是对称串。所谓对称串是指从左向右读和从右向左读的序列相同。 解:对于字符串str,先将其所有元素进栈。然后从头开始扫描str,并出栈元素,将两者进行比较,若不相同则返回false。当str扫描完毕仍没有返回时返回true。实际上,从头开始扫描str是从左向右读,出栈序列是从右向左读,两者相等说明该串是对称串
bool symmetry(ElemType str[])
{
int i; ElemType e;
SqStack *st;
InitStack(st); //初始化栈
for (i=0;str[i]!='\0';i++) //将串所有元素进栈
Push(st,str[i]); //元素进栈
for (i=0;str[i]!='\0';i++)
{
Pop(st,e); //退栈元素e
if (str[i]!=e) //若e与当前串元素不同则不是对称串
{
DestroyStack(st);//销毁栈
return false;
}
}
DestroyStack(st); //销毁栈
return true;
}
例:编写一个算法判断输入的表达式中括号是否配对(假设只含有左、右圆括号)。
解:该算法在表达式括号配对时返回true,否则返回false。设置一个顺序栈St,扫描表达式exp,遇到左括号时进栈;遇到右括号时:若栈顶为左括号,则出栈,否则返回false。当表达式扫描完毕,栈为空时返回true;否则返回false。
bool Match(char exp[],int n)
{
int i=0; char e; bool match=true; SqStack *st;
InitStack(st); //初始化栈
while (i<n && match) //扫描exp中所有字符
{
if ( exp[i]=='(‘ ) //当前字符为左括号,将其进栈
Push(st,exp[i]);
else if (exp[i]==')') //当前字符为右括号
{
if (GetTop(st,e)==true)
{
if (e!='(') //栈顶元素不为'('时表示不匹配
match=false;
else
Pop(st,e); //将栈顶元素出栈
}
else match=false; //无法取栈顶元素时表示不匹配
}
i++; //继续处理其他字符
}
if (!StackEmpty(st)) //栈不空时表示不匹配
match=false;
DestroyStack(st); //销毁栈
return match;
}
例:括号配对
不能使用栈(15min,不太好想,mad,笔试那会儿就没想到!)
以下是我的想法,具体的过程如下:
(1)由于不能使用栈,将左括号定义为数值1,右括号定义为数值-1,存放到向量id(C++)或列表tmp (Python)中;
(2)初始化变量sum,用于判断总的求和结果是否等于0,若不等于0,则肯定不正确,若等于0,不一定正确;
(3)循环遍历输入的括号向量vec,判断当前括号属性的同时,进行累加求和,如果求和值小于等于-1,break(跳出循环);
(4)最后再检查sum是否等于0,此时若等于0,则为正确。
#include
#include
using namespace std;
bool isRight(vector<char> &vec)
{
vector<int> id(vec.size()); //用于存放左右括号的属性:左括号用1表示,右括号用-1表示
int sum = 0;
bool index = false;
if (vec.size() <= 1 || vec[0]!='(' || vec.size()%2!=0)
{
return index;
}
for (int i = 0; i < vec.size(); i++)
{
if (vec[i] == '(')
{
id.push_back(1);
sum = id[i] + sum;
}
else if (vec[i] == ')')
{
id.push_back(-1);
sum = id[i] + sum;
if (sum <= -1)
break;
}
}
if (sum == 0)
index = true;
return index;
}
int main()
{
//输入不定长的括号
vector<char> vec;
char tmpCh;
char t;
cout << "输入一串括号为:";
do{
cin >> tmpCh;
vec.push_back(tmpCh);
} while ((t = cin.get()) != '\n');
//调用isRight函数
bool myRes = isRight(vec);
cout << myRes << endl;
system("pause");
return 0;
}