顺序栈的总结
Posted 菜鸟沃土
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了顺序栈的总结相关的知识,希望对你有一定的参考价值。
基本数据结构之-顺序栈
栈是一种先进后出的数据结构,我们可以使用一个数组来模拟栈的这种结构,将数组的尾部当做栈的栈顶似乎是一个不错的选择(插入和移除元素是不涉及到数据的移动),也可以很好的控制数组的长度,和数据的进栈和出栈!
首先先解析一下顺序栈的数据结构
1 需要一个数据域来存储数据 考虑到可能存储自定义的数据类型,所以我们选择存储每个数据的开始的地址 (void **stack)
2 需要一个值来记录当前的数据域的长度 (size)
3 需要一个值来记录当前的容器的长度
typedef struct _QUEUESTACK
{
// 栈的数据
void **Stack;
// 栈的数据长度
int Size;
// 栈的容量
int Capacity;
}QueueStack;
接下来是栈的初始化
需要传入一个容量的参数,主要是测试的时候,我可以把长度设置小一点,哈哈!
// 初始化栈
int Init_QueueStack(void **queuestack, int capacity)
{
if (queuestack == NULL)
{
exit(-1);
}
// 定义一个栈结构体的指针
QueueStack *stack = (QueueStack *)malloc(sizeof(QueueStack));
// 判断开辟内存是否成功
if (stack == NULL)
{
exit(-2);
}
// 为stack 开辟一段堆内存
stack->Stack = (void **)malloc(sizeof(void *)*capacity);
// 判断开辟内存是否成功
if (stack->Stack == NULL)
{
exit(-2);
}
// 写入相关的变化
stack->Capacity = capacity;
stack->Size = 0;
// 将开辟出来的空间置零
memset(stack->Stack, 0, sizeof(void *)*stack->Capacity);
*queuestack = stack;
return 0;
}
入栈,当数据的长度等于容量时需要动态的开辟新的空间
//入栈
int Push_QueueStack(void *queuestack, void *data)
{
// 对传入的参数做判断
if (queuestack == NULL)
{
return -1;
}
if (data == NULL)
{
return -2;
}
// 将指针转化为我们可以操作的类型
QueueStack *stack = (QueueStack *)queuestack;
if (stack->Size == stack->Capacity)
{
// 当数据域的长度不够时,进行动态开辟
void ** newStack = (void **)malloc(stack->Capacity * 2);
if (newStack == NULL)
{
return -3;
}
// 将开辟的空间全部置零
memset(newStack, 0, sizeof(void *)* stack->Capacity * 2);
// 将原来的数据拷贝到新的栈
memcpy(newStack, stack->Stack, sizeof(void *)*stack->Capacity);
// 释放原来栈的空间
free(stack->Stack);
// 将栈的数据域指向新的位置
stack->Stack = newStack;
stack->Capacity *= 2;
}
// 将数据加入到栈的数据域中
stack->Stack[stack->Size] = data;
++stack->Size;
return 0;
}
//出栈 当数据域的长度为0 时,就不能正常的出栈了
int Pop_QueueStack(void *queuestack)
{
if (queuestack == NULL)
{
return -1;
}
// 将指针转化为我们可以操作的类型
QueueStack *stack = (QueueStack *)queuestack;
// 数据域没数据没法出栈
if (stack->Size == 0)
{
return -2;
}
else
{
// 先将长度减一
--stack->Size;
// 将最后一个元素的位置空
stack->Stack[stack->Size] = NULL;
}
return 0;
}
获取栈顶的元素 当栈的数据域的长度为0 时 栈顶元素为空
void * Top_QueueStack(void *queuestack)
{
if (queuestack == NULL)
{
return NULL;
}
// 将指针转化为我们可以操作的类型
QueueStack *stack = (QueueStack *)queuestack;
// 数据域没数据没法出栈
if (stack->Size == 0)
{
return NULL;
}
else
{
return stack->Stack[stack->Size - 1];
}
}
销毁栈,一定要记住不要释放数据域,因为存储的是地址,我们并不知道需要释放的是开辟的堆内存还是栈内存,也不知道每个地址下的数据域的长度,所以还是交给使用者去释放吧
int Destory_QueueStack(void *queuestack)
{
if (queuestack == NULL)
{
return -1;
}
// 将指针转化为我们可以操作的类型
QueueStack *stack = (QueueStack *)queuestack;
if (stack->Stack != NULL)
{
// 不知道这段内存的位置(栈内存还是堆内存) 里面存储的是地址 由使用者自己管理
//free(stack->Stack);
stack->Stack = NULL;
stack->Size = 0;
stack->Capacity = 0;
}
free(stack);
return 0;
}
// 栈的长度
int Size__QueueStack(void *queuestack)
{
if (queuestack == NULL)
{
return -1;
}
// 将指针转化为我们可以操作的类型
QueueStack *stack = (QueueStack *)queuestack;
return stack->Size;
}
如果想把开辟的数组的其实位置看做栈顶的话,在每次入队的时候记得把所有已经存在的数据向后移动一个位置,同时出栈的时候,需要向前移动一个位置。
以上是关于顺序栈的总结的主要内容,如果未能解决你的问题,请参考以下文章