栈(Stack):是限制在表的一端进行插入和删除操作的线性表。又称为后进先出LIFO (Last In First Out)或先进后出FILO(First In Last Out)线性表。
栈顶(Top)∶允许进行插入、删除操作的一端,又称为表尾。用栈顶指针(top)来指示栈顶元素。
栈底(Bottom):是固定端,又称为表头。空栈:当表中没有元素时称为空栈。
顺序栈
#include <iostream>
using namespace std;
#define MAX 100
//顺序栈的定义
typedef struct
{
int *base;
int *top;
int stacksize;
}SqStack;
//初始化
int InitStack(SqStack &S)
{
S.base = new int[MAX]; // 为顺序栈动态分配一个最大容量为MAX的数组空间
if (!S.base)
{
return 0;
}
S.top = S.base;//初始化将栈置空,就是让头指针指向尾指针,从语句上讲就是把尾指针的值赋值给头指针
S.stacksize = MAX;
return 1;
}
//入栈
int Push_S(SqStack &S, int e)
{
//将元素e入栈
if (S.top - S.base == S.stacksize) // 判断栈是否满
{
return 0;
}
*S.top++ = e; // *S.top=e; S.top++;
return 1;
}
//出栈
int Pop_S(SqStack &S, int &e)
{
//用e返回出栈的元素
if (S.top == S.base) // 判断栈是否为空
{
return 0;
}
e = *--S.top; // --S.top;e=*S.top;
return 1;
}
// 取栈顶元素
int GetTop( SqStack S, int &e)
{
if (S.top == S.base)
return 0; // 栈空
e = *(S.top - 1);
return 1;
}
int main()
{
SqStack S;
if (InitStack(S))
{
printf("顺序栈初始化成功!\n");
}
else
{
printf("顺序栈初始化失败!\n");
}
int loop = 1;
int e1;
int i = 1;
// 入栈
printf("请输入入栈元素(输入0终止):\n");
while (loop)
{
printf("请输入第%d个元素值:",i++);
scanf("%d", &e1);
if (e1 != 0)
{
Push_S(S,e1);
}
else if (e1 == 0)
{
loop = 0;
}
}
// 取栈顶元素
int e2;
GetTop(S, e2);
printf("栈顶元素是:%d\n", e2);
// 出栈
int e3; int j = 1;
while (S.top != S.base)
{
Pop_S(S, e3);
printf("第%d个出栈的元素是:%d\n",j++,e3);
}
system("pause");
return 0;
}
链栈
链栈是一种特殊的线性链表,使使用链式存储结构的栈,链栈也有栈顶栈底,同样是一种后进先出(LIFO)的数据结构
链栈定义
链栈需要定义两个结构体,LinkStackNode 用来定义链栈节点的类型,存放节点的数据和下一节点的 next 指针
LinkStack 结构体用来定义链栈的结构,存放 top 栈顶指针和链栈的总长度
typedef struct LinkStackNode {
int data;
LinkStackNode *next;
}LinkStackNode;
typedef struct LinkStack {
LinkStackNode *top;
int length;
}LinkStack;
创建链栈
创建链栈的过程就是定义 LinkStack 变量并为其分配内存,再让栈顶指针指空,栈的长度归 0
LinkStack * CreateStack() {
LinkStack *p;
p = (LinkStack *)malloc(sizeof(LinkStack));
p->length = 0;
p->top = NULL;
return p;
}
判断栈是否为空
int IsEmpty(LinkStack *p) {
if (p->length == 0)
return 1;
else
return 0;
}
入栈
因为栈的本质是一种后入先出的数据结构,所以所有的操作都要在栈顶进行。入栈操作即定义新的 LinkStackNode 并为其分配内存,给他的数据域赋值,使新节点的 next 指向原栈顶处的节点,在使新入节点成为新的栈顶结点,栈的长度 +1
LinkStack *PushStack(LinkStack *p, int d) {
if (p == NULL)
return NULL;
LinkStackNode *temp;
temp = (LinkStackNode *)malloc(sizeof(LinkStackNode));
temp->data = d;
temp->next = p->top;
p->top = temp;
p->length++;
return p;
}
出栈
出栈需要先判断栈是否为空,再将栈顶指针指向原栈顶节点的 next,释放原栈顶节点的内存,栈的长度 -1
LinkStack *PopStack(LinkStack *p) {
LinkStackNode *temp;
temp = p->top;
if (p->top == NULL || IsEmpty(p) == 1) {
cout << "this stack is EMPTY !" << endl;
return p;
}
else {
p->top = p->top->next;
free(temp);
p->length--;
return p;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
打印栈
打印栈同样先检测栈是否为空,然后在遍历栈的同时打印每个节点的数据
int ShowStack(LinkStack *p) {
LinkStackNode *temp;
temp = p->top;
if (p->top == NULL || IsEmpty(p) == 1) {
cout << "this stack is EMPTY !" << endl;
return 0;
}
while (temp != NULL) {
cout << temp->data << ' ';
temp = temp->next;
}
cout << endl;
return 0;
}