数据结构之栈 C语言数组版
数据结构中,栈是必须要学的这么一个数据结构,而这个栈的数据结构的特点就是 先进后出,后进先出。存储方式就可以是顺序的数组结构存储或者是链式结构的存储方式存储。这里写的就是使用数组这种顺序存储结构来存储栈的数据。
栈的概念
栈的本质
- 栈是一种数据结构
- 有顺序的数组存储方式,称为顺序栈
- 有链式的链表存储方式,称为链式栈
栈的特点
-
先进后出,后进先出
-
有栈满和栈空的情况
-
有底部的指针,管理整个栈
-
有顶部的标记,管理栈顶的元素
栈的图解
需要的头文件
#include<stdio.h>
#include<stdlib.h> //malloc
#include<assert.h> //断言
- 标准头文件
- 动态内存申请需要的头文件,可以是stdlib.h也可以是malloc.h
- 最后一个是一个断言(assert)的头文件,主要是用来判断在堆区申请的内存是否成功的
栈的基本结构(代码)
//栈的基本结构
typedef struct Stack
{
int top; //栈顶标记
int* base; //栈底指针
}Stack,*pStack;
为了省点力气写代码,可以用typedef给结构体类型起别名 。
- 栈顶标记,主要是用来标记栈顶的,可以移动。元素出栈的时候都是通过栈顶出的。入栈的时候栈顶标记就往上走,出栈的时候栈顶标记就往下走。
- 栈底指针,主要是用来标识堆区申请的内存的首地址的。不可以移动,移动了,原来在栈中的元素就找不到了。
别名 :
Stack相当于struct Stack
pStack相当于struct Stack*
如果不觉得麻烦的话也可以不起别名 ,但是写代码的时候就比较多一点。
各个子函数的实现与解析
预定义:
#define MAX 10
创建栈
pStack createStack()
{
pStack stack = (pStack)malloc(sizeof(Stack));
assert(stack);
stack->top = -1; //初始化为-1,方便用的时候类似数组的用法
stack->base = (int*)malloc(sizeof(int) * MAX);
assert(stack->base);
return stack;
}
使用一个子函数创建栈,这样的逻辑就比较清晰一点。直接用一个结构体指针指向堆区的内存(这个内存就是用来存我们创建出来的栈的),然后就是top数据成员的初始化。其实也不一定要初始化为-1,这个和等下的入栈和出栈等操作相联系。如果top初始化为零,那等下的入栈就先把元素放到栈中,然后再把栈顶标记往上移动一个单位。如果初始化为-1就是先把栈顶标记往上移动一个单位,然后再把元素放到栈中。当然也可以初始化为其他值,那就是先移动到对应的位置了之后再把元素放到栈中来。这里就简单点直接初始化为-1。
再然后就是初始化栈的成员指针base(栈底指针),让它指向堆区中的内存申请一个MAX个int类型的大小。最后然后这个stack指针就可以完成创建顺序栈了。
判空
int isEmpty(pStack stack)
{
if (stack->top == -1)
{
printf("Stack is empty!!!\n");
return 1;
}
return 0;
}
思路很简单,判空就看栈顶标记和栈底的位置关系。对于这里实现栈的代码中,如果栈顶标记等于栈底表示的是当前栈有一个元素;当栈顶标记在栈底指针的下面,则表示的是当前栈是一个空栈。所以代码实现的时候就直接用if语句就好,我这里是想打印”Stack is empty!!!“这句话才使用的if语句。当然也可以用三目运算符,但这样做的话,可读性可能不是很好。
叛栈满
int isFull(pStack stack)
{
if (stack->top == MAX)
{
printf("Stack is full!!!\n");
return 1;
}
return 0;
}
思路:判断栈是否满就看栈顶标记是不是已经走到栈的最上面了,因为栈是有栈满的情况的。MAX就是栈的最大存储内存。
获取当前栈的大小
int size(pStack stack)
{
if (isEmpty(stack))
return -1;
else
return stack->top + 1;
}
这里存在一个小细节,就是我们创建的这个栈是从零开始计算的,所以获取栈的大小的时候要记得做加1操作(不是做++运算)。
入栈
void pushStack(pStack stack,int Data)
{
if (isFull(stack))
return;
stack->base[++stack->top] = Data;
}
思路:入栈的时候先判断栈是否满,如果栈满就直接结束掉或者函数,如果没有满就做入栈的操作。stack->base表示的就是栈指针的栈底指针成员。因为实际的元素是存在base指向的堆区的内存中的。然后就是中括号 里面的[++stack->top]表示的就是栈的实际内存的实际位置,因为top一开始初始化为-1所以要先做增1的操作然后才把元素放到栈中,后面的=Data就是一个赋值操作。就是函数实参传进来的数值,这里用整型为代表测试。当然也可以是其他类型的数据,就是代码要稍微改一改。
获取栈顶元素
int top(pStack stack)
{
if (isEmpty(stack))
return -1;
return stack->base[stack->top];
}
直接返回栈顶的元素。栈的元素实际是存在base指针指向的内存,所以要这么写。
出栈
void popStack(pStack stack)
{
if (isEmpty(stack))
return;
--stack->top;
}
这里的出栈操作是没有把内存释放的,只是把栈顶标记往下移动一个单位,就表示这个元素已经出栈了。当然在运行或者函数前,也是要判断栈是否是空栈。是空栈就没有必要执行下面的代码了,那就直接结束掉这个函数。
测试函数
void test()
{
pStack stack = createStack(); //创建一个栈
for (int i = 0; i < 3; i++)
{
pushStack(stack, i + 1);
}
while (!isEmpty(stack))
{
printf("%d ", top(stack));
popStack(stack);
}
}
测试代码主要的功能是:创建一个栈,然后做了入栈的操作,然后又进行出栈的操作。就这么简单。值得 主要的地方就是isEmpty这个函数要进行取反运算 。因为空栈会返回1。然后循环中的内容就是把栈的元素打印出来,打印出来后就把栈顶标记 往下移动一个单位。
整体源代码
#include<stdio.h>
#include<stdlib.h> //malloc
#include<assert.h> //断言
#define MAX 10 //设置栈的大小为10
//栈的基本结构
typedef struct Stack
{
int top; //栈顶
int* base; //栈底指针
}Stack,*pStack;
//创建栈
pStack createStack()
{
pStack stack = (pStack)malloc(sizeof(Stack));
assert(stack);
stack->top = -1; //初始化为-1,方便用的时候类似数组的用法
stack->base = (int*)malloc(sizeof(int) * MAX);
assert(stack->base);
return stack;
}
//判空
int isEmpty(pStack stack)
{
if (stack->top == -1)
{
printf("Stack is empty!!!\n");
return 1;
}
return 0;
}
//叛栈满
int isFull(pStack stack)
{
if (stack->top == MAX)
{
printf("Stack is full!!!\n");
return 1;
}
return 0;
}
//获取当前栈的大小
int size(pStack stack)
{
if (isEmpty(stack))
return -1;
else
return stack->top + 1;
}
//入栈
void pushStack(pStack stack,int Data)
{
if (isFull(stack))
return;
stack->base[++stack->top] = Data;
}
//获取栈顶元素
int top(pStack stack)
{
if (isEmpty(stack))
return -1;
return stack->base[stack->top];
}
//出栈
void popStack(pStack stack)
{
if (isEmpty(stack))
return;
--stack->top;
}
void test()
{
pStack stack = createStack(); //创建一个栈
for (int i = 0; i < 3; i++)
{
pushStack(stack, i + 1);
}
while (!isEmpty(stack))
{
printf("%d ", top(stack));
popStack(stack);
}
}
int main()
{
//测试函数
test();
return 0;
}
测试结果
3 2 1 Stack is empty!!!
这里只是简单的使用了入栈和出栈的操作,想搞其他花里胡哨的,只要顺序栈能满足的,这个代码都是完成的。