文章目录
背景介绍
最近又看了一遍大话数据结构,在这里对第四章——栈进行一些总结。
栈
定义,栈是限定在表尾进行插入删除的线性表。其中进行插入删除操作的一端称作栈顶,另一端为栈底,无元素称为空栈。
栈的抽象数据类型:
栈的顺序存储结构
结构代码如下:
typedef int SElemType; /* SElemType类型根据实际情况而定,这里假设为int */
/* 顺序栈结构 */
typedef struct
{
SElemType data[MAXSIZE];
int top; /* 用于栈顶指针 */
}SqStack; //sq即sequence,表示顺序的意思,sqlist表示顺序表,SqStack表示顺序栈。
可以看出,顺序表(sqlist)跟顺序栈(SqStack)的存储结构区别不大,只是将SqList中length替换成top,其中top指向栈顶的元素,比如,当栈内存在一个元素时,即data[0]存在时,top为0,当栈内无元素时,top为-1.
另外,栈也需要通过初始化函数 InitStact ( *L ) ,建立一个空的栈L。
各类相应操作函数可在网上查询,这里不复赘言。
栈的小技巧——两栈共享空间
定义:简单来说,就是使用的两个栈共享同一个存储空间。
代码如下:
/* 两栈共享空间结构 */
typedef struct
{
SElemType data[MAXSIZE];
int top1; /* 栈1栈顶指针 */
int top2; /* 栈2栈顶指针 */
}SqDoubleStack;
可以看出两栈的结构相对于顺序栈SqStack只是多了一个top变量。
使用函数InitStack,初始化两栈栈
/* 构造一个空栈S */
Status InitStack(SqDoubleStack *S)
{
S->top1=-1;
S->top2=MAXSIZE;
return OK;
}
此时栈的情况如下:
在这里,n就是MAXSIZE,可以看出两栈的结构相对于顺序栈SqStack只是多了一个top2变量。在栈中,栈1与栈2实际上是同一个栈,共享同一个存储空间,即数组data( SElemType data[MAXSIZE];),只是人为的在概念上将它划分为两个栈(栈1与栈2)。
当元素进入栈1时, top1加一,当元素从栈1出去时,top1减一,与顺序栈SqStack中插入删除并无太大关系,当元素进入栈2时,top2减1,当元素从栈2出去时,top2加一,简单来说,就是栈1 以数组左端为栈底,向右端延伸,栈2以数组右端为栈底,向左端延伸。
附上插入的代码,便与加深对双栈的理解。
/* 插入元素e为新的栈顶元素 */
//stackNumber,说明插入的栈为1或2.
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;
}
栈满的判定条件:
容易发现,当top1+1=top2时,栈满,此时不能再插入元素。
栈的链式存储结构
结构代码如下:
/* 链栈结构 */
typedef struct StackNode
{
SElemType data;
struct StackNode *next;
}StackNode,*LinkStackPtr;
typedef struct
{
LinkStackPtr top;
int count;
}LinkStack;
可以看出,其实链栈与单链表LinkList并没有太大的区别,其中LinkStackPtr top就相当于单链表LinkList的头指针,只不过单链表LinkList头指针一般冠以链表名,而top指向的是尾结点,并且多了一个计数器count,形成一个链栈结构LinkStact。另外,插句题外话,顺序表SqList中有个length,也是类似作用。
链栈初始化:
/* 构造一个空栈S */
Status InitStack(LinkStack *S)
{
S->top = (LinkStackPtr)malloc(sizeof(StackNode));
if(!S->top)
return ERROR;
S->top=NULL;
S->count=0;
return OK;
}
另外值得注意的是,单链表中next指针指向的下一个结点,即后继,但链栈中next指针指向的结点,实际上是前一个元素,即前驱。
附上流程图一张
附上插入元素的函数代码,便与理解:
/* 插入元素e为新的栈顶元素 */
Status Push(LinkStack *S,SElemType e)
{
LinkStackPtr s=(LinkStackPtr)malloc(sizeof(StackNode));
s->data=e;
s->next=S->top; /* 把当前的栈顶元素赋值给新结点的直接后继,见图中① */
S->top=s; /* 将新的结点s赋值给栈顶指针,见图中② */
S->count++;
return OK;
}
其他各类相应操作函数可在网上查询,这里不复赘言。