栈的定义
栈是限定仅在表尾进行插入和删除的线性表。(后进先出)
我们把允许插入和删除的一段=端称为栈顶,另一端称为栈底。
首先,栈是一个线性表,栈的元素具有线性关系。栈特殊的地方在于它的插入和删除的位置有所限定,始终只在栈顶插入,最先插入的只能在栈底。
栈的插入操作叫进栈,栈的删除操作叫出栈。
栈的顺序存储结构的实现
typedef struct
{
int maxsize;
int* top;
int* base;
}SqStack;
maxsize代表栈的最大容量,top代表栈顶指针变量,base代表栈底的指针变量。
top为栈顶指针,top的初值指向栈底。每当插入一个元素时top加1,弹出一个元素时top减1。
我们也可以这样实现栈
typedef struct
{
int data[maxsize];
int top;
int stacksize;
}SqStack;
其中top用来标注栈顶的位置。
当空栈时top = -1。
创建一个栈
void init(SqStack* s, int n)
{
s->base = (int*)malloc(sizeof(int)*n);
if( !s->base )
{
exit(0);
}
s->maxsize = n;
s->top = s->base;
}
最开始时,栈顶就是栈底,此时top = base。
当top = base时,栈为空栈。当top = maxsize 时栈满。
入栈操作
void push(SqStack* s, int a)
{
if(s->top - s->base == s->maxsize)
{
printf("栈满!\n");
exit(0);
}
*s->top++ = a;
}
当top - base = maxsize时,说明栈满了,无法进栈。
也可以用realloc函数增加空间。
出栈操作
int pop(SqStack* s)
{
if(s->top == s->base)
{
printf("栈已空\n");
return;
}
return *--s->top;
}
出栈操作就是在栈顶取出数据,栈顶指针下移。
*--s->top先将top指针减一,再取出元素,即出栈。这里要注意top指向栈顶的位置是没有存储东西的,要取出的元素是栈顶下面的数据。
计算栈的当前容量
栈的当前容量就是元素的个数,只需要用top - base 即可求出当前元素个数。
注意:指针只能相减不能相加。
清空一个栈和销毁一个栈
清空一个栈就是将栈中的所有元素全部作废,因此我们只需要将s->top的值赋予
给s->base即可,清空以后一个栈变为空栈,但是空间结构不会改变。
销毁一个栈与清空不同,销毁栈需要把它占用的空间释放掉。
void CleanStack(SqStack* s)
{
s->top = s->base;
}
void DestroyStack(SqStack *s)
{
int i,len;
len = s->maxsize;
for( i = 0;i < len;i++)
{
free( s->base);
s->base++;
}
s->base = s->top = NULL;
s->maxsize = 0;
}
栈的链式存储结构的实现
typedef struct StackNode
{
ElemType data; //存放栈的数据
struct StackNode *next;
}StackNode,*LinkStackPtr;
typedef struct LinkStack
{
LinkStackPtr top; //top指针
int count; // 栈元素计数器
}
链栈的操作绝大多数都和单链表类似,只是在插入和删除上特殊一点。
进栈操作
Status Push(LinkStack *s, ElemType e)
{
LinkStackPtr p = (LinkStackPtr)malloc(sizeof(StackNode));
p->data = e;
p->next = s->top;
s->top = p;
s->count++;
return OK;
}
用s作为存储e的新结点。
出栈操作
Status Pop(LinkStack *s,ElemType *e)
{
LinkStackPtr p;
if( StackEmpty(*s) )
{
return ERROR;
}
*e = s->top->data;
p = s->top;
s->top = s->top->next;
free(p);
s->count--;
return OK;
}
用变量p来存储要删除的链栈结点,将栈顶指针下移一位,最后释放p。