目录
一、前言
栈作为一种常用的结构,可以用顺序栈和链栈实现。
1、顺序栈(两个指针分别指向栈底、栈顶)
2、链式栈(和单链表一样,只是没有头节点,直接从首元节点开始)
这两种存储方式各有优略,我们可以根据实际情况选择对应的存储方式。 下面,着重分析两种存储的定义和相关操作。
二、结构定义
1、首先使用顺序存储的方式定义一个栈的结构体,有栈底栈顶指针,和栈的大小。
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100
typedef struct{ // 顺序栈
int * base; // 栈底指针
int * top ; // 栈顶指针
int stacksize; // 栈可用最大容量
}SqStack;
2、再用链式存储方式定义栈的结构体,和单链表相似。
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100
/*
* 需要注意
* 1、 链表的头指针就是栈顶
* 2、不需要头节点
* 3、基本不存在栈满的情况
* 4、空战相当于头指针指向空
* 5、插入和删除仅在栈顶处执行
*/
typedef struct StackNode{ // 链栈
int data; // 数据域
struct StackNode * next; // 指针域
}SNStack;
三、相关操作
对栈的操作包括但不限于(初始化、判断栈空、入栈、出栈、清空顺序栈、销毁顺序栈)
1、栈的初始化
顺序栈初始化
bool InitStack(SqStack &S){ // 构造一个空栈
S.base = (int *)malloc(sizeof(int)*MAXSIZE);
if(!S.base)
return false;
S.top = S.base; // 栈顶指针等于栈底指针
S.stacksize = MAXSIZE;
return true;
}
链式栈初始化
void InitStack(SNStack * &S){ // 链栈初始化
S = NULL;
}
2、判断是否栈空
顺序栈的判断
bool isEmpty(SqStack S){ // 判断是否栈空
if(S.top == S.base)
return true;
else
return false;
}
链式栈的判断
bool isEmpty(SNStack * S){ // 判断链栈是否为空
if(S == NULL)
return true;
else
return false;
}
3、入栈操作
顺序栈的入栈
bool Push(SqStack &S, int e){ // 顺序栈入栈
if(S.top - S.base == S.stacksize) // 栈满
return false;
* S.top ++ = e; // 栈顶指针指向的位置赋值,然后指针指向下一个位置
return true;
}
链式栈的入栈(直接放在第一个节点前面p->next=S)
void Push(SNStack * &S, int e){ // 链栈的入栈
SNStack * p = (SNStack *)malloc(sizeof(SNStack)); // 新节点
p->data = e;
p->next = S; // 新节点插入到栈顶
S = p; // 修改栈顶指针
}
4、出栈操作
顺序栈的出栈
bool Pop(SqStack &S, int &e){ // 顺序栈出栈到e
if(S.top == S.base ) // 栈空
return false;
e = * --S.top; // 指定指针先指向前一个位置,然后把该位置的值取出赋给e
return true;
}
链式栈的出栈
bool Pop(SNStack * &S, int &e){ // 链栈的出栈
if(S == NULL) // 栈空
return false;
e = S->data;
SNStack * p = S;
S = S->next;
free(p); // 释放p
return true;
}
5、清空顺序栈
void ClearStack(SqStack &S){ // 清空顺序栈
if(S.base)
S.top = S.base;
}
6、销毁顺序栈
void DestoryStack(SqStack &S){ // 销毁顺序栈
if(S.base){
free(S.base);
S.stacksize = 0;
S.base = S.top = NULL;
}
}