众所周知,栈(stack)是限定仅在表尾进行插入或删除操作的线性表,其特点是后进先出
允许删除和插入的一端称为栈顶(top),另一端称为栈底(base)
根据这个特性,可以实现多种实际应用,本文跟大家分享十进制转换其他进制数和括号匹配检验的应用举例
栈的实现和表示
头文件、常量定义和栈的定义
#include<iostream>
using namespace std;
#define OK 1
#define ERROR 0
#define STACK_INIT_SIZE 100 //设置存储空间初始分配量为100
#define STACKINCREMENT 10 //设置存储空间分配增量为10
typedef int Status;
#define SElemType int
typedef struct {
SElemType* base;
SElemType* top;
int stacksize;
}SqStack; //栈的定义
创建空栈
Status InitStack(SqStack& S) //创建空栈
{
S.base = (SElemType*)malloc(STACK_INIT_SIZE * sizeof(SElemType));
if (!S.base) exit(1); //存储分配失败
S.top = S.base;
S.stacksize = STACK_INIT_SIZE;
return OK;
}
判断栈是否为空,是否已满
int StackEmpty(SqStack S) //判断栈是否为空
{
if (S.top == S.base) return 1; //为空
else return 0;
}
int StackFull(SqStack S) //判断栈是否满
{
if (S.top - S.base >= S.stacksize) return 1; //已满
else return 0;
}
入栈(即插入元素)
Status Push(SqStack& S, SElemType e) //入栈
{
if (S.top - S.base >= S.stacksize) //若栈满,增加存储空间
{
S.base = (SElemType*)realloc(S.base, (S.stacksize + STACKINCREMENT) * sizeof(SElemType));
if (!S.base) exit(1);
S.top = S.base + S.stacksize;
S.stacksize += STACKINCREMENT;
}
*S.top++ = e; //等价于 *S.top=e; S.top++;
return OK;
}
出栈(即删除元素)
Status Pop(SqStack& S,SElemType &e) //出栈,并用e返回删除值
{
if (S.top == S.base) return ERROR; //若为空栈,出错
e=*--S.top; //相当于e=*(S.top-1); --S.top;
return OK;
}
返回栈顶元素
Status GetTop(SqStack S, SElemType& e) //返回栈顶元素
{
if (S.base == S.top) return ERROR; //若为空栈,出错
e = *(S.top-1);
return 0;
}
此处说明,S.top指针是指向最上面一个元素上面的一个空间,是没有数据值的,如图:
对比入栈出栈和取栈顶元素
入栈时,对S.top先赋值,后自加
*S.top++ = e; //等价于 *S.top=e; S.top++;
取栈顶元素,即取(S.top-1)的值
e = *(S.top-1);
出栈时,先取栈顶元素,再自减
e=*--S.top; //相当于e=*(S.top-1); --S.top;
数制转换的思路(举例十进制转八进制)
由于十进制转其他进制数的方法中,计算顺序和输出顺序相反,故可以利用栈的“后进先出”的特点,来实现十进制向其他进制的转换。
思路如下:
- 初始化一个栈,输入一个十进制数
- 将十进制数除以8,把余数入栈
- 将商作为被除数,重复第一步,直到商为0
- 当商为0时,输出栈
void convert() //将十进制数转换为八进制数
{
int p,e;
SqStack S;
InitStack(S);
cin >> p;
while (p)
{
Push(S, p % 8);
p = p / 8;
}
while (!StackEmpty(S))
{
Pop(S, e);
cout << e;
}
cout << endl;
}
括号匹配检验
本函数只识别两种括号:"("、")"、"["、"]"
其他括号思路相同,以此类推
思路如下:
- 初始化一个栈,输入一个括号序列
- 依次对括号序列中的字符进行如下判断:
2.1 如果是左括号,则进栈,回到步骤2
2.2 如果是其他字符,则格式不正确。程序结束
2.3 如果是右括号,则取出栈顶元素判断:
-
2.3.1 若右括号与栈顶元素匹配,回到步骤2
-
2.3.2 若右括号与栈顶元素不匹配,则格式不正确。程序结束
3.判断栈是否为空栈,若为空,则括号序列格式正确,否则,格式错误
void match()
{
SqStack S;
InitStack(S);
char a[20];
int i = 0;
cin >> a;
while (a[i] != '\0')
{
if (a[i] == '(' || a[i] == '[')
{
Push(S, a[i]);
i++;
}
else if (a[i] == ')' || a[i] == ']')
{
SElemType e;
if (!StackEmpty(S))
{
Pop(S, e);
if ((a[i] == ')' && e == '(') || (a[i] == ']' && e == '[')) i++;
else { cout << "不匹配" << endl; return; }
}
else { cout << "不匹配" << endl; return; }
}
else { cout << "不匹配,请输入正确的括号" << endl; return; }
}
if (StackEmpty(S)) cout << "匹配" << endl;
else cout << "不匹配" << endl;
}
主函数
int main()
{
char a;
cout << " 1.十进制数转八进制数 2.括号匹配检验 0.退出" << endl;
while (1)
{
cout << "请输入想要执行的操作:";
cin >> a;
switch (a)
{
case '1': cout << "请输入十进制数:"; convert(); break;
case '2': cout << "请输入一组括号(英文括号“( ) [ ]”):"; match(); break;
case '0': exit(0); break;
default:cout << "请重新输入正确操作!" << endl; break;
}
}
return 0;
}
运行如下
对于主函数中的switch语句,我存在以下未解决的问题:
-
当a定义为字符型数据时,若误输多个字节的数据,则不会执行default,而是一个一个识别字符。
如图 -
当a定义为整型时,可输入多位数整型数据,但是输入字符数据时会直接跳出程序
如图 -
当a定义为字符串数组时,string类型使用于switch语句上转换定义相关较为复杂,还没有足够丰富的知识来解决
-
有人说我多虑了,不会出现这些情况,因为交互性中已经说明清楚了操作对应的数据,但是这些情况是实际存在的,还未解决,只怨学识不够,会继续学习!
我低头帮陌生人拾起掉落的书的时候,心里已经划过了整个四季