什么是栈
**定义:**是线性表的子集,一种特殊的线性表
一般的线性表的插入、删除、运算不受限制,而栈只能从一端操作(栈顶)
栈只能从一端操作、先进后出,这是属于人为规定的。即可以从栈中间取一个元素,并且程序可以运行,但这样就不是栈了,因为这不符合栈的定义
特点:先进后出(或后进先出)
按存储结构分类
顺序栈
采用地址连续的存储空间(类似于数组)依次存储栈中数据元素,入栈和出栈运算都是在栈顶进行,而栈底位置是固定不变,可以将栈底位置设置在内存空间的起始处;栈顶位置是随入栈和出栈操作而变化,用一个整型变量top来记录当前栈顶元素在数组中的位置。
应用
栈顶指针往后移,把数据存放在栈顶位置,;出栈是删除栈顶元素,栈顶往前移
链栈
采用链式存储,每个结点的地址是不连续的,并且每个结点包含数据域(存储数据)和指针域(存储下一个结点的地址),和单链表相同,但链栈没有头节点,而且链栈只能从一端操作(栈的定义),即只能从一端插入、删除等
应用:和单链表类似
优点:不会出现栈满溢出的情况
顺序栈和链栈的区别:
顺序栈采用的是预先分配内存,有可能会内存不够,或内存浪费;链栈不会有这些情况,但是每个结点有一个指针域,增加内存的开销。元素比较多的话用链栈比较好,反之顺序栈比较好
顺序栈
#define Maxsize 100 //预先分配栈空间的大小,由世界情况确定
typedef struct stack
{
ElemType data[Maxsize]; //ElemType:元素类型,根据自己需要定义,例如int、char、float以及自定义的类型;data[Maxsize]:定义数组的长度
int top; //栈顶指针
int base; //栈底指针,一般可不定义
}SqStack;
void InitStack(SqStack &st) //初始化顺序栈
{
st.top = -1;
}
void Push(SqStack *&st, ElemType e) //入栈
{
int i = 0;
if (st.top == Maxsize - 1) //入栈需要判断栈空间已满是否已满,如果栈已满,则入栈失败,如果依旧往栈里面存储数据,会导致栈满溢出的情况
{
printf("栈空间已满\n");
return ;
}
else
{
st.top++; //入栈先使栈顶指针加1(栈顶指针上移一位),在存储数据
st.data[st.top] = n;
}
}
void Pop(SqStack *&st, ElemType &n) //出栈
{
int i=0;
if (st.top == -1) //判断是否栈空,如果栈空则结束
{
printf("栈空\n");
}
else
{
n = st.data[st.top];//出栈先取出栈顶数据,然后栈顶指针减一(栈顶指针移向下一位置)
st.top--;
}
}
void GetTop(SqStack *st, ElemType n) //取栈顶元素
{
if (st.top == -1) //栈空时取栈顶元素没有意义
{
printf("栈空\n");
}
else
{
while(st.top != -1)
{
n = st.top;
}
}
}
void DestroyStack(SqStack st)//销毁栈
{}
int StackEmpty(SqStack st) //判断栈是否为空,可用来作为结束循环语句的条件(例如:while(!StackEmpty()) )当栈空时结束循环
{
if (st.top == -1)
{
printf("\n栈空\n");
return 1;
}
return 0;
}
链栈
typedef struct LiStack
{
ElemType data; //数据域
struct LiStack *next; //指针域
}LiStack;
void InitStack(LiStack *&st) //初始化栈
{
st=(LiStack *)malloc(sizeof(LiStack));
st-
> 这里是引用
=NULL;
}
void Push(LiStack *&st, ElemType x) //入栈,将新元素节点压入栈顶
{
LiStack *p;
p=(LiStack *)malloc(sizeof(LiStack)); //创建新的节点
p->data=x;
p->next=st; //将st的地址赋值给新建节点p的指针域
st=p; //新栈的栈顶指针为p
}
void Pop(LiStack *&st,ElemType &x) //出栈,将栈顶元素删除,让栈顶指针指向下一元素
{
LiStack *p;
if(st->next==NULL)
{
printf("栈空\n");
}
else
{
x=st->data;
p=st; //p指向栈顶元素
st=st->next; //st指向栈顶的下一节点
delete p; //释放原栈顶元素的空间
}
}
ElemType GetTop(LiStack *st) //取栈顶元素,复制栈顶元素的数据
{
if(st->next==NULL)
{
printf("栈空\n");
}
else
{
return st->data;
}
}
void DestroyStack(LiStack *&st) //销毁栈
{
LiStack *p=st,*q=st->next;
while(q!=NULL)
{
free(p);
p=q;
q=q->next;
}
free(p);
}
int StackEmpty(LiStack *st) //判断栈是否为空
{
if (st == NULL)
return 1;
else
return 0;
}
栈的应用
顺序栈
题目:进栈顺序为(1,2,3…n),给定出栈顺序,判断该出栈顺序是否合法
#include<stdio.h>
#define Maxsize 100
#define N 5
#pragma warning(disable:4996)
typedef struct SqQueue
{
int data[Maxsize];
int top;
}Sq;
void Push(Sq &, int);
void Pop(Sq &);
void GetTop(Sq, int &);
int StackEmpty(Sq);
void Push(Sq &st, int x) //元素x进栈
{
if (st.top > Maxsize - 1)
{
printf("栈空间已满\n");
}
else
{
st.top++;
st.data[st.top] = x;
}
}
void Pop(Sq &st) //出栈
{
if (st.top == -1)
{
printf("栈空\n");
}
else
{
st.top--;
}
}
void GetTop(Sq st, int &x) //获取栈顶元素
{
if (st.top == -1)
printf("栈空\n");
else
x = st.data[st.top];
}
int StackEmpty(Sq st) //判断栈是否为空
{
if (st.top == -1)
return 1;
else
return 0;
}
int main()
{
Sq st;
st.top = -1;
int a[N]; //存储出栈顺序
int i, j = 0, t = 0,e;
printf("请输入你想要检测的出栈序列:\n");
for (i = 0; i < N; i++)
{
scanf("%d", &a[i]);
}
for (i = 1; i <= N; i++)
{
Push(st, i); //i进栈
printf("%d进栈\n", i);
while (!StackEmpty(st)) //判断栈是否为空,栈空返回1,非空返回0
{
GetTop(st, e); //获取栈顶元素
if (a[j] == e) //每进栈一个元素,就判断该元素是否时下一个出栈的元素
{
Pop(st);
printf("%d出栈\n", e);
j++;
t++; //t记录已经出栈的个数
}
else
break;
}
}
if (t == N) //判断出栈个数和进栈个数是否相同
{
printf("该顺序合法\n");
}
else
printf("该顺序不合法\n");
return 0;
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020060615410680.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1ODk2NzY2,size_16,color_FFFFFF,t_70#pic_center)
链栈
链栈的基本操作
#include<stdio.h>
#include<malloc.h>
#define Maxsize 100
#define N 5
#pragma warning(disable:4996)
typedef struct LiStack
{
int data; //数据域
struct LiStack *next; //指针域
}LiStack;
void InitStack(LiStack *&st) //初始化栈
{
st = (LiStack *)malloc(sizeof(LiStack));
st->next = NULL;
}
void Push(LiStack *&st, int x)
{
LiStack *p;
p = (LiStack *)malloc(sizeof(LiStack));
p->data = x;
p->next = st;
st = p;
}
void Pop(LiStack *&st, int &x)
{
LiStack *p;
if (st->next == NULL)
{
printf("栈空\n");
}
while (st->next != NULL)
{
x = st->data;
p = st;
st = st->next;
printf("%d\t", x);
free(p);
}
}
void GetTop(LiStack *st, int &x)
{
if (st->next == NULL)
{
printf("栈空\n");
}
else
{
x = st->data;
}
}
void DestroyStack(LiStack *&st) //销毁栈
{
LiStack *p = st, *q = st->next;
while (q != NULL)
{
free(p);
p = q;
q = q->next;
}
free(p);
}
int main()
{
LiStack *st;
int x;
InitStack(st); //初始化栈
printf("1进栈\n");
Push(st, 1);
printf("2进栈\n");
Push(st, 2);
printf("3进栈\n");
Push(st, 3);
GetTop(st, x);
printf("此时栈顶元素为%d\n", x);
printf("出栈次序:");
Pop(st, x);
printf("\n销毁栈\n");
free(st);
return 0;
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200606221617723.png)
}
由于时间、水平、精力有限,文中难免会出现不准确的、甚至错误的地方,欢迎大佬看见的话批评指正。