① 栈是一种特殊的线性表,它只允许在固定的一端进行插入和删除元素的操作。
② 进行数据插入的删除和操作的一端,称为栈顶 ,另一端则称为 栈底 。
③ 栈中的元素遵守后进先出的原则,即 LIFO原则(Last In First Out)栈也称为后进先出表。
④栈的插入操作通常称为进栈或者入栈,栈的删除操作通常称为出栈或退栈。
栈的顺序存储结构称为顺序栈
声明顺序栈
typedef struct
{
ElemType data[MaxSize];
int top; //栈指针
} SqStack;
栈的链式存储结构称为链栈
声明链栈
typedef struct linknode
{
ElemType data; //数据域
struct linknode *next; //指针域
} LinkStNode;
设计顺序栈基本运算算法四要素:
1.栈空的条件:s->top==-1;
2.栈满的条件:s->top==MaxSize-1(data数组最大下标)
3.进栈操作:先将栈顶指针top加1,然后将元素e放在栈顶指针处
4.出栈操作:先将栈顶指针处的元素取出并赋给e,然后将栈顶指针减1
初始化栈
void InitStack(SqStack *&s)
{
s=(SqStack *)malloc(sizeof(SqStack));
s->top=-1;
}
该运算创建一个空栈,将s指向它,并将栈顶指针设置为-1。
本算法的时间复杂度为O(1)
销毁栈
void DestroyStack(SqStack *&s)
{
free(s);
}
该运算用free函数释放栈s占用的空间。
本算法的时间复杂度为O(1)
判断栈是否为空
bool StackEmpty(SqStack *s)
{
return(s->top==-1);
}
该运算判断栈是否为空,当s->top=-1时表示栈为空。
本算法的时间复杂度为O(1)
进栈操作
bool Push(SqStack *&s,ElemType e)
{
if (s->top==MaxSize-1) //栈满的情况,即栈上溢出
return false;
s->top++;
s->data[s->top]=e;
return true;
}
该运算插入一个数据元素,首先判断栈是否为已满,如果栈已满则返回 false,在栈不满的条件下先将栈顶指针增1,然后在该位置插入元素e,最后返回 true。
动画演示:
本算法的时间复杂度为O(1)
出栈操作
bool Pop(SqStack *&s,ElemType &e)
{
if (s->top==-1) //栈为空的情况,即栈下溢出
return false;
e=s->data[s->top];
s->top--;
return true;
}
该运算删除一个数据元素,首先判断栈是否为空,如果为空则返回false,在栈不为空的条件下先将栈顶元素赋给e,然后再将栈顶指针减1,最后返回 true。
动画演示:
本算法的时间复杂度为O(1)
取栈顶元素
bool GetTop(SqStack *s,ElemType &e)
{
if (s->top==-1) //栈为空的情况,即栈下溢出
return false;
e=s->data[s->top];
return true;
}
该运算在栈不为空的的条件下将栈顶元素赋给e并返回 true,如果栈为空则返回false。
本算法的时间复杂度为O(1)
设计链栈(带头结点)基本运算算法四要素:
1.栈空的条件:s->next==NULL
2.栈满的条件:由于只有内存溢出时才出现栈满,通常不考虑这样的情况,所以在链栈中可以看成不存在栈满
3.进栈操作:首先新建一个结点存放元素e(由p指向它),将结点p插入到头结点之后
4.出栈操作:取出首结点的值并将其删除
初始化栈
void InitStack(LinkStNode *&s)
{
s=(LinkStNode *)malloc(sizeof(LinkStNode));
s->next=NULL;
}
该运算创建一个空栈,就是创建链栈的头结点 并将其next域置为NULL。
本算法的时间复杂度为O(1)
销毁栈
void DestroyStack(LinkStNode *&s)
{
LinkStNode *p=s->next;
while (p!=NULL)
{
free(s);
s=p;
p=p->next;
}
free(s); //s指向尾结点,释放其空间
}
该运算释放链栈s占用的全部结点空间,和单链表的销毁算法相同。
本算法的时间复杂度为O(n)
判断栈是否为空
bool StackEmpty(LinkStNode *s)
{
return(s->next==NULL);
}
该运算判断栈是否为空,就是判断s->next=NULL是否成立。
本算法的时间复杂度为O(1)
进栈操作
void Push(LinkStNode *&s,ElemType e)
{ LinkStNode *p;
p=(LinkStNode *)malloc(sizeof(LinkStNode));
p->data=e; //新建元素e对应的结点p
p->next=s->next; //插入p结点作为开始结点
s->next=p;
}
首先新建一个结点,用来存放元素e(由指针p指向它),然后将其插入到头结点之后(此处类似于创建单链表时的头插法),最后返回true。
本算法的时间复杂度为O(1)
出栈操作
bool Pop(SqStack *&s,ElemType &e)
{
if (s->top==-1) //栈为空的情况,即栈下溢出
return false;
e=s->data[s->top];
s->top--;
return true;
}
首先判断栈是否为空,如果为空则返回false,在栈不为空的条件下将首结点的值赋给e(此处e为引用型参数),然后将其删除,最后返回true。
本算法的时间复杂度为O(1)
取栈顶元素
bool GetTop(SqStack *s,ElemType &e)
{
if (s->top==-1) //栈为空的情况,即栈下溢出
return false;
e=s->data[s->top];
return true;
}
首先判断栈是否为空,如果为空则返回false,在栈不为空的条件下将首结点的数据域赋给e(e为引用型参数),最后返回true。
本算法的时间复杂度为O(1)
#include
#include
#define MaxSize 100
typedef int ElemType;
typedef struct
{
ElemType data[MaxSize];
int top; //栈指针
} SqStack; //顺序栈类型
void InitStack(SqStack *&s)
{
s=(SqStack *)malloc(sizeof(SqStack));
s->top=-1;
}
void DestroyStack(SqStack *&s)
{
free(s);
}
bool StackEmpty(SqStack *s)
{
return(s->top==-1);
}
bool Push(SqStack *&s,ElemType e)
{
if (s->top==MaxSize-1) //栈满的情况,即栈上溢出
return false;
s->top++;
s->data[s->top]=e;
return true;
}
bool Pop(SqStack *&s,ElemType &e)
{
if (s->top==-1) //栈为空的情况,即栈下溢出
return false;
e=s->data[s->top];
s->top--;
return true;
}
bool GetTop(SqStack *s,ElemType &e)
{
if (s->top==-1) //栈为空的情况,即栈下溢出
return false;
e=s->data[s->top];
return true;
}
int main()
{
SqStack *s; //定义一个栈
InitStack(s); //初始化栈
ElemType e;
Push(s,1);
Push(s,2);
Push(s,3);
GetTop(s,e); // 取栈顶元素
printf("当前栈顶元素为:%d\n",e);
Pop(s,e);
printf("出栈元素为:%d\n",e);
printf("当前栈是否为空:%d\n",StackEmpty(s));
DestroyStack(s);
return 0;
}
#include
#include
typedef int ElemType;
typedef struct linknode
{
ElemType data; //数据域
struct linknode *next; //指针域
} LinkStNode; //链栈类型
void InitStack(LinkStNode *&s)
{
s=(LinkStNode *)malloc(sizeof(LinkStNode));
s->next=NULL;
}
void DestroyStack(LinkStNode *&s)
{
LinkStNode *p=s->next;
while (p!=NULL)
{
free(s);
s=p;
p=p->next;
}
free(s); //s指向尾结点,释放其空间
}
bool StackEmpty(LinkStNode *s)
{
return(s->next==NULL);
}
void Push(LinkStNode *&s,ElemType e)
{ LinkStNode *p;
p=(LinkStNode *)malloc(sizeof(LinkStNode));
p->data=e; //新建元素e对应的结点p
p->next=s->next; //插入p结点作为开始结点
s->next=p;
}
bool Pop(LinkStNode *&s,ElemType &e)
{ LinkStNode *p;
if (s->next==NULL) //栈空的情况
return false;
p=s->next; //p指向开始结点
e=p->data;
s->next=p->next; //删除p结点
free(p); //释放p结点
return true;
}
bool GetTop(LinkStNode *s,ElemType &e)
{ if (s->next==NULL) //栈空的情况
return false;
e=s->next->data;
return true;
}
int main()
{
LinkStNode *s; //定义一个栈
InitStack(s); //初始化栈
ElemType e;
Push(s,1); //进栈1
Push(s,2); //进栈2
Push(s,3); //进栈3
GetTop(s,e); // 取栈顶元素
printf("当前栈顶元素为:%d\n",e);
Pop(s,e);
printf("出栈元素为:%d\n",e);
printf("当前栈是否为空:%d\n",StackEmpty(s));
DestroyStack(s);
return 0;
}
参考资料
李春葆《数据结构教程》(第五版)