栈
这是大话数据结构种对于栈的描述
可以看到 栈是一种特殊的线性表
它只能在尾部进行元素的插入和删除 但是在栈种 这叫做 入栈 和 出栈
而且它遵循 先进入的元素后出 后进入的元素先出
即就是我们常听说的 先进后出 和后进先出
这里就有一个简单的例子 先进后出 后进先出
这里有个更加形象的例子 手枪弹夹 我们后装入的子弹位于 弹夹的顶端 因此会被先射出 而先装入的子弹位于弹夹底端 因此会后射出
那么我们的栈的基础结构就和这个手枪弹夹十分类似
栈的结构可以分为顺序栈 和 链式栈
今天我们介绍 顺序栈
我们可以在顺序表的基础上做出修改就可以实现一个顺序栈
这是往期的顺序表的实现 可以参考这个来实现顺序栈
基础数据结构线性表_iccoke的博客-CSDN博客
首先我们给出 顺序栈的结构体定义
#pragma once
//可扩容的顺序栈的结构体设计
#define STACK_INIT_SIZE 100 //初始大小
#define STACK_INCREMENT 10 //不需要
typedef int ELEM_TYPE;
typedef struct Stack
{
ELEM_TYPE *base;//存储空间基址(用来接收malloc返回在堆上申请的连续空间块开始地址)
int top;//当前有效长度,且还可以表示下一个待插入位置的下标
int stack_size;//当前总空间大小(以格子个数为单位)
}Stack, *PStack;
//初始化
void Init_stack(struct Stack *st);
//入栈(队尾插入)
bool Push(struct Stack *st, ELEM_TYPE val);
//出栈(队尾删除) 出栈,将值删除一个
bool Pop(struct Stack *st);
//获取栈顶元素值 //获取栈顶的元素值,但是不删除
ELEM_TYPE Top(struct Stack *st);
//判空
bool Is_Empty(struct Stack *st);
//判满
bool Is_Full(struct Stack *st);
//扩容 *2
void Inc(struct Stack *st);
//搜索
int Search(struct Stack *st, ELEM_TYPE val);
//清空
void Clear(struct Stack *st);
//销毁
void Destroy(struct Stack *st);
//打印
void Show(struct Stack *st);
//获取有效值个数
int Get_length(struct Stack *st);
熟悉顺序表的同学应该可以发现这里的结构体定义实际上顺序表一致
只不过是为了区分因此我们改变了结构体种的变量名
然后我们来实现 顺序栈
首先是初始化 我们依旧申请内存来初始化
void Init_stack(struct Stack *st)
{
st->base = (ELEM_TYPE*)malloc(STACK_INIT_SIZE * sizeof(ELEM_TYPE));
st->top = 0;//即代表下一个合适的插入位置下标为0,也代表当前有效长度为0
st->stack_size = STACK_INIT_SIZE;
}
初始化的时候栈中是没有元素的 因此我们的top 是 0
但是因为栈有大小 因此我们给点大小 用stack_size 宏来初始化
那么也就意味着我们现在在插入 和 删除 时都需要进行判断
插入时 判断是否为满 如果 满 进行插入失败 或者 扩容操作
删除时依旧 要判断是否为空
接下来 我们写 顺序栈中最重要的两个函数
入栈
bool Push(struct Stack *st, ELEM_TYPE val)
{
//0.安全性处理
assert(st != NULL);//保证顺序表的头结点存在
//1.如果栈还有空间,则将值val插入到top指向的格子里面
if(Is_Full(st))//判断是否栈满
{
Inc(st);//满了就扩容
}
//当上面的if执行结束,可以保证现在肯定有空闲格子了
st->base[st->top] = val;
//2.注意:不要忘记让top++
st->top++;
return true;
}
bool Is_Full(struct Stack *st)
{
//assert
//当当前有效格子数 == 当前总格子数,则满了
return st->top == st->stack_size;
}
//扩容 *2
void Inc(struct Stack *st)
{
ELEM_TYPE *tmp = (ELEM_TYPE*)realloc(st->base, (st->stack_size * sizeof(ELEM_TYPE))*2);
if(tmp == NULL)
{
printf("error\n");
return;
}
st->base = tmp;
//st->top;//扩容成功。有效长度不变
st->stack_size *= 2;
}
这里的重点时 判断是否为满 和 要对top进行 ++ 操作
还有 就是 在我们使用realloc进行扩容的时候 我们要使用另外一个变量来代替 base 然后 如果扩容成功的话 再将其赋值给base 这样可以防止 扩容失败影响栈中元素 完成扩容后要改变 最大空间的大小
出栈
bool Pop(struct Stack *st)
{
//0.安全性处理
//1.删除需要判空
st->top--;
return true;
}
bool Is_Empty(struct Stack *st)
{
//0.安全性处理
return st->top==0;
}
这里的安全性处理 就是 assert 防止这个栈不存在
然后判空 就是 调用判空函数 来检查是否为空
然后就是在栈中 相对来说 比较特殊的函数
获取栈顶元素
那么 或者获取栈顶元素 只是获取并不删除
因此获取完之后不需要进行top--操作
ELEM_TYPE Top(struct Stack *st)
{
//0.安全性处理
//1.判空
return st->base[st->top-1];
}
搜索函数 是循环遍历这个栈即可
int Search(struct Stack *st, ELEM_TYPE val)
{
//0.安全性处理
for(int i=0; i<st->top; i++)
{
if(st->base[i] == val)
{
return i;
}
}
return -1;
}
最后是清空和打印函数
void Clear(struct Stack *st)
{
//0.安全性处理
st->top = 0;
}
//销毁
void Destroy(struct Stack *st)
{
free(st->base);
st->stack_size = st->top = 0;
}
//打印
void Show(struct Stack *st)
{
//0.安全性处理
for(int i=0; i<st->top; i++)
{
printf("%d ", st->base[i]);
}
printf("\n");
}
//获取有效值个数
int Get_length(struct Stack *st)
{
return st->top;
/*int count = 0;
for(int i=0; i<st->top; i++)
{
count++;
}
return count;*/
}
完整代码
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "Stack.h"
//初始化
void Init_stack(struct Stack *st)
{
st->base = (ELEM_TYPE*)malloc(STACK_INIT_SIZE * sizeof(ELEM_TYPE));
st->top = 0;//即代表下一个合适的插入位置下标为0,也代表当前有效长度为0
st->stack_size = STACK_INIT_SIZE;
}
//入栈(队尾插入)
bool Push(struct Stack *st, ELEM_TYPE val)
{
//0.安全性处理
assert(st != NULL);//保证顺序表的头结点存在
//1.如果栈还有空间,则将值val插入到top指向的格子里面
if(Is_Full(st))//判断是否栈满
{
Inc(st);//满了就扩容
}
//当上面的if执行结束,可以保证现在肯定有空闲格子了
st->base[st->top] = val;
//2.注意:不要忘记让top++
st->top++;
return true;
}
//出栈(队尾删除) 出栈,将值删除一个
bool Pop(struct Stack *st)
{
//0.安全性处理
//1.删除需要判空
st->top--;
return true;
}
//获取栈顶元素值 //获取栈顶的元素值,但是不删除
ELEM_TYPE Top(struct Stack *st)
{
//0.安全性处理
//1.判空
return st->base[st->top-1];
}
//判空
bool Is_Empty(struct Stack *st)
{
//0.安全性处理
return st->top==0;
}
//判满
bool Is_Full(struct Stack *st)
{
//assert
//当当前有效格子数 == 当前总格子数,则满了
return st->top == st->stack_size;
}
//扩容 *2
void Inc(struct Stack *st)
{
ELEM_TYPE *tmp = (ELEM_TYPE*)realloc(st->base, (st->stack_size * sizeof(ELEM_TYPE))*2);
if(tmp == NULL)
{
printf("error\n");
return;
}
st->base = tmp;
//st->top;//扩容成功。有效长度不变
st->stack_size *= 2;
}
//搜索
int Search(struct Stack *st, ELEM_TYPE val)
{
//0.安全性处理
for(int i=0; i<st->top; i++)
{
if(st->base[i] == val)
{
return i;
}
}
return -1;
}
//清空
void Clear(struct Stack *st)
{
//0.安全性处理
st->top = 0;
}
//销毁
void Destroy(struct Stack *st)
{
free(st->base);
st->stack_size = st->top = 0;
}
//打印
void Show(struct Stack *st)
{
//0.安全性处理
for(int i=0; i<st->top; i++)
{
printf("%d ", st->base[i]);
}
printf("\n");
}
//获取有效值个数
int Get_length(struct Stack *st)
{
return st->top;
/*int count = 0;
for(int i=0; i<st->top; i++)
{
count++;
}
return count;*/
}