对于栈来讲,理论上线性表的操作特性它都具备,可由于它的特殊性,所以在操作上会有一些变化,特别是插入和删除操作(可以理解为子弹压入和弹出)
1.首先我们来看栈的结构定义:
typedef struct
{
SElemType* data;
int top;//一直记录栈顶所用的游标
}SqStack;
对比顺序表我们这里定义的int类型的top变量用于记录栈顶下标
2.然后我们构造一个空栈:
int InitStack(SqStack* S)//构造一个空栈
{
S->data = new SElemType[MAXSIZE];
if (!(S->data))
return 0;
S->top = -1;//让栈的游标初始化
return 1;
}
和顺序表相同用new开辟空间,不同之处在于在构造空栈时要把top的值初始化为-1代表栈中没有数据(初始化为-1便于之后输入数据的同时自增top即可让top记录此时栈顶的下标)
3.为了便于调试我们之后需要输入数的情况都用系统产生的随机数,接下来我们向栈中输入数据:
void CreatStack(SqStack* S)//向栈传入数据
{
int i;
for (i = 0; i < CONTENT; i++)
{
S->data[i] = rand() % 100 + 1;//随机赋给栈1-100的CONTENT个数字
S->top++;
}
}
这里可以说说随机数的产生:首先我们要定义头文件#include<ctime>,为了让随机数真的是随机的我们要添加随机数种子srand((unsigned int)time(NULL));(目的是利用当前系统时间生成随机数),然后便可以通过rand()%100+1随机生成1-100的数字赋给栈
4.我们定义一个输出栈中数据的函数便于检验对栈的操作是否正确:
void PrintStack(SqStack* S)//输出栈中的数据
{
int i;
for (i = S->top; i >= 0; i--)
{
cout << S->data[i] << " ";
}
cout << endl;
}
由于栈底是首先输入到栈中的下标为0的数据,所以我们在输出时要从栈顶输出就要从游标top记录的下标开始输出到下标为0时的数据
5.接下来就是栈与顺序表很不相同的进栈操作:
void Push(SqStack* S, SElemType e)//进栈操作
{
if (S->top == MAXSIZE - 1)
{
cout << "栈已满" << endl;
return;
}
cout << "向栈中插入随机数" << e << endl;
S->data[++S->top] = e;
cout << "成功插入" << endl;
}
首先判断栈此时是否满了,如果游标top此时记录的是最后一个位置的下标则说明栈已经满了,就无法再插入数据。向栈中插入数据只能在栈顶插入,所以插入的时候只需将游标top指向当前栈顶的上方后再向其中输入数据,输入的数便成了新的栈顶(top不是指针,但用指针的说法比较好理解)
6.下来就是栈与顺序表很不相同的出栈操作:
void Pop(SqStack* S)//出栈操作
{
if (S->top == -1)
{
cout << "栈中已没有数据" << endl;
return;
}
cout << "出栈的数据为:" << S->data[S->top] << endl;
S->top--;
}
首先我们要判断此时栈是否为空,在定义空栈的时候我们便知道当游标top记录的下标为-1时便说明栈是空栈。出栈游标的变化就与进栈有些许不同我们在出栈时先将游标top指向的当前栈顶的数据记录下来,然后再将游标top向下指(实践如果不是为了检验,直接将游标top--,将游标向下指便完成了出栈操作)
ps:这里有一个个人理解,栈在出栈的时候不需要像链表一样删除数据后将空间释放,因为栈类似于数组,一开始储存空间是确定的,而链表是动态分配内存空间的,所以栈在进行删除操作时只需要将游标top向下指然后虽然top原来指向的栈顶内还有数据但由于top的限制,在对栈进行的操作都是无法作用于里面的数据的,在进行进栈操作时便会重新给其中的数据赋值,所以以前的那个值在游标top向下指时就已经是无效的状态了,而链表在删除了以后,重新添加结点时是重新开辟的空间,所以之前那个空间就属于是无效空间了,所以链表在删除时要进行释放。
接下来展示程序代码:
1.头文件FUNC.h
#pragma once
#include <iostream>
#include<ctime>
using namespace std;
typedef int SElemType;//要储存的数据类型
#define MAXSIZE 20
#define CONTENT 10
typedef struct
{
SElemType* data;
int top;//一直记录栈顶所用的游标
}SqStack;
int InitStack(SqStack* S);//构造一个空栈
void CreatStack(SqStack* S);//向栈传入数据
void PrintStack(SqStack* S);//输出栈中的数据
void Push(SqStack* S, SElemType e);//进栈操作
void Pop(SqStack* S);//出栈操作
2.源文件FUNC.cpp
#include"FUNC.h"
int InitStack(SqStack* S)//构造一个空栈
{
S->data = new SElemType[MAXSIZE];
if (!(S->data))
return 0;
S->top = -1;//让栈的游标初始化
return 1;
}
void CreatStack(SqStack* S)//向栈传入数据
{
int i;
for (i = 0; i < CONTENT; i++)
{
S->data[i] = rand() % 100 + 1;//随机赋给栈1-100的CONTENT个数字
S->top++;
}
}
void PrintStack(SqStack* S)//输出栈中的数据
{
int i;
for (i = S->top; i >= 0; i--)
{
cout << S->data[i] << " ";
}
cout << endl;
}
void Push(SqStack* S, SElemType e)//进栈操作
{
if (S->top == MAXSIZE - 1)
{
cout << "栈已满" << endl;
return;
}
cout << "向栈中插入随机数" << e << endl;
S->data[++S->top] = e;
cout << "成功插入" << endl;
}
void Pop(SqStack* S)//出栈操作
{
if (S->top == -1)
{
cout << "栈中已没有数据" << endl;
return;
}
cout << "出栈的数据为:" << S->data[S->top] << endl;
S->top--;
}
3.源文件text.cpp
#include"FUNC.h"
int main()
{
int n;
int DBD=1;
srand((unsigned int)time(NULL));//添加随机数种子
cout << "欢迎来到顺序栈储存结构" << endl;
SqStack S;//定义一个栈S
if (InitStack(&S) == 1)
{
cout << "空栈创建成功" << endl;
}
else
cout<< "空栈创建失败" << endl;
//向栈随机传入数据
CreatStack(&S);
while (DBD)
{
system("pause");
system("cls");
cout << "1.输出栈的内容 2.进栈操作 3.出栈操作 4.退出程序" << endl;
cin >> n;
switch (n)
{
case 1:
{
PrintStack(&S);
cout << "第一个数是栈顶" << endl;
break;
}
case 2:
{
SElemType e;//用于临时储存要进栈的数据
e = rand() % 100 + 1;//向e中随机传入一个1-100的数
Push(&S, e);
break;
}
case 3:
{
Pop(&S);
break;
}
case 4:
{
DBD = 0;
cout << "谢谢使用" << endl;
break;
}
default:
{
cout << "输入不合法" << endl;
break;
}
}
}
return 0;
}
顺序栈完成。