数组栈
栈的相关知识
栈结构存取数据的方式为后进先出,即后进栈的数据先被读取。
栈可以使用数组方式实现,也可以使用链表实现。
我这里是使用数组实现栈的。
此处的链表如果是单链表的话,正常情况是将含有新数据的节点插入链表尾部,即链表尾部作栈顶,链表头部做栈底。由于要遵循栈结构的后进先出,所以在插入新节点和取出节点中的数据的时候需要查找尾节点,这就比较耗费时间了。不过,我们可以将链表的头部取作栈顶,将链表的尾部取作栈底,利用链表的头插头删完成栈的后进先出。
定义数组栈的结构
定义数据类型结构
typedef int STDataType;
定义数组栈的结构
这里定义a为数组第一个元素的指针,也可以说是数组名。
top为数组元素个数,在初始化的时候初始为0。
capacity为数组的容量,即此时数组最多可以存储多少个我们定义的数据类型个数。
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
* 初始化数组栈*
初始化的时候我们默认不给数组分配空间,所以我们将数组的容量(capacity)置为0,数组中也没有数据,所以top也置为0。
void StackInit(ST* ps)
{
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
数组栈判空
这里需要assert()函数来判断一下传进来的指针是否为空,因为不能对空指针进行解引用。
判断是否为空的条件是:如果数组栈结构中的top等于0,说明数组中没有元素,返回1,
否则,返回0。
bool StackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
数组栈销毁
free掉为数组申请的空间后要将指向数组的指针置为NULL,同时将数组容量(capacity)和数组中元素个数(top)置为空.
void StackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = 0;
ps->top = 0;
}
数组中元素的个数
这里只需要返回数组栈结构中的top即可。
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
插入新的数据元素
这里的逻辑是这样的:如果数组栈结构中的数据个数和数组的最大容量相等,有两种情况,第一种情况是第一次容量为零的时候,我们就要给数组指定分配多少个数据元素作为第一次数组的最大容量;第二种情况是,前面已经给数组分配好了空间,但是现在数据元素个数依然达到了上限,这里采取的方法是,将数组最大容量扩至原来的两倍。
如果数组栈结构中的数据个数和数组的最大容量不相等,说明此时数组不需要扩容,仅需将数组下标为top处的值修改为x即可,注意这里我们又添加了一个数据,所以数组中的元素个数(top)应该+1。
void StackPush(ST* ps, STDataType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
int newCapacity = (ps->capacity == 0 ? 4 : ps->capacity * 2);
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
if (tmp == NULL)
exit(-1);
ps->capacity = newCapacity;
ps->a = tmp;
}
ps->a[ps->top] = x;
ps->top++;
}
从栈顶取出元素
注意这里的第二个assert()函数,非空继续执行程序,为空终止程序。
注意返回的时候应写为ps->a[ps->top-1],错误的写法是ps->a[ps->top–],这样数组就发生了越界访问,并且删除了栈顶元素,因为此时的top被修改了,当然,也不能写为ps->a[ps->–top]。
STDataType StackTop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
return ps->a[ps->top-1];
}
删除栈顶元素
在第二个assert()函数中使用判空函数,可以防止数组越界访问。
这里只需要将数组元素个数(top)自身-1,只要我们以后依据数组元素个数(top)访问不到之后的数据就ok啦。
void StackPop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
ps->top--;
}
测试
头文件
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
测试
这里要注意的是如果想取栈顶下一个数据,就要删掉栈顶数据,使栈顶的下一个元素成为新的栈顶。
int main()
{
ST stack;
StackInit(&stack);
StackPush(&stack, 1);
StackPush(&stack, 2);
StackPush(&stack, 3);
StackPush(&stack, 4);
printf("%d ", StackTop(&stack));
StackPop(&stack);
printf("%d ", StackTop(&stack));
StackPop(&stack);
StackPush(&stack, 5);
StackPush(&stack, 6);
while (!StackEmpty(&stack))
{
printf("%d ", StackTop(&stack));
StackPop(&stack);
}
StackDestroy(&stack);
return 0;
}
运行结果
这里设计的程序是先出了4 3 再进了 5 6 然后再从后进的 6 开始出在数组中剩下的元素。