栈的定义
栈(stack)是限定于在表尾进行插入和删除操作的线性表
可以理解为后进先出,先进后出的数据结构
栈的基本操作
1.Push
将数据压入栈中,压出的数据成为新的栈顶
2.Pop
获取栈顶数据,并释放,原栈顶后一个元素成为新栈顶
![](https://i-blog.csdnimg.cn/blog_migrate/e0ec589dc084acb75a6f1722b012fd94.jpeg)
栈的分类
1.顺序存储结构栈
用一段内存作为栈的存储空间,top指向栈顶元素的下标
2.共享空间栈
两个类型的栈共享一段内存,适用于此消彼长型的数据情况。top1指向栈1的栈顶,top2指向栈2的栈顶,当top1与top2碰头则栈空间不足。
3.链栈
就是一个只允许在线性链表表头插入删除的线性链表top为指向链表节点的指针。
C实现
1.顺序结构栈
栈结构为
typedef struct item//普通栈
{
int buffer[MAX_SIZE];//这个其实可以动态分配
int top=-1;
}Stack;
MAX_SIZE为一个宏定义
Push操作
bool Push(Stack *L,int *arry,int lenth)
{
if (MAX_SIZE - L->top - 1<lenth)return 0;//看空间是否足够
for (int i = 0; i < lenth; i++)
{
L->top++;
L->buffer[L->top] = arry[i];
}
return 1;
}
该操作允许向栈中压入一组数据,会进行对栈空间进行计算,如果栈空间不够(MAX_SIZE-L->top-1)则返回0,压入成功返回1
Pop操作
bool Pop(Stack *L, int *e)
{
if (L->top == -1)return 0;
*e = L->buffer[L->top];
L->top--;
return 1;
}
弹出操作会先判断栈中是否有数据即栈顶知否指向-1,如果是则表示栈为空返回0,否则返回栈顶数据。
因为插入与弹出操作均未涉及到循环所以其时间复杂度为O(1)
2.共享空间栈
栈结构:
typedef struct date//共享空间栈
{
int buffer[MAX_SIZE];
int top1=-1;
int top2=MAX_SIZE;
}SqlStack;
top1指向数组的底部 top2指向数据的顶部 MAX_SIZE依然是对数组长度的宏定义
Push操作
bool Push(SqlStack *L,int *arry,int lenth,int Stacknum)//适用于两栈共享
{
if (L->top1 + lenth > L->top2)return 0;//没有存储空间了
if (Stacknum == 1)
{
for (int i = 0; i < lenth; i++)
{
L->top1++;
L->buffer[L->top1] = arry[i];
}
}
else if (Stacknum == 2)
{
for (int i = 0; i < lenth; i++)
{
L->top2--;
L->buffer[L->top2] = arry[i];
}
}
else return 0;
return 1;
}
该操作依然允许压入一组数据,并且需要指出压入栈1或者压入栈2,当top1与top2碰面则表示该栈空间已不足返回0,否则完成操作后返回1
Pop操作
bool Pop(SqlStack *L,int *date,int Stacknum)
{
if (L->top1 == -1 && L->top2 == MAX_SIZE)return 0;//栈中没有数据
if (Stacknum == 1)
{
*date = L->buffer[L->top1];
L->top1--;
}
else if (Stacknum == 2)
{
*date = L->buffer[L->top2];
L->top2++;
}
else return 0;
return 1;
}
弹出栈顶元素的数据,这里判断空栈的方式是top1=-1并且top2=MAX_SIZE
3.链栈
数据结构:
节点:
typedef struct obj
{
int num = 0;
obj*next = NULL;
}StackNode,*LinkStackPtr;
栈结构:
typedef struct element
{
LinkStackPtr top=NULL;
int count;
}LinkStack;//链栈
Push操作:
bool Push(LinkStack *L,int date)//新加入的元素会在顶部
{
LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StackNode));
s->num = date;
s->next = L->top;
L->top = s;
L->count++;
return 1;
}
该操作会先创建一个链节点s为其分配存储空间 s的向后指针next指向栈顶之后栈顶指针指向s,此时操作结束top指向s,s指向栈原栈顶元素
bool Pop(LinkStack *L,StackNode *e)
{
LinkStackPtr ptr;
if (L->top==NULL)return 0;
e->num = L->top->num;
ptr = L->top;
L->top = L->top->next;
free(ptr);
L->count--;
return 1;
}
该操作依然会先对链栈进行判断是否是空链栈,判断方式可以是判断count的值,也可以判断top指针是否为空
copy一个节点元素并将其复制给e所在地址的元素返回。