目录
栈,是仅限定在表尾进行插入或删除操作的线性表。因此,对栈来说,表尾端有其特殊含义,称为栈顶(top),相应的,表头段称为栈底(bottom)。不含元素的空表称为空栈。
假设栈S = {a1,a2,a3,......an},则称a1为栈底元素,an为栈顶元素。栈中的元素按a1,a2,a3,......,an的次序进栈,退栈的第一个元素应该为栈顶元素。换句话说,栈是一种先进后出(LIFO)的线性表。如图1所示:
栈同样有顺序存贮和链式存储,下面我们来看这两种结构。
顺序栈,即栈的的顺序存储结构是利用一组地址连续的存储单元依次存放自栈顶到栈顶的数据元素,同时附设指针top指示栈顶元素在顺序栈中的位置,通常我们将 top = 0 表示空栈。对于数组而言,我们在使用的时候必须为其分配一个固定的大小,但是栈在使用过程中并不能估计出其容量。一个较合理的办法是,先为栈分配一个基本容量,然后在应用过程中,当栈的空间不够时在进行扩容。对于向栈中添加元素,称之为入栈(push),从栈中删除元素,称之为出战(pop)。图2显示了其过程:
基本操作:
//构造一个空栈S
Status InitStack(SqStack &S);
//销毁栈S,S不在存在
Status DestroyStack(SqStack &S);
//把S置为空栈
Status ClearStack(SqStack &S);
//若S栈为空栈,则返回TRUE,否则返回FALSE
Status StackEmpty(SqStack S);
//若S栈为满,则返回TRUE,否则返回FALSE
Status StackFull(SqStack S);
//返回S的元素个数,即栈的长度
int StackLength(SqStack S);
//若栈不空,则用e返回S栈顶元素,并返回OK,否则返回ERROR
Status GetTop(SqStack S,SElemType &e);
//若站不满插入元素e为新的栈顶元素
Status Push(SqStack &S,SElemType e);
//扩容
Status Resize(SqStack S);
//若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK,否则返回ERROR
Status Pop(SqStack &S,SElemType &e);
//定义visit()
Status PrintfElement(SElemType e);
栈底到栈顶依次对栈中的每个元素调用visit().一点调用失败,则操作失败
Status ListTraverse(SqStack L,Status (*visit)(SElemType e));
代码实现:
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define STACK_INIT_SIZE 10 //栈初始化大小
#define STACKINCREAM 2 //扩容倍数
enum Status{OK = 1,ERROR = 0,TRUE = 1,FALSE = 0,OVERFLOW = -1};
typedef int SElemType;
typedef struct
{
SElemType *base; //栈底指针
SElemType top; //栈顶
int stacksize; //栈当前可用的最大容量
}SqStack;
//构造一个空栈S
Status InitStack(SqStack &S)
{
S.base = (SElemType*)malloc(STACK_INIT_SIZE * sizeof(SElemType));
if(NULL == S.base)
exit(OVERFLOW);
S.top = 0;
S.stacksize = STACK_INIT_SIZE;
return OK;
}
//销毁栈S,S不在存在
Status DestroyStack(SqStack &S)
{
free(S.base);
S.base = NULL;
S.stacksize = S.top = 0;
return OK;
}
//把S置为空栈
Status ClearStack(SqStack &S)
{
S.top = 0;
return OK;
}
//若S栈为空栈,则返回TRUE,否则返回FALSE
Status StackEmpty(SqStack S)
{
if(S.top == 0)
return TRUE;
else
return FALSE;
}
//若S栈为满,则返回TRUE,否则返回FALSE
Status StackFull(SqStack S)
{
if(S.top == STACK_INIT_SIZE)
return TRUE;
else
return FALSE;
}
//返回S的元素个数,即栈的长度
int StackLength(SqStack S)
{
return S.top;
}
//若栈不空,则用e返回S栈顶元素,并返回OK,否则返回ERROR
Status GetTop(SqStack S,SElemType &e)
{
if(StackEmpty(S))
return ERROR;
e = S.base[S.top - 1]; //获取元素
return OK;
}
//若站不满插入元素e为新的栈顶元素
Status Push(SqStack &S,SElemType e)
{
if(StackFull(S))
{
S.base = (SElemType*)realloc(S.base,(S.stacksize * STACKINCREAM) * sizeof(SElemType));
if(NULL == S.base)
exit(OVERFLOW);
S.top = S.stacksize;
S.stacksize *= STACKINCREAM;
}
S.base[S.top++] = e;
return OK;
}
//若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK,否则返回ERROR
Status Pop(SqStack &S,SElemType &e)
{
if(StackEmpty(S))
return ERROR;
e = S.base[--S.top];
return OK;
}
//定义visit()
Status PrintfElement(SElemType e)
{
printf("%d ",e);
return OK;
}
//从栈底到栈顶依次对栈中的每个元素调用visit().一点调用失败,则操作失败
Status ListTraverse(SqStack S,Status (*visit)(SElemType e))
{
int tmp = 0;
while(tmp < StackLength(S))
{
(*visit)(S.base[tmp++]);
}
printf("\n");
return OK;
}
main函数:
int main()
{
SqStack stack;
SElemType e;
InitStack(stack); //建立一个空栈
Push(stack,2); //入栈
Push(stack,4);
Push(stack,6);
Push(stack,8);
Push(stack,10);
Push(stack,1);
Push(stack,3);
Push(stack,5);
Push(stack,7);
Push(stack,9);
Push(stack,211);
Push(stack,719);
Push(stack,336);
Push(stack,170);
Push(stack,509);
ListTraverse(stack,PrintfElement);
printf("len = %d\n",StackLength(stack)); //获取栈长
Pop(stack,e); //出栈
Pop(stack,e);
ListTraverse(stack,PrintfElement); //遍历栈
printf("e = %d\n",e);
GetTop(stack,e); //获取栈顶元素
printf("Gettop = %d\n",e);
ClearStack(stack); //清空栈
Push(stack,3);
ListTraverse(stack,PrintfElement);
printf("len = %d\n",StackLength(stack));
ListTraverse(stack,PrintfElement);
DestroyStack(stack); //销毁栈
return 0;
}
所谓的链式栈其实只是一种特殊的线性表,只不过链式栈限制了线性表插入结点和删除结点的位置。对于线性表而言,我们知道,头插和头删的时间复杂度是O(1),而尾删和尾插操作的时间复杂度为O(n),那么对于栈顶的选择应该在哪里呢?
我们知道,栈是一种先进后出的线性数据结构,假设我们将栈顶放在链表的末尾,每次在链表的末尾进行插入和删除,那么其时间复杂度是O(n),这不是我们所期望的。而如果将栈顶放在链表的开头,每次在链表的开头进行插入和结尾操作,只需要根据头指针即可找到链表的首结点元素。因此我们一般将链式栈的出、入栈操作通过对链表进行头插和头删实现。这里不对链表相关操作进行详细说明,如需了解,可以参考我的另外一篇博客。
https://blog.youkuaiyun.com/FDk_LCL/article/details/89020533
基本操作:
//构造一个空栈S
Status InitStack(CLstack &S);
//销毁栈S,S不在存在
Status DestroyStack(CLstack &S);
//把S置为空栈
Status ClearStack(CLstack &S);
//若S栈为空栈,则返回TRUE,否则返回FALSE
Status StackEmpty(CLstack S);
//返回S的元素个数,即栈的长度
int StackLength(CLstack S);
//获取元素
pNode* GetNode(SElemType e);
//插入元素e为新的栈顶元素
Status Push(CLstack S,SElemType e);
//若栈不空,则删除S的栈顶元素,用e返回其值
Status Pop(CLstack S,SElemType &e);
//若栈不空,获取栈顶元素,用e返回其值
Status Gettop(CLstack S,SElemType &e);
//定义visit()
Status PrintfElement(SElemType e);
//依次对L的每个数据元素调用函数visit().一旦visit()失败,则操作失败
Status StackTraverse(CLstack L,Status (*visit)(SElemType e));
代码实现:
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
enum Status{OK = 1,ERROR = 0,TRUE = 1,FALSE = 0,OVERFLOW = -1};
typedef int SElemType;
typedef struct Node //定义结点类型
{
SElemType data; //数据域
struct Node *next; //结点域
}pNode;
typedef struct list
{
pNode *head;
}CLstack;
//构造一个空栈S
Status InitStack(CLstack &S)
{
S.head = (pNode*)malloc(sizeof(pNode)); //动态开辟结点空间
if(NULL == S.head)
exit(OVERFLOW); //开辟失败,返回
S.head->next = NULL;
return OK;
}
//销毁栈S,S不在存在
Status DestroyStack(CLstack &S)
{
pNode *pcur = S.head;
while(pcur != NULL)
{
S.head = S.head->next;
free(pcur);
pcur = S.head;
}
return OK;
}
//把S置为空栈
Status ClearStack(CLstack &S)
{
pNode *pcur = S.head->next;
while(pcur != NULL)
{
S.head->next = pcur->next;
free(pcur);
pcur = S.head->next;
}
return OK;
}
//若S栈为空栈,则返回TRUE,否则返回FALSE
Status StackEmpty(CLstack S)
{
if(S.head->next == NULL)
return FALSE;
else
return TRUE;
}
//返回S的元素个数,即栈的长度
int StackLength(CLstack S)
{
int count = 0; //定义一个计数器
pNode *pcur = S.head->next;
while(pcur != NULL)
{
count++;
pcur = pcur->next;
}
return count;
}
//若栈不空,则用e返回S栈顶元素,并返回OK,否则返回ERROR
//获取元素
pNode* GetNode(SElemType e)
{
pNode *pGet = (pNode*)malloc(sizeof(pNode));
if(NULL == pGet)
exit(OVERFLOW);
pGet->data = e;
pGet->next = NULL;
return pGet;
}
//插入元素e为新的栈顶元素
Status Push(CLstack S,SElemType e)
{
pNode *pGet = GetNode(e);
pGet->next = S.head->next;
S.head->next = pGet;
return OK;
}
//若栈不空,则删除S的栈顶元素,用e返回其值
Status Pop(CLstack S,SElemType &e)
{
if(!StackEmpty(S))
exit(OVERFLOW);
e = S.head->next->data;
S.head->next = S.head->next->next;
return OK;
}
//若栈不空,获取栈顶元素,用e返回其值
Status Gettop(CLstack S,SElemType &e)
{
if(!StackEmpty(S))
return ERROR;
e = S.head->next->data;
return OK;
}
//定义visit()
Status PrintfElement(SElemType e)
{
printf("%d ",e);
return OK;
}
//依次对L的每个数据元素调用函数visit().一旦visit()失败,则操作失败
Status StackTraverse(CLstack L,Status (*visit)(SElemType e))
{
pNode *pcur = L.head->next;
while(pcur != NULL)
{
(*visit)(pcur->data);
pcur = pcur->next;
}
printf("\n");
return OK;
}
main函数:
int main()
{
CLstack stack;
SElemType e;
InitStack(stack);
Push(stack,2);
Push(stack,4);
Push(stack,6);
Push(stack,8);
StackTraverse(stack,PrintfElement);
printf("len = %d\n",StackLength(stack));
Pop(stack,e);
printf("e = %d\n",e);
Gettop(stack,e);
printf("Gettop = %d\n",e);
StackTraverse(stack,PrintfElement);
DestroyStack(stack);
return 0;
}