顺序栈的设计及运行
1. 顺序栈
栈是在顺序表和链表的基础上学习的另一种存储形式,是只能在表的一端(栈顶)进行插入和删除的线性表,也就是遵循先进后出的原则,它与线性表一样,仍然是一对一的关系,根据存储关系不同,可以分为顺序栈和链栈,这里我来演示一下顺序栈的C语言操作。
还是那句话,没有什么是操作一遍解决不了的,如果还有的话,那就再来一遍,嗯,请叫这句话为lanyan理论,哈哈嗝。
2. 代码部分
- 主函数(主函数没啥看的,理解一下我是怎么调用各种函数的操作就行)
#include"basic.h"
int main()
{
int choose = -1;
SElemType e; //定义一个结构体的元素e
SqStack S; //定义一个顺序栈的变量S
InitStack(S); //初始化顺序栈
cout << "本次服务共有以下内容:" << endl << 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 << "0. 退出" << endl << endl;
while (choose != 0) {
cout << "请选择您需要的服务:" << endl; //输入选择
do {
cin >> choose;
if (choose < 0 || choose>8)
cout << "您输入的信息不在本次服务之内,请重新输入:" << endl;
} while (choose < 0 || choose>8);
switch (choose)
{
case 1:
if (InitStack(S)) cout << "顺序栈初始化成功!" << endl << endl;
else cout << "顺序栈初始化失败!" << endl << endl;;
break;
case 2:
if (StackEmpty(S)) cout << "此顺序栈为空!" << endl << endl;
else cout << "此顺序栈不为空!" << endl << endl;
break;
case 3:
cout << "此时栈内共有" << StaticLength(S) << "个元素" << endl<<endl;
break;
case 4:
if (ClearStack(S)) cout << "清空顺序表成功" << endl << endl;
break;
case 5:
if (DestroyStack(S)) cout << "销毁顺序表成功" << endl << endl;
break;
case 6:
cout << "请依次输入姓名和学号" << endl;
cin >> e.name>> e.mumber;
if (Push(S, e)) cout << "该元素入栈成功" << endl << endl;
break;
case 7:
Pop(S, e);
cout << "您本次取出的元素为:" << endl;
cout << e.name << " " << e.mumber << endl<<endl;
break;
case 8:
GetTop(S, e);
cout << "您此时栈顶的元素为:" << endl;
cout << e.name << " " << e.mumber << endl << endl;
break;
default:break;
}
}
return 0;
}
- basic.h头文件(嗯,关键信息都在这里,敲黑板划重点了)
#pragma once
#include<iostream>
using namespace std;
#define OVERFLOW -2
#define OK 1
#define ERROR 0
#define MAXSIZE 100
typedef int Status;
typedef struct //定义一个的结构体
{
char name[30]; //姓名
char mumber[30]; //学号
}SElemType;
typedef struct //定义一个顺序栈的结构(封装体)
{
SElemType* base;
SElemType* top;
int stacksize;
}SqStack;
Status InitStack(SqStack& S) //1. 顺序栈的初始化
{
S.base = new SElemType[MAXSIZE];
if (!S.base) return OVERFLOW;
S.top = S.base;
S.stacksize = MAXSIZE;
return OK;
}
bool StackEmpty(SqStack S) //2. 判断顺序栈是否为空
{
if (S.top == S.base) return true;
else return false;
}
int StaticLength(SqStack S) //3. 判断顺序栈的长度
{
return S.top - S.base;
}
Status ClearStack(SqStack S) //4. 清空顺序栈
{
if (S.base) S.top = S.base;
return OK;
}
Status DestroyStack(SqStack& S) //5. 销毁顺序栈
{
if (S.base) {
delete S.base;
S.stacksize = 0;
S.base = S.top = NULL;
}
return OK;
}
Status Push(SqStack& S, SElemType e) //6. 顺序栈入栈
{
if (S.top - S.base == S.stacksize) //满了
return ERROR;
*S.top++ = e; //先赋值,再加
return OK;
}
Status Pop(SqStack& S, SElemType& e) //7. 顺序栈出栈
{
if (S.top == S.base) //栈空
return ERROR;
e = *--S.top;
return OK;
}
Status GetTop(SqStack S, SElemType e) //8. 取顺序栈顶元素
{
if (S.top == S.base) //栈空
return ERROR;
e = *(S.top - 1);
return OK;
}
3. 代码分析
1)主函数内容分析
- 主函数我主要用了while语句,它形成的作用是完成一个操作后程序不会退出,问你继续哪步操作,除非你按下0该程序才会结束,并显示一个万能提示:
当然这里需要设置一个信号量choose(注意看一下它是有初值的),判断choose是否为0,以便于随时退出程序。
- 一个有意思的地方在于我我弄了一个很贱的操作(嘿嘿嘿)
do {
cin >> choose;
if (choose < 0 || choose>8)
cout << "您输入的信息不在本次服务之内,请重新输入:" << endl;
} while (choose < 0 || choose>8);
emmm……,它的意思就是说如果你不选择我给你设定的那几个数,你就甭想从我这里过去,对,就是这么干,不过值得注意的是do-while语句可以用来写选择提示性语句,很好使,对了,while后边括号里是条件为真的判断(真的才能继续执行循环),我每次到这里总弄错,给你借鉴一下。
- 其他要注意的地方就是case里要写break,很容易忘,主函数就介绍这么多。
2)basic.h文件分析
- 定义一个结构体,这里就不多说了,不过你要是想继续扩展的话可以自愿添加元素,比如我这里只设定了姓名和学号两类:
typedef struct //定义一个的结构体
{
char name[30]; //姓名
char mumber[30]; //学号
}SElemType;
可能你要问为什么学号我也用char类型,呃,你问到我的痛处了。。。
开始我也设置的是int型,但最后运行程序的时候总是出现死循环,九牛二虎之力后才发现是这里溢出的原因,
如果我输入的学号是311608070508,嗯,毫无疑问,这都多大的数了,int放不下,而且我也不建议用unsigned int,以及long int,为什么呢?因为划不来:
- 学号不用参与数值计算,把它当做数值的话浪费空间和脑力;
- char型可以存放好多好多好多位学号,还不占用大面积存储空间;
所以,我果断选择了char number[30] (我特么就不信谁的学号有三十位数,超神学院的吧)
- 定义一个顺序栈
typedef struct //定义一个顺序栈的结构(封装体)
{
SElemType* base;
SElemType* top;
int stacksize;
}SqStack;
顺序栈定义很简单,就俩指针,一个指向顶端,一个指向底端,但要注意的是:top指的是栈顶元素之上的下标地址,
这个很好理解,如果base=0的话,那top=3,元素的个数就很容易求出来了:
stacksize=top-base;
- 接下来就是顺序栈的初始化、判断它是否为空、求长度、清空顺序栈、销毁顺序栈、顺序栈入栈、顺序栈出栈、取顺序栈顶元素,
是不是感觉妈呀,真多,你要是这么感觉的话,那我只能说:
确实不多,就不要吓自己咯,这些全是一个个函数而已,用的时候调用一下就行了。不过重点我给大家总结了一下几点:
- 当S.top == S.base,即两个指针相遇的时候,就意味着这个栈是空的
- 销毁顺序栈的时候用了一个if语句:
if (S.base) {
…
}
return OK;
为什么只写了S.base呢,if语句又该怎么判断呢?注意:S.base是一个指针,这里是判断S.base是否为 NULL
- 线性栈入栈和出栈的时候我分别用了*S.top++ = e;和e = *–S.top; ,注意看程序里我写的注释,到底是先加、减,还是先赋值
- 输入的时候注意,因为我的结构体有两项元素,所以在main函数里我的输入是这样的:
cin >> e.name>> e.mumber;
如果你扩展了结构体其他的元素,记得输入的时候也要输进去;
- 最后来一个完美的return 0 就告一段落了。
4. 运行结果
嗯,这才是世界应有的样子,就到这里,撂了。