一、栈的定义
栈(stack)是限定仅在表位进行插入和删除操作的线性表。
我们把允许插入和删除的一端称为栈顶(top),另外一端称为栈底(bottom),不含任何元素的栈称为空栈。栈又被称为先进后出的线性表,简称LIFO结构。
理解栈的定义需要注意以下几点:
首先它是一个线性表,也就是说,栈元素具有线性关系,即前驱后继关系。只不过它是一种特殊的线性表而已。定义中说是在线性表的表尾进行插入和删除操作,这里表尾是指栈顶而不是栈底。
栈的特殊之处在于限制了这个线性表的插入和删除的位置,它始终只在栈顶进行,这也就使得:栈底是固定的,最先进栈的智能在栈底。
栈的插入操作,叫做进栈,也称为压栈,入栈。
栈的删除操作,叫作出栈,也称为弹栈。
二、进栈出栈的变化形式
首先大家要弄清楚一个问题:最先进栈的元素是不是就只能最后出栈呢?
答案是不一定的,要看什么情况。栈对线性表的插入和删除的位置进行了限制,并没有对元素的进出时间进行限制,也就是说,在不是所有元素都进栈的情况下,事先进去的元素也可以出栈,只要保证是栈顶元素出栈就可以。
三、栈的顺序存储结构及实现
3.1栈的顺序存储结构
栈是线性表的特例,那么栈的顺序存储结构其实也是线性表的顺序存储结构的简化,我们简称为顺序栈。
栈的结构定义C代码:
#include<stdio.h>
#define MAXSIZE 20
typedef int ElemType
typedef struct
{
Elemtype data[MAXSIZE];
int top; /*用于栈顶指针*/
}SqStack;
3.2栈的顺序存储结构——栈的初始化操作C实现
void Init_Stack(SqStack *S)
{
S->top=-1;
}
3.3栈的顺序存储结构——进栈操作C实现
Status Push(SqStack *S, ElemType e)
{
if(S->top == MAXSIZE -1) // 栈满
{
printf("栈已满,不能进行插入操作!!!");
return FALSE;
}
S->top++; //栈顶指针加1
S->data[S->top] = e; //将性插入的元素赋值给栈顶空间
return OK;
}
3.4栈的顺序存储结构——出栈操作C实现
Status Pop(SqStack *S, ElemType *e)
{
if(S->top == -1)
{
prinitf("此栈为空!\n");
return FALSE;
}
*e = S->data[S->top]; //取出出栈的元素
S->top--; //栈顶指针减1
return OK;
}
3.5栈的顺序存储结构——栈的遍历操作C实现
Status StackTravel(SqStack *S)
{
int i = 0;
for(i = 0 ; i <= S->top; i++)
{
printf(" %d",S->data[i]);
}
}
3.6栈的顺序存储结构——栈的各种操作实现C++
1.用C++自带的库实现:
/*
#include<stack>
s.empty() 如果栈为空返回true,否则返回false
s.size() 返回栈中元素的个数
s.pop() 删除栈顶元素但不返回其值
s.top() 返回栈顶的元素,但不删除该元素
s.push() 在栈顶压入新元素
*/
#include <iostream>
#include <stack>
using namespace std;
int main(void) {
stack<int> st;
int len=0;
st.push(4);
st.push(3);
st.push(2);
st.push(1);
st.push(0);
cout<<"size is "<<st.size()<<endl;
cout<<"top elem is "<<st.top()<<endl;
len=st.size();
for(int i=0;i<len;i++)
{
cout<<"After pop, The "<<i<<"th top elem is "<< st.top()<<endl;
st.pop();
}
return 0;
}
四、栈的链式存储结构及实现
前面写了顺序存储结构的C和C++实现,我们现在来看看栈的链式存储结构简称链栈。通常来说链栈是不需要头结点的。对于链栈来说,基本不存在栈满的情况,除非内存已经没有可以使用的空间,如果真的发生,那此时的计算机操作系统已经面临死机崩溃的情况,而不是这个链栈是否溢出的问题。
但对于空栈来说,链表原定义是头指针指向空,那么链栈的空其实就是top = NULL的时候。链栈的结构代码如下:
#include <stdio.h>
#include <stdlib.h>
#include<malloc.h>
#define false -1
#define true 1
typedef int bool;
typedef int ElemType ;
typedef struct StackNode{
ElemType data;
struct StackNode *Next;
}StackNode,*LinkStackPtr;
typedef struct LinkStack{
LinkStackPtr top;
int count;
}LinkStack;
4.1链栈——进栈操作
对于连栈的Push操作,假设元素值为e的新结点是s,top为栈顶指针,其代码如下所示:
//链式存储进栈操作
bool Push(LinkStack *S, ElemType e)
{
LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StackNode));
s->data = e;
s->Next = S->top; //当前的栈顶元素赋值给新结点的直接后继
S->top = s; //新的节点赋值给栈顶指针
S->count++;
return true;
}
4.2 连栈——出栈操作
假设变量p用来存储要删除的栈顶结点,将栈顶指针下移一位,最后释放p即可
bool Pop(LinkStack *S, ElemType *e)
{
LinkStackPtr P;
if(S->count == 0)
{
printf("栈为空!!\n");
return false;
}
*e = S->top->data;
P = S->top;
S->top = S->top->Next;
free(P);
S->count--;
}
4.3连栈——其它常见操作
//栈的初始化
bool InitStack(LinkStack *S)
{
S->top = (LinkStackPtr)malloc(sizeof(StackNode));
if(!S->top)
return false;
S->top = NULL;
S->count = 0;
return true;
}
//把栈置空
bool ClearStack(LinkStack *S)
{
LinkStackPtr p,q;
p = S->top;
while(p)
{
q = p ;
p = p->Next;
free(q);
}
S->count = 0;
return true;
}