赞
踩
栈是一种特殊的线性表,其只允许固定一端进行插入和删除元素操作。进行数据的插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈/入栈/进栈:栈的插入操作,入数据在栈顶
出栈:栈的删除操作叫出栈。出数据也是在栈顶
后进先出(Last In First Out)
上图展示了栈的入栈与出栈,只有一端开口是栈的特点。
要实现栈其实很简单,可以说栈就是功能缺失的顺序表。另外栈也分为数组栈和链栈。
链栈和数组栈也没什么特别的优劣之分,不过如果你要实现单链表的链栈,就要让链表的头为栈顶,这样插入数据的时候就不用找尾了。
相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。下面我们来实现数组栈。
为了以后用这个栈来存储各种类型的数据,所以我们定义一个标识符Datatype。
为了定位栈顶还需要一个top变量来指向栈的顶部。以及记录当前开了多少空间的capacity。
#define Datatype int //增加代码的拓展性
typedef struct stack
{
Datatype* a;
int top;
int capacity;
}stack;
在初始化中可以先malloc一些空间,不过这里我就直接初始化为NULL了,后面插入时在扩容。
关于top
如果你初始化为-1代表的意思就是栈顶元素,如果你初始化为0代表的意思就是栈顶元素的下一个元素。
无论你初始化哪个都是可以的,只是后续的实现代码有些许不同。这里我选的就是初始化为0
void InitStack(stack* ps)
{
ps->a = NULL;//可以初始时就开辟空间,不过我选择了初始不开空间的写法
ps->top = 0;//初始为-1或者0都可以,后面的操作根据top的初始值来操作。
ps->capacity = 0;
}
每次入栈都要判断当前的空间是否足够,你也可以像写顺序表时那样把,判断写成一个函数,不过因为栈就只有一个插入函数,就显的没什么必要了。
扩容时要注意,因为初始化时的capacity为0不能直接X2扩容,要判断一下。
另外可能会有人有疑问,realloc不是用来扩容的吗,还可以当malloc用吗?
可以的,当没有初始空间时,realloc就可以当malloc使用。
//栈的插入/入栈 void PushStack(stack* ps,Datatype x) { assert(ps); //判断空间是否充足 if (ps->top == ps->capacity) { //空间不够,扩容 int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//防止0乘任何数都为0的情况 Datatype* tmp = (stack*)realloc(ps->a,sizeof(stack) * newcapacity); if (tmp == NULL) { perror("realloc"); exit(-1); } ps->a = tmp; ps->capacity = newcapacity; } ps->a[ps->top] = x; ps->top += 1; }
删除是唯一要注意的就是,如果栈为空可不能再删除了。
//栈的删除/出栈
void PopStack(stack* ps)
{
assert(ps);
assert(ps->top > 0);//栈为空时不能删除
ps->top -= 1;
}
注意为空返回真,不为空返回假。
这里只要判断ps->top是否为0就可以了。
bool EmptyStack(stack* ps)
{
assert(ps);
return ps->top == 0;
}
因为ps->top表示栈顶的下一个元素,所以返回ps->a[ps->top - 1]
就可以了
//取出栈顶元素
Datatype TopStack(stack* ps)
{
assert(ps);
assert(ps->top > 0);
return ps->a[ps->top - 1];
}
不知道大家有没有认为,ps->top很像顺序表的size。这里我们直接返回ps->top就可以代表有效个数了。
//获取栈中有效元素个数
int SizeStack(stack* ps)
{
assert(ps);
return ps->top;
}
为了防止内存泄漏,一定要记得释放空间哦~
//销毁栈
void DestoryStack(stack* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
//stack.h #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <stdbool.h> #define Datatype int //增加代码的拓展性 typedef struct stack { Datatype* a; int top; int capacity; }stack; //栈的初始化 void InitStack(stack* ps); //栈的插入/入栈 void PushStack(stack* ps, Datatype x); //栈的删除/出栈 void PopStack(stack* ps); //判断栈是否为空 bool EmptyStack(stack* ps); //取出栈顶元素 Datatype TopStack(stack* ps); //获取栈中有效元素个数 int SizeStack(stack* ps); //销毁栈 void DestoryStack(stack* ps); //stack.c #include "stack.h" //栈的初始化 void InitStack(stack* ps) { ps->a = NULL;//可以初始时就开辟空间,不过我选择了初始不开空间的写法 ps->top = 0;//初始为-1或者0都可以,后面的操作根据top的初始值来操作。 ps->capacity = 0; } //栈的插入/入栈 void PushStack(stack* ps,Datatype x) { assert(ps); //判断空间是否充足 if (ps->top == ps->capacity) { //空间不够,扩容 int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//防止0乘任何数都为0的情况 Datatype* tmp = (stack*)realloc(ps->a,sizeof(stack) * newcapacity); if (tmp == NULL) { perror("realloc"); exit(-1); } ps->a = tmp; ps->capacity = newcapacity; } ps->a[ps->top] = x; ps->top += 1; } //栈的删除/出栈 void PopStack(stack* ps) { assert(ps); assert(ps->top > 0);//栈为空时不能删除 ps->top -= 1; } //判断栈是否为空 bool EmptyStack(stack* ps) { assert(ps); return ps->top == 0; } //取出栈顶元素 Datatype TopStack(stack* ps) { assert(ps); assert(ps->top > 0); return ps->a[ps->top - 1]; } //获取栈中有效元素个数 int SizeStack(stack* ps) { assert(ps); return ps->top; } //销毁栈 void DestoryStack(stack* ps) { assert(ps); free(ps->a); ps->a = NULL; ps->top = 0; ps->capacity = 0; } //test.c #include "stack.h" void test1() { /*stack s; InitStack(&s); PushStack(&s, 1); PushStack(&s, 1); PushStack(&s, 2); PushStack(&s, 2); PushStack(&s, 3); PushStack(&s, 3); PushStack(&s, 4); PushStack(&s, 4); while (!EmptyStack(&s)) { printf("%d ", TopStack(&s)); PopStack(&s); } DestoryStack(&s);*/ } int main() { test1(); return 0; }
完
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。