目录
栈的实现
文件名 | 功能 |
---|---|
pubuse.h | 提供了常用的预处理宏、类型别名和标准库引用,如状态值和控制操作。 |
SqStackAlgo.h | 定义了Stack类,包括栈操作函数如初始化、插入/移除元素,以及用于表达式处理的运算符优先级和转后缀表达式等算法。 |
SqStackDef.h | 描述栈数据结构的定义,包括Stack类的组成部分(栈底指针、栈顶指针和大小等)。 |
SqStackUse.cpp | 用户界面接口,包含基本栈操作(创建、显示、操作元素)的函数实现,以及解析和计算数学表达式的功能。 |
程序整体功能:SqStackUse.cpp
实现了一个命令行界面,用户可以通过栈操作来管理字符数据,还能够解析和计算基于中缀表达式的数学计算。其他文件(pubuse.h
, SqStackAlgo.h
, 和 SqStackDef.h
)提供了核心数据结构和相关函数的支持。
这些文件构成了一个C++项目,由pubuse.h
提供预处理宏与库支持,SqStackAlgo.h
定义Stack类及其算法,SqStackDef.h
定义数据结构,而SqStackUse.cpp
则是用户驱动的栈操作和表达式处理程序实现。
项目获取
所有代码已经上传到CSDN,通过资源绑定功能,已经绑定本篇博客,有需要请自取,完整的VS2022项目,运行“数据结构-栈的实现.sln”即可在vs2022中打开(一般来说,版本无限制)
在我上传时,设置了0积分,可以免费获取,但不保证后续积分要求会不会变化(但放心,不会变成付费或会员专享资源),不过,还请尽快保存!
具体实现文件解析
pubuse.h
头文件
这段代码是pubuse.h
头文件,主要包括以下内容:
- 定义预处理器宏常量(如 TRUE/FALSE/OK/ERROR),用于简化状态值表示。
- 使用 C++ 标准类型别名:Status 和 Boolean,分别用于存储状态和布尔值,方便在函数返回类型和使用上。
#pragma once
特性,确保此头文件只被包含一次,避免多次定义。
文件中包含了 C++ 中常用的一些头文件,比如 <string>
、<iostream>
、<cstdlib>
、<conio.h>
等,它们分别提供了字符串处理、输入输出、内存管理、控制台输入输出等基础功能。
整体来看,这个文件旨在为后续的代码提供一些基本的类型定义、预处理变量以及必要的库引用,它可能是一个公共模块或者基础工具类的定义部分。
#include<string>
#include<ctype.h>
#include<malloc.h> /* malloc()等*/
#include<limits.h> /* INT_MAX 等*/
#include<stdio.h> /* EOF(=^Z 或F6),NULL */
#include<iostream>
#include<stdlib.h> /* atoi() */
#include<io.h> /* eof() */
#include<math.h>/* floor(),ceil(),abs() */
#include<process.h> /* exit() */
#include"conio.h"
#include <sstream>
using namespace std;
/* 函数结果状态代码*/
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
//#define OVERFLOW -2 因为在math. h 中已定义OVERFLOW 的值为3,故去掉此行
typedef int Status; /* Status 是函数的类型,其值是函数结果状态代码,如OK 等*/
typedef int Boolean; /* Boolean 是布尔类型,其值是TRUE 或FALSE */
#pragma once
SqStackDef.h
文件
这个SqStackDef.h
文件是用于定义一个名为SqStack
的数据结构,它表示一个栈(stack)的实现。栈是一种线性数据结构,遵循后进先出(LIFO,Last In, First Out)原则。
SElemType
是一个结构体别名,它包含两个元素:一个字符c
和一个双精度浮点数num
,这代表栈中的通用元素类型。SqStack
结构体包含了以下三个成员:base
:指向栈底元素的指针。top
:指向栈顶元素的指针。stacksize
:表示栈的当前大小(最多可以存储的元素数量),使用预定义的最大值MAXSIZE(这里是100)。
通过这个头文件,其他代码可以包含SqStack
类型并操作它们,比如创建、删除元素和检查栈是否为空等。pubuse.h
可能是另一个包含了公共函数声明的头文件,但在这个代码片段中没有直接用到。
#include"pubuse.h"
#define MAXSIZE 100
typedef struct
{
char c;
double num;
}SElemType;
typedef struct
{
SElemType* base;
SElemType* top;
int stacksize;
}SqStack;
SqStackAlgo.h
文件
SqStackAlgo.h
是一个 C++ 文件,定义了一个名为 SqStack 的自定义栈数据结构及其操作方法(如初始化、压入元素、弹出元素等)。其中还包括了辅助功能:
- 定义了状态枚举 Status,用于表示操作结果。
- 验证栈是否为空(StackEmpty)和检查栈顶是否有元素(IsEmpty)的函数。
- 计算栈的长度(StackLength)。
- 展示栈中所有元素的操作(ShowAll)。
- 一个函数 Priority_ss 来确定运算符的优先级。
- change_ss 函数负责把中缀表达式转换为后缀(也称逆波兰)表达式,涉及到符号处理和括号匹配。
- js_new_ss 函数接受一个后缀表达式,并计算其对应的数值结果。
整体来看,这个文件提供了一套完整的栈数据结构和算法来支持表达式的处理。
#include"SqStackDef.h"
//初始化
Status InitStack(SqStack& S) {
S.base = new SElemType[MAXSIZE];
if (!S.base) exit(OVERFLOW);
S.top = S.base;
S.stacksize = MAXSIZE;
return OK;
}
//入栈
Status Push(SqStack& S, SElemType e) {
if (S.top - S.base == S.stacksize) return ERROR;
*S.top++ = e;
return OK;
}
//出栈
Status Pop(SqStack& S, SElemType &e) {
if (S.top == S.base) return ERROR;
e = *--S.top;
return OK;
}
//取栈顶元素
SElemType GetTop(SqStack S) {
if (S.top != S.base) return *(S.top - 1);
}
//销毁栈
Status DestroyStack(SqStack &S) {
if(S.base) {
delete S.base;
S.stacksize = 0;
S.base = S.top = NULL;
}
return OK;
}
//置空栈
Status StackEmpty(SqStack& S) {
S.top = S.base;
return OK;
}
//判是否空栈
bool IsEmpty(SqStack S) {
return S.base == S.top;
}
//求栈的长度
int StackLength(SqStack S) {
return S.top - S.base;
}
//栈遍历
Status ShowAll(SqStack S) {
SElemType* p = S.base;
while (p != S.top)
{
cout << p->c << endl;
p++;
}
return OK;
}
// 获取运算符的优先级
int Priority_ss(char op) {
if (op == '*' || op == '/') return 2;
else if (op == '+' || op == '-') return 1;
else return 0; // '('优先级最低
}
// 将中缀表达式转换为后缀表达式
string change_ss(string ss) {
SqStack S; // 用于存储运算符的栈
SElemType e1; //弹出无用栈顶元素,过渡
InitStack(S);
string new_ss = ""; //后缀表达式
istringstream iss(ss);
string s1;
while (iss >> s1) {
if (isdigit(s1[0])) {
// 如果是数字,将数添加到后缀表达式中
new_ss += s1;
new_ss += " ";
}
else if (s1 == "(") {
// 如果是'(',直接入栈
SElemType e;
e.c = '(';
Push(S, e);
}
else if (s1 == ")") {
// 如果是')',将运算符栈中的运算符弹出并添加到后缀表达式中,直到遇到'('
while (!IsEmpty(S) && GetTop(S).c != '(') {
new_ss += GetTop(S).c;
new_ss += " ";
Pop(S, e1);
}
Pop(S, e1); // 弹出'('
}
else if (s1 == "+" || s1 == "-" || s1 == "*" || s1 == "/") {
// 如果是运算符,弹出优先级大于等于当前运算符的运算符,添加到后缀表达式中,并将当前运算符入栈
while (!IsEmpty(S) && Priority_ss(GetTop(S).c) >= Priority_ss(s1[0])) {
new_ss += GetTop(S).c;
new_ss += " ";
Pop(S, e1);
}
SElemType e;
e.c = s1[0];
Push(S, e);
}
else
{
return "false";
}
}
……完整代码,请下载本博客绑定的资源(请见谅)
SqStackUse.cpp
文件
SqStackUse.cpp
文件是一个C++程序,实现了栈(Stack)的一些基本操作。它包含了以下几个功能:
- ShowMenu():显示菜单,列出栈的基本操作选项。
- ExitEnter(): 清屏并暂停程序执行。
- main():
- 初始化栈(
case 1
):调用名为InitStack
的函数初始化栈。 - 检查栈是否已空并破坏(
case 2
):分别对应销毁栈的操作与检查。 - 判断栈是否为空(
case 3
)、是否只包含一个元素(case 4
),以及获取栈顶元素(case 6
)。 - 执行push(入栈)操作(
case 7
),接收用户输入的字符并将它们添加到栈中。 - 弹出并打印栈顶元素(
case 8
)。 - 显示全部栈元素(
case 9
)。 - 解析并计算数学表达式(
case 10
),调用change_ss
和js_new_ss
函数执行计算。 - 主循环控制,当选择等于0时退出。
- 初始化栈(
这个程序提供了一个用户接口,用于操作一个简单的字符栈数据结构,同时包含了一个字符串数学运算处理功能。
#include"SqStackAlgo.h"
void ShowMenu() {
cout << "========= 栈的实现及应用 =========" << endl;
cout << "1. 初始化(使用以下功能时,务必先初始化,除了算术运算)" << endl;
cout << "2. 销毁栈" << endl;
cout << "3. 置空栈" << endl;
cout << "4. 判断是否空栈" << endl;
cout << "5. 求栈的长度" << endl;
cout << "6. 取栈顶元素" << endl;
cout << "7. 入栈" << endl;
cout << "8. 出栈" << endl;
cout << "9. 栈遍历" << endl;
cout << "10. 算术运算" << endl;
cout << "0. 退出" << endl;
cout << "请输入你的选择:";
}
void ExitEnter() {
cout << "-------------------------------" << endl;
system("pause");
system("cls");
}
int main() {
SqStack S;
SElemType e;
int numF = 12; //菜单选项数量
int choice;
do {
ShowMenu();
cin >> choice;
while (choice < 0 || choice>numF || cin.fail())
{
system("cls");
cin.clear();
cin.ignore();
ShowMenu();
cin >> choice;
}
switch (choice) {
case 1: {
// 初始化
system("cls");
if (InitStack(S)) cout << "初始化成功" << endl;
else cout << "初始化失败" << endl;
ExitEnter();
break;
}
case 2: {
// 销毁栈
system("cls");
if (DestroyStack(S)) cout << "销毁栈成功" << endl;
else cout << "销毁栈失败" << endl;
ExitEnter();
break;
}
case 3: {
// 置空栈
system("cls");
if (StackEmpty(S)) cout << "置空栈成功" << endl;
else cout << "置空栈失败" << endl;
ExitEnter();
break;
}
case 4: {
// 判是否空栈
system("cls");
if (IsEmpty(S)) cout << "是空栈" << endl;
else cout << "不是空栈" << endl;
ExitEnter();
break;
}
case 5: {
// 求栈的长度
system("cls");
int i = StackLength(S);
cout << "栈的长度为:" << i << endl;
ExitEnter();
break;
}
case 6: {
// 取栈顶元素
system("cls");
if (!IsEmpty(S)) {
e = GetTop(S);
cout << "栈顶元素为:" << e.c << endl;
}
else
{
cout << "取取栈顶元素失败" << endl;
}
ExitEnter();
break;
}
case 7: {
// 入栈
system("cls");
cout << "入栈,输入char字符,回车入栈(输入n再回车退出)" << endl;
char in;
while (TRUE)
{
cout << "开始输入:";
cin >> in;
while (cin.fail())
{
cin.ignore();
cin.clear();
cout << "输入有误,重新输入:";
cin >> in;
}
if (in == 'n') break;
e.c = in;
Push(S, e);
}
ExitEnter();
break;
}
case 8: {
// 出栈
system("cls");
if (Pop(S, e) && !IsEmpty(S)) {
cout << "出栈成功" << endl;
cout << "出栈元素为:" << e.c << endl;
}
else cout << "栈空,出栈失败" << endl;
ExitEnter();
break;
}
case 9: {
// 栈遍历
system("cls");
if (ShowAll(S) && !IsEmpty(S))cout << "\n栈遍历成功" << endl;
else cout << "栈遍历失败" << endl;
ExitEnter();
break;
}
case 10: {
// 算术运算
system("cls");
cin.ignore();
string ss;
cout << "输入的算术表达式,数字和运算符用空格隔开,比如:100 + 2.5 - ( 7 - 1 * 2 ) / 2" << endl;
cout << "请输入(不支持负数):";
getline(cin, ss);
// 将中缀表达式转换为后缀表达式
string new_ss = change_ss(ss);
if (new_ss != "false") {
cout << "后缀表达式:" << new_ss << endl;
double result = js_new_ss(new_ss);
cout << "结果:" << result << endl;
}
else
{
cout << "算式输入有误" << endl;
}
ExitEnter();
break;
}
case 0: {
cout << "-------------------------------" << endl;
cout << "感谢使用,再见!" << endl;
break;
}
default:
system("cls");
cout << "输入无效,请重新选择!" << endl;
break;
}
} while (choice != 0);
return 0;
}
结语
希望你能通过本篇博客,更好理解数据结构——栈。
最后,使用愉快!