顺序栈的总结

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;

 

}

 

如果想把开辟的数组的其实位置看做栈顶的话,在每次入队的时候记得把所有已经存在的数据向后移动一个位置,同时出栈的时候,需要向前移动一个位置。

 

以上是关于顺序栈的总结的主要内容,如果未能解决你的问题,请参考以下文章

数据结构学习笔记(栈队列)整理与总结

数据结构第三章学习总结

栈的入栈和出栈的顺序规律是啥?

数据结构学习笔记——栈的基本知识和顺序存储结构实现栈(顺序栈)

数据结构学习笔记——顺序存储结构实现栈

数据结构5 栈