2.05——栈
1. 栈的定义
栈(stack)是限定仅在表尾进行插入和删除操作的线性表。
我们把允许插入和删除的一端成为栈顶(top),另一端为栈底(bottom),不喊任何数据元素的栈成为空栈。栈又成为后进先出(Last In First Out)的线性表,简称LIFO结构。
首先它是一个线性表,也就是,栈元素具有线性关系,即前驱后继关系。只不过它是一种特殊的线性表而已。定义中硕士在线性表的表尾进行插入和删除操作,这里表尾是指栈顶,而不是栈底。它的特殊之处就在于限制了这个线性表的插入和删除位置,它时钟只在栈顶进行。这也就使得:栈底是固定的,最先进栈的只能在栈底。
2. 栈的顺序存储结构
既然是线性表的特例,那么栈的顺序存储其实也是线性表顺序存储的简化,我们简称为顺序栈。线性表是用数组来实现的,下标为0的一端作为栈底比较好,因为首元素都存在栈底,变化最小,所以让它作栈底。我们定义一个top变量来指示栈顶元素在数组中的位置,若存储栈的长度为stacksize,则栈顶位置top必须小于stacksize。当栈存在一个元素时,top等于0,因此通常把空栈的判定条件定为top等于-1。
3. 顺序栈的插入操作
对于栈的插入,即进栈操作,如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gE5GDAvO-1590541577775)(http://p3glgyim1.bkt.clouddn.com//img/clip1517989199.png)]
代码如下
int Push(Stack *s, DataType e)
{
if (s->top >= SIZE - 1)
{
return FAILURE;
}
s->data[++(s->top)] = e;
return SUCCESS;
}
4. 顺序栈的出栈操作
出栈操作Pop,代码如下:
int Pop(Stack *s, DataType *e)
{
if(s->top > -1)
{
*e = s->data[s->top];
s->top--;
return SUCCESS;
}
return FAILURE;
}
5. 栈的链式存储结构
栈的链式存储结构,简称链栈。把栈顶放在单链表的头部,通常也不需要头结点。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q0jDYG4a-1590541577777)(http://p3glgyim1.bkt.clouddn.com//img/clip1517987544.png)]
链栈的结构代码如下:
typedef struct node
{
DataType data;
struct node *next;
}Node;
typedef struct stack
{
Node *top;
int length;
}Stack;
6. 链栈的进栈操作
对于链栈的进栈Push操作,假设元素值为e的新结点是s,top为栈顶指针,示意图如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BfZjXerE-1590541577778)(http://p3glgyim1.bkt.clouddn.com//img/clip1517988055.png)]
代码如下:
int Push(Stack *s, DataType e)
{
if (NULL == s)
{
return FAILURE;
}
Node *p = (Node *)malloc(sizeof(Node));
p->data = e;
p->next = s->top;
s->top = p;
s->length++;
return SUCCESS;
}
7. 链栈的出栈操作
出栈Pop操作,假设变量p用来存储要删除的栈顶结点,就栈顶指针下移以为,最后释放p即可。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BZXQaBEO-1590541577779)(http://p3glgyim1.bkt.clouddn.com//img/clip1517988208.png)]
代码如下:
int Pop(Stack *s, DataType *e)
{
if(s->top == NULL)
{
return FAILURE;
}
*e = s->top->data;
Node *p = s->top;
s->top = s->top->next;
s->length--;
free(p);
return SUCCESS;
}
8. 递归的定义
在高级语言中,调用自己和其他函数并没有本质的不同。我们把一个直接调用自己或通过一系列的调用语句间接调用自己的函数,称作递归函数。每个递归定义必须至少有一个条件,满足时递归不在进行,即不在引用自身而是返回值退出。
9. 栈的作用
栈的引入简化了程序设计的问题,划分了不同关注层次,使得是靠范围缩小,更加聚焦于我们要解决的问题核心。繁殖,想数组等,因为要分散精力去考虑数组的下标增减等细节问题,反而掩盖了问题的本质。
10. 两栈共享空间
数组有两个端点,两个栈有两个栈底,让一个栈底为数组的始端,即下标为0,另一个栈为栈的末端,即下标为数组长度n-1处。这样,两个栈如果增加元素,就是两端点向中间延伸。这样的数据结构通常都是当两个栈的空间需求有相反关系时,也就是一个栈增长时另一个栈在缩短的情况。