目录
前言
本篇文章介绍栈的基础知识,以及栈的实现,包括顺序表示和链式表示。
一、栈及其抽象数据类型
1.1 栈的基本概念
基本定义:限定只能在表的一端进行插入和删除操作的线性表(只能在栈顶操作)
逻辑结构: 一种特殊线性表,一对一关系
存储结构:顺序存储(顺序栈)或链式存储(链栈),常用顺序存储
运算规则:只能在栈顶运算,且访问结点时依照后进先出(LIFO)的原则
栈的插入操作通常称为进栈或入栈(push)
栈的删除操作通常称为退栈或出栈(pop)
可以将线性表旋转,则得到栈的示意图(图1.1)
1.2 栈的抽象数据类型
栈的抽象数据类定义如下:
ADT Stack
{
数据对象:D={ai|ai ∈ElemSet,i=1,2,3,...n,n >= 0}
数据关系:S={<ai-1,ai>|ai-1,ai∈D,i=2,...,n}
约定an为栈顶,a1为栈底
基本操作:
initStack(&S)
操作结果:构造一个空栈S
destoryStack(&S)
初始条件:栈S已存在
操作结果:栈S被销毁
isEmptyStack(S)
初始条件:栈S已存在
操作结果:若栈S为空栈,返回TRUE,否则返回FALSE
lengthStack(S)
初始条件:栈S已存在
操作结果:返回栈S的元素个数,即栈的长度
getTop(S,&e)
初始条件:栈S已存在且非空
操作结果:用e返回S的栈顶元素
clearStack(&S)
初始条件:栈S已存在
操作结果:将S清为空栈
pushStack(&S,e)
初始条件:栈S已存在
操作结果:插入元素e为新的栈顶元素
popStack(&S,&e)
初始条件:栈S已存在且非空
操作结果:删除S的栈顶元素,并用e返回被删除的元素
}ADT Stack
二、栈的实现
2.1 顺序表示
2.1.1 结构定义
用顺序的方式表示栈时,要分配一块连续的存储区域存放栈中的元素,用一个元素类型的指针指向栈顶位置。
顺序栈的类型定义如下
//定义转态码
#define SUCCESS 1
#define ERROR 0
#define OVERFLOW -1
//数据元素类型定义
typedef char SElemType;
//定义栈的最大的数据元素个数
#define MAXSIZE 100
//顺序栈类型定义
struct SeqStack {
SElemType* base; //栈底指针
SElemType* top; //栈顶指针
int stackSize; //栈可用最大容量
};
//结点结构类型
typedef struct SeqStack SeqStack;
//定义栈的结点指针类型
typedef struct SeqStack* PSeqStack;
利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素。栈底一般在低地址
top指针,指示栈顶元素在顺序栈中的位置
base指针,指针栈底元素在顺序栈中的位置
用stackSize表示栈可使用的最大容量
为了方便操作,通常top指示真正的栈顶元素之上的位置,如图2.1
假设stackSize=4,那么顺序栈的动态示意图如下(图2.2)
空栈:base == top 是空栈的判断
满栈:(top-base) == stackSize 是满栈的判断
其中top-base为指针操作,两个指针相减,得到数据元素个数。
满栈的处理方法:
- 报错,返回操作系统(常用)
- 分配更大的空间,将原内容移入新栈(不常用,因为当数据元素个数过多时,移动操作耗时)
使用数组作为顺序栈存储方式的特点:简单、方便、但易产生溢出(数组大小固定)
上溢(overflow):栈已满,执行进栈操作
下溢(underflow):栈已空,执行出栈操作
注意:上溢是一种错误,使问题无法进行处理;而下溢一般认为是一种结束条件,即问题处理介绍
2.1.2 基本操作的实现
-
顺序栈的初始化
step1 申请一块连续的内存空间,大小为MAXSIZE*sizeof(SElemType)
step2 将base和top指针指向这块空间的初始位置,stackSize设置为MAXSIZE//4.1 顺序栈的初始化(构造一个空栈) void initSeqStack(PSeqStack stack) { assert(stack); stack->base = (SElemType*)malloc(sizeof(SElemType) * MAXSIZE); if (NULL == stack->base) { printf("malloc fail!\n"); exit(OVERFLOW); } stack->top = stack->base; //表示空栈 stack->stackSize = MAXSIZE; }
-
顺序栈的销毁
释放动态申请的内存空间//4.2 顺序栈的销毁 void destorySeqStack(PSeqStack stack) { assert(stack); free(stack->base); stack->base = NULL; stack->top = NULL; stack->stackSize = 0; }
-
顺序栈入栈
step1 判断栈是否为满栈
step2 入栈//4.6 顺序栈入栈 //栈满,则返回ERROR //栈不满,则将数据元素e插入到栈顶 int pushSeqStack(PSeqStack stack, SElemType e) { assert(stack); if ((stack->top - stack->base) == stack->stackSize) //判断满栈 return ERROR; *(stack->top++) = e; // *(stack->top) = e; stack->top = stack->top+1; return SUCCESS; }
-
顺序栈出栈
step1 判断是否为空栈
step2 出栈//4.7 顺序栈出栈 //栈空,则返回ERROR //栈不空,则将栈顶元素删除 int popSeqStack(PSeqStack stack, SElemType* e) { assert(stack); if (stack->top == stack->base) //判断空栈 return ERROR; *e = *(--stack->top); //stack->top = stack-top -1; *(stack->top); return SUCCESS; }
-
获取栈顶元素
step1 判断是否为空栈
step2 获取栈顶元素//4.8 获取栈顶元素 //获取成功 返回SUCCESS //获取失败 返回ERROR int getSElem(PSeqStack stack,SElemType* e) { assert(stack); if (stack->top == stack->base) //判断是否为空栈 return ERROR; *e = *(stack->top - 1); return SUCCESS; }
2.2 链式表示
2.2.1 结构定义
实现栈的链式存储,使用不带头结点的单链表
链栈的类型定义如下:
//栈的链式存储
//不带头结点
#define SUCCESS 1
#define ERROR 0
#define OVERFLOW -1
//数据元素类型定义
typedef char SElemType;
struct StackNode {
SElemType data;
struct StackNode* next;
};
//结点结构类型
typedef struct StackNode StackNode;
//定义结点指针类型
typedef StackNode* PStackNode;
//定义链栈类型
typedef StackNode* LinkStack;
由于使用不带头结点的单链表,当头指针为NULL时,则表示空栈
链栈的示意图如下(图2.3)
2.2.2 基本操作的实现
-
链栈的初始化
//5.1 链栈的初始化 //不带头结点 //头指针为空,则为空栈 void initLinkStack(LinkStack* stack) { assert(stack); *stack = NULL; }
-
销毁链栈
//5.2 链栈的销毁 void destoryLinkStack(LinkStack* stack) { assert(stack); PStackNode p = *stack; while (p) { PStackNode q = p->next; free(p); p = q; } *stack = NULL; }
-
链栈的入栈
step1 申请结点空间
step2 将结点插入栈顶,修改头指针的指向(移动栈顶指针)//5.4 链栈的入栈 int pushLinkStack(LinkStack* stack,SElemType e) { assert(stack); //新建结点 PStackNode newNode = (PStackNode)malloc(sizeof(StackNode)); if (NULL == newNode) { printf("malloc fail!\n"); return ERROR; } newNode->data = e; newNode->next = *stack; *stack = newNode; return SUCCESS; }
-
链栈的出栈
step1 释放结点空间
step2 修改头指针指向,删除结点//5.5 链栈的出栈 int popLinkStack(LinkStack* stack, SElemType* e) { assert(stack); if (NULL == *stack) //判断是否为空栈 return ERROR; *e = (*stack)->data; PStackNode p = (*stack); *stack = (*stack)->next; free(p); return SUCCESS; }
-
获取栈顶元素
//5.6 获取栈顶元素 int getSElemLinkStack(LinkStack stack, SElemType* e) { if (NULL == stack) //判断是否为空栈 return ERROR; *e = stack->data; return SUCCESS; }