栈
栈(stack)是限定仅在表尾进行插入和删除操作的线性表。
允许插入和删除的一段称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。
栈又称为后进先出(Last In First Out)的线性表,简称LIFO结构。
栈的插入操作,叫作进栈,也称为压栈、入栈。
栈的删除操作,叫作出栈,也有的叫作弹栈。
栈的顺序存储结构
#include <stdlib.h>
#define MAXSIZE 5 /*存储空间初始分配量*/
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int SElemType;
typedef int Status; /*Status是函数的类型,其值是函数结果状态代码,如ok等*/
typedef int ElemType; /*ElemType 类型*/
/*
*栈的 【顺序存储结构】
*/
typedef struct
{
SElemType data[MAXSIZE];
int top; /*用于指向栈顶的指针*/
}SqStack;
C语言实现
初始化操作
/*
*【0】初始化栈 操作
*/
void iniStack(SqStack* s)
{
s->top=-1; //只需要将栈顶指针初始化为-1
}
进栈操作
/*
*【1】入栈操作
*操作结果:插入元素e为新的栈顶元素
*/
Status Push(SqStack* s, SElemType e)
{
if (s->top == MAXSIZE - 1) /*栈满*/
{
return ERROR;
}
s->top++; /*栈顶指针加1*/
s->data[s->top] = e; /*将新插入元素赋值给栈顶空间*/
// s->data[s->top++] = e ; 一条语句实现入栈
return OK;
}
出栈操作
/*
*【2】出栈操作
*操作结果:若栈不空,则删除 s 的栈顶,用 e 返回其值,并返回OK;否则返回ERROR
*/
Status Pop(SqStack* s, SElemType* e)
{
if (s->top == -1) /*栈空*/
{
return ERROR;
}
*e = s->data[s->top]; /*将要删除的栈顶元素赋值给e*/
s->top--; /*栈顶指针减1*/
//*e = s->data[s->top--] ; 一条语句实现出栈
return OK;
}
两栈共享空间
#include <stdlib.h>
#define MAXSIZE 5 /*存储空间初始分配量*/
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int SElemType;
typedef int Status; /*Status是函数的类型,其值是函数结果状态代码,如ok等*/
typedef int ElemType; /*ElemType 类型*/
/*
*两栈共享结构
*/
typedef struct
{
SElemType data[MAXSIZE];
int top1; /*栈1栈顶指针*/
int top2; /*栈2栈顶指针*/
}SqDoubleStack;
C语言实现
入栈操作
/*
*【1】入栈操作
*操作结果:插入元素e为新的栈顶元素
* 【除了要插入元素值之外,还需要一个判断是栈1还是栈2的栈好参数stackNumber】
*/
Status Push(SqDoubleStack* s, SElemType e, int stackNumber)
{
if (s->top1 + 1 == s->top2) /*栈满,不能再push新元素了*/
{
return ERROR;
}
if (stackNumber == 1) /*栈1有元素进栈*/
{
s->data[++s->top1] = e; /*栈1先 top1+1 后给数组元素赋值*/
}
else if (stackNumber == 2) /*栈2有元素进栈*/
{
s->data[--s->top2] = e; /*栈2先 top2-1 后给数组元素赋值*/
}
return OK;
}
出栈操作
/*
*【2】出栈操作
*操作结果:若栈不空,则删除 s 的栈顶,用 e 返回其值,并返回OK;否则返回ERROR
*/
Status Pop(SqDoubleStack* s, SElemType* e, int stackNumber)
{
if (stackNumber == 1)
{
if (s->top1 == -1)
return ERROR; /*说明栈1 已经是空栈,溢出*/
*e = s->data[s->top1--]; /*将 栈1 栈顶的元素出栈*/
}
else if (stackNumber == 2)
{
if (s->top2 == MAXSIZE)
return ERROR; /*说明栈2 已经是空栈,溢出*/
*e = s->data[s->top2++]; /*将 栈2 栈顶的元素出栈*/
}
return OK;
}
栈的链式存储结构
对于链栈来说,基本不存在满栈的情况,除非内存已经没有可以使用的空间,
如果真的发生。那此时的计算机操作系统已经面临死机崩溃的情况,而不是这个链表是否溢出的问题。
#include <stdlib.h>
#define MAXSIZE 5 /*存储空间初始分配量*/
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int SElemType;
typedef int Status; /*Status是函数的类型,其值是函数结果状态代码,如ok等*/
typedef int ElemType; /*ElemType 类型*/
/*
*链栈的结构代码
*/
typedef struct StackNode
{
SElemType data;
struct StackNode* next;
}StackNode, * LinkStackPtr;
typedef struct LinkStack
{
LinkStackPtr top;
int count;
}LinkStack;
C语言实现
入栈操作
/*
*【1】入栈操作
*操作结果:插入元素e为新的栈顶元素
*/
Status Push(LinkStack *S, SElemType e)
{
LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StackNode));
s->data = e;
s->next = S->top; /*把当前的栈顶元素赋值给新结点的直接后继,如图中 1 的操作*/
S->top = s; /*把新的结点s 赋值给栈顶指针,如图中 2 的操作*/
S->count++;
return OK;
}
出栈操作
/*
*【2】出栈操作
*操作结果:若栈不空,则删除 s 的栈顶元素,用 e 返回其值,并返回OK;否则返回ERROR
*/
Status Pop(LinkStack *S, SElemType *e)
{
LinkStackPtr p;
if (StackEmpty(*s))
{
return ERROR;
}
*e = S->top->data;
p = S->top; /*将栈顶结点赋值给p , 如图 3 操作*/
S->top = S->top->next; /*使得栈顶指针下移一位,指向后一结点, 如图 4 操作*/
free(p); /*释放结点 p */
S->count--;
return OK;
}
迭代与递归的区别
迭代:使用的是循环结构,不需要反复调用函数和占用额外的内存。
递归:使用的是选择结构,可以使程序的结构更清晰、更简洁、更容易让人理解,从而减少阅读代码时间,但是大量的递归会导致建立函数的副本,会消耗大量的时间和内存。
参考:
[1]大话数据结构/程杰著.——北京:清华大学出版社,2011.6