栈的介绍:
栈是一种只能在一端进行插入或者删除操纵的线性表或者链表,表中允许进行插入和删除操作的一端被称为栈顶,表的另外一端称为栈底
当栈中没有元素是称为空栈,栈的插入操作通常称为进栈或者入栈,栈的删除操作通常称为出栈或者退栈。
栈的特点:
栈的特点是后进先出(Last In First Out,LIFO),即后进先出,后面进来的元素先出栈
栈的种类
采用线性存储结构的栈称为顺序栈,采用链式存储结构的被称为链式栈
栈的基本操作:
这里用的是链式栈,顺序栈在后面的文章中会仔细解释
//初始化栈
Status InitStack(LinkSqStack *Stack);
//销毁栈
Status DestoryStack(LinkSqStack *Stack);
//判空
Status EmptyStack(LinkSqStack *Stack);
//进栈
Status push(LinkSqStack *Stack,ElemType e);
//出栈
Status Pop(LinkSqStack *Stack,ElemType *e);
//取栈顶元素
Status GetPop(LinkSqStack *Stack,ElemType *e);
//将指针指向最后一个元素
Status pTail(LinkSqStack *Stack);
//求栈的长度
Status LengthStack(LinkSqStack *Stack);
//栈的遍历
Status TraverseStack(LinkSqStack *Stack);
栈的基本操作的实现:
状态常量
直接在头部定义以后后续改的时候方便,Status是int 的别名,也是为了后续改动方便
#include <stdlib.h>
#include <stdio.h>
#define OK 1
#define ERROR 0
#define OVERFLOW –2
#define TRUE 1
#define FALSE 0
typedef int Status;
栈的结构体定义
ElemType定义的是栈的节点的类型,取别名是为了后续方便改动
typedef int ElemType;
typedef struct LinkSqNode{
ElemType data;
struct LinkSqNode *next;
}LinkSqStack;
初始化栈
初始化栈过于简单,这里不做详细介绍
Status InitStack(LinkSqStack *Stack){
Stack= (LinkSqStack*)malloc(sizeof(LinkSqStack));
if (!Stack) {
return FALSE;
}
Stack->next = NULL;
return OK;
}
销毁栈
销毁栈,因为创建节点的时候是一个一个的创建的,所以销毁的时候也要一个一个的销毁,里面需要用到两个辅助指针,一个指针指向首元节点,一个指针指向首元节点的下一个节点,然后利用两个指针依次循环就可以销毁栈了,后面还要释放头节点
Status DestoryStack(LinkSqStack *Stack){
LinkSqStack *p = Stack,*q = Stack->next;
while (q) {
p = q;
q = q->next;
free(p);
}
free(q);
printf("栈已销毁\n");
return OK;
}
栈的判空操作
如果头节点的后面为空,则栈空
Status EmptyStack(LinkSqStack *Stack){
if (Stack->next == NULL) {
printf("栈空\n");
return FALSE;
}else{
printf("栈非空\n");
return OK;
}
}
进栈或入栈操作
一般用Push来表示入栈操作,创建一个新的节点,把要进栈的数据传给这个节点,再把这个节点插入到栈顶(这里的栈顶是在前面,以首元节点为栈顶,就是在链表的前端进行插入和删除操作)
Status push(LinkSqStack *Stack,ElemType e){
LinkSqStack *p = (LinkSqStack*)malloc(sizeof(LinkSqStack));
p->data = e;
p->next = Stack->next;
Stack->next = p;
return OK;
}
出栈或者退栈操作
首先判断栈是否为空,然后用一个辅助指针移到首元节点上面,(注意:要先把值取出来才能进行删除节点),让头节点的指针域记录首元节点的指针域,然后释放首元节点
Status Pop(LinkSqStack *Stack,ElemType *e){
if (Stack->next == NULL) {
printf("栈空\n");
return FALSE;
}
LinkSqStack *p;
p = Stack->next;
*e = p->data;
Stack->next = p->next;
free(p);
return OK;
}
取栈顶元素
首先判断栈是否为空,然后不删除节点,直接取值就可以
Status GetPop(LinkSqStack *Stack,ElemType *e){
if (Stack->next == NULL) {
printf("栈空\n");
return FALSE;
}
*e = Stack->next->data;
return OK;
}
求栈的长度
操作过于简单,这里不做解释
Status LengthStack(LinkSqStack *Stack){
int count = 0;
while (Stack) {
Stack = Stack->next;
count++;
}
printf("栈的容量为%d",count);
return OK;
}
栈的遍历
首先,要把指针移到首元节点上面,因为头节点不维护数据域,然后使用while循环遍历栈,直到指针指向栈底元素,栈底元素的指针域为空
Status TraverseStack(LinkSqStack *Stack){
Stack = Stack->next;
if (Stack->next == NULL) {
printf("栈空\n");
return FALSE;
}
while (Stack) {
printf("%d\t",Stack->data);
Stack =Stack->next;
}
return OK;
}
下面是栈的测试代码
int main(void){
LinkSqStack Stack;
ElemType e;
InitStack(&Stack);
for (int i = 0; i < 9; i++) {
push(&Stack, i);
}
EmptyStack(&Stack);
LengthStack(&Stack);
printf("\n");
TraverseStack(&Stack);
printf("\n");
GetPop(&Stack, &e);
printf("栈顶元素%d",e);
printf("\n");
printf("元素出栈(前三个元素出栈)\n");
for (int j = 0; j < 3; j++) {
Pop(&Stack, &e);
printf("%d\t",e);
}
printf("\n");
DestoryStack(&Stack);
}
测试结果