•顺序栈
只能从在一端进行插入和删除的线性表是栈
采用顺序存储的的栈就是顺序栈
typedef struct{
ElemType data[MaxSize]; //静态数组存放栈中的元素
int top; //栈顶指针,指示当前栈顶元素的位置(从0开始的数组下标)
}SqStack;
连续空间)
SqStack S;//声名一个顺序栈(为栈分配一块MaxSize*sizeof(ElemType)大小的连续空间)
1.初始化,判空与读取栈顶
//栈的初始化
void InitStack(SqStack &S)
{
S.top = -1; //置栈顶指针为-1,栈顶压入元素时从数组下标0开始
}
⋅ \cdot ⋅对栈本身进行操作,所以用引用传递
&s
,纯c语言用法的话,这里则需要用到指针
⋅ \cdot ⋅结构体访问用s.xxx
,如果是结构体指针则是s->xxx
通过判断栈顶指针的值来判断栈空
//栈的判空
bool StackEmpty(SqStack S)
{
if(S.top == -1){
return true;
}
else{
return false;
}
}
//读栈顶元素
bool GetTop(SqStack S, ElemType &x)
{
if (S.top == -1) {
return fales; //栈空
}
x = S.data[S.top]; //读栈顶元素
return true;
}
2.进栈和出栈
//进栈
bool Push(SqStack &S, ElemType e)
{
if (S.top == MaxSize - 1) {
return false; //栈满
}
S.top++; //栈顶指针自增1
S.data[S.top] = e; //更新栈顶指针指向的栈顶数据为e
/*
另一种写法
S.data[++S.top] = e;
等价于
S.top += 1;
S.data[S.top] = e;
*/
return true;
}
//出栈,返回值为x
bool Pop(SqStack &S, ElemType &x)
{
if (S.top == -1) {
return fales; //栈空
}
x = S.data[S.top]; //栈顶元素出栈
S.top--; //更新栈顶指针
/*
另一种写法
S.data[S.top--] = x;
等价于
x = S.data[S.top] = x;
S.top -= 1;
*/
return true;
}
3.共享栈
顺序栈的大小不可变,为了避免内存资源的浪费,提高存储空间的利用率,可以使用共享栈
即两个顺序栈共享一个一维数组空间
typedef struct {
ElemType data[MaxSize]; //静态数组存放栈中的元素
int top0; //0号栈的栈顶指针
int top1; //1号栈的栈顶指针
} ShStack;
//共享栈的初始化
S.top0 = -1;
S.top1 = MaxSize;
//共享栈判空
S.top0 == S.top1;
4.代码汇总
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MaxSize 10
#define ElemType int
typedef struct {
ElemType data[MaxSize]; //静态数组存放栈中的元素
int top; //栈顶指针,指示当前栈顶元素的位置(从0开始的数组下标)
} SqStack;
typedef struct {
ElemType data[MaxSize]; //静态数组存放栈中的元素
int top0; //0号栈的栈顶指针
int top1; //1号栈的栈顶指针
} ShStack;
//----------------------------------------------------------------------------
//栈的初始化
void InitStack(SqStack &S)
{
S.top = -1; //置栈顶指针为-1,栈顶压入元素时从数组下标0开始
/*
共享栈的初始化
S.top0 = -1;
S.top1 = MaxSize;
共享栈判空
S.top0 == S.top1;
*/
}
//栈的判空
bool StackEmpty(SqStack S)
{
if (S.top == -1) {
return true;
} else {
return false;
}
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//进栈
bool Push(SqStack &S, ElemType e)
{
if (S.top == MaxSize - 1) {
return false; //栈满
}
S.top++; //栈顶指针自增1
S.data[S.top] = e; //更新栈顶指针指向的栈顶数据为e
/*
另一种写法
S.data[++S.top] = e;
等价于
S.top += 1;
S.data[S.top] = e;
*/
return true;
}
//出栈,返回值为x
bool Pop(SqStack &S, ElemType &x)
{
if (S.top == -1) {
return false; //栈空
}
x = S.data[S.top]; //栈顶元素出栈
S.top--; //更新栈顶指针
/*
另一种写法
S.data[S.top--] = x;
等价于
x = S.data[S.top] = x;
S.top -= 1;
*/
return true;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//读栈顶元素
bool GetTop(SqStack S, ElemType &x)
{
if (S.top == -1) {
return false; //栈空
}
x = S.data[S.top]; //读栈顶元素
return true;
}
//----------------------------------------------------------------------------
•链栈
通常采用单链表实现,所有的操作都在单链表的表头进行
如果链栈不带头结点,则头指针指向的是栈顶元素
而链栈从代码结构上看是可以遍历或者读取元素的,但这影响了栈的后进先出原则。
//不带头结点的链栈
typedef struct LinkNode {
ElemType data;
struct LinkNode * next;
} LinkNode, *LiStack;
1.初始化,判空和读取栈顶
//链栈的初始化,不带头结点
void InitStack1(LiStack &S)
{
S = null; //链栈置空
}
//链栈的判空
bool StackEmpty1(LiStack S)
{
if (S == null) {
return ture;
} else {
return false;
}
}
//获取栈顶
bool GetTop1(LiStack S, ElemType &x)
{
if (S == null) {
return false; //栈空
}
x = S->data; //获取栈顶的数据
return true;
}
2.链栈的进栈与出栈
//进栈
bool Pop1(LiStack &S, ElemType e)
{
LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
if (s == null) {
return false; //分配新节点不成功
}
s->data = e; //分配入栈结点的数据域
s->next = S; //入栈结点的next指向原本的栈顶结点
S = s; //更新栈顶结点为s
return true;
}
bool Push1(LiStack &S, ElemType &x)
{
if (S == null) {
return false; //栈空
}
LinkNode* s = S; //s指向出栈结点
x = s->data;
S = S->next; //更新栈顶结点
free(s);
return true;
}
3.代码汇总
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MaxSize 10
#define ElemType int
#define bool int
//不带头结点的链栈
typedef struct LinkNode {
ElemType data;
struct LinkNode * next;
} LinkNode, *LiStack;
//----------------------------------------------------------------------------
//链栈的初始化
void InitStack1(LiStack &S)
{
S = null; //链栈置空
}
//链栈的判空
bool StackEmpty1(LiStack S)
{
if (S == null) {
return ture;
} else {
return false;
}
}
//获取栈顶
bool GetTop1(LiStack S, ElemType &x)
{
if (S == null) {
return false; //栈空
}
x = S->data; //获取栈顶的数据
return true;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//进栈
bool Pop1(LiStack &S, ElemType e)
{
LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
if (s == null) {
return false; //分配新节点不成功
}
s->data = e; //分配入栈结点的数据域
s->next = S; //入栈结点的next指向原本的栈顶结点
S = s; //更新栈顶结点为s
return true;
}
//出栈
bool Push1(LiStack &S, ElemType &x)
{
if (S == null) {
return false; //栈空
}
LinkNode* s = S; //s指向出栈结点
x = s->data;
S = S->next; //更新栈顶结点
free(s);
return true;
}
//----------------------------------------------------------------------------