【数据结构】使用C语言 从零实现一个栈的数据结构

什么是栈?栈是一种特殊的线性表,它只能在在表尾进行插入和删除操作。

栈的底部称为栈底,顶部称为栈顶,所有的操作只能在栈顶进行,也就是说,被压在下方的元素,只能等待其上方的元素出栈之后才能取出,就像我们往箱子里里面放的书一样,因为只有一个口取出里面的物品,所以被压在下面的书只能等上面的书被拿出来之后才能取出,这就是栈的思想,它是一种先进后出的数据结构。

使用C语言实现栈

一般使用栈这样的机构,常用的两个操作就是入栈和出栈

  • pop:出栈操作,将栈顶的元素取出,并删除
  • push:入栈操作,将新元素置入栈顶

定义数据结构

我们在栈的底层使用数组进行存储,所以结构中将储存一个数组的指针,和数组的容量(方便初始化和申请内存);另外栈只能操作栈顶的元素,所以结构中还存着一个变量top,表示栈顶的元素。

c 复制代码
typedef int E;

struct Stack
{
    E * array; // 一个数组的指针
    int capacity; // 数组的容量
    int top;  // 栈顶的元素
};

typedef struct Stack * stack;

再给栈结构的指针起一个别名,便于后续对栈进行操作。

定义初始化方法

接着我们定义一个初始化栈的方法,在初始化方法中,我们默认初始化时,底层数组的最大容量是10个内存单位,也就是40字节(因为E是int类型),接着我们定义,刚初始化完栈之后是一个空栈,则栈顶的指针默认为-1。

top变量是为后续的入栈出栈操作做铺垫的,它可以当作数组的索引,也可以用来当作是否是空栈的标识。

c 复制代码
int initStack(stack stack)
{
    stack->array = malloc(sizeof(E) * 10); // 申请一个40字节的内存
    if (stack->array == NULL) return 0;
    stack->capacity = 10; // 记录底层数组的容量
    stack->top = -1;  // 栈没有元素默认为-1

    return 1;
}

在main函数中,实例化一个Stack类型,接着使用initStack函数就完成了栈的初始化:

c 复制代码
int main()
{
    struct Stack stack;
    initStack(&stack);


    return 0;
}

实现入栈操作

入栈操作,就是把一个元素放到栈的最上方,也就是栈顶上,所以实现该操作的函数只需要有两个参数就可以了:

  • 栈的指针
  • 需要入栈的元素

另外,底层数组的默认容量是10,如果入栈超过10个元素的话,内存就会造成泄露,所以对底层数组进行扩容操作也是必不可少的。

c 复制代码
int pushStack(stack stack,E element)
{
    if (stack->top == stack->capacity - 1) // 扩容
    {
        int newCapacity = stack->capacity * 2;
        E* newArray = realloc(stack->array,newCapacity * sizeof(E));
        if (newArray == NULL) return 0;
        stack->array = newArray;
        stack->capacity = newCapacity;
    }

    stack->top++;
    stack->array[stack->top] = element;
    
    return 1;
}

在扩容操作中,我们使用realloc函数将原数组拷贝到一个新的大小的内存中,这个内存地址我们使用newArray来接收,最后将原栈中的array指向newArray,将原栈中的capacity 指向newCapacity

简单编写一个打印栈元素的函数,用于测试栈:

c 复制代码
void printStack(stack stack)
{
    printf("|");
    for (int i = 0;i<=stack->top;i++)
    {
        printf("%d, ",stack->array[i]);
    }

    printf("\n");
}

int main()
{
    struct Stack stack;
    initStack(&stack);

    for(int i = 1;i<=10;i++)
    {
        pushStack(&stack,i);
    }

    printStack(&stack);

    return 0;
}

控制台输出:

|1, 2, 3, 4, 5, 6, 7, 8, 9, 10,

入栈操作成功实现~

实现出栈操作

出栈操作就是把栈顶的元素取出,然后把top执行自减操作,如果不自减元素出栈之后栈顶的元素还会是原来的元素。

c 复制代码
E popStack(stack stack)
{
    if (stack->top == -1)
    {
        printf("栈为空,不能出栈\n");
        return -1;
    }
    
    E element = stack->array[stack->top];
    stack->top--;

    return element;
}

我们接着测试一下:

c 复制代码
void printStack(stack stack)
{
    printf("|");
    for (int i = 0;i<=stack->top;i++)
    {
        printf("%d, ",stack->array[i]);
    }

    printf("\n");
}

int main()
{
    struct Stack stack;
    initStack(&stack);

    for(int i = 1;i<=20;i++)
    {
        pushStack(&stack,i);
    }

    printStack(&stack);

    printf("出栈的元素顺序:");
    while (1)
    {
        printf("%d, ",stack.array[stack.top]);
        popStack(&stack);
        if (stack.top == -1) break;
    }

    return 0;
}

会发现控制台输出的信息为:

|1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
出栈的元素顺序:20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,

出栈的顺序是从20到1的,说明元素是从栈顶依次出去的,至此出栈操作也实现好了。

总结

使用C语言手动把栈的结构和各种操作实现一遍是很重要的,它能够加深学习者对计算机底层的认识,也能够为后续的算法题的解题提供一种新的思路。

本篇博文所有代码:

c 复制代码
#include "stdio.h"
#include "stdlib.h"

typedef int E;

struct Stack
{
    E * array; // 一个数组的指针
    int capacity; // 数组的容量
    int top;  // 栈顶的元素
};

typedef struct Stack * stack;

int initStack(stack stack)
{
    stack->array = malloc(sizeof(E) * 10); // 申请一个40字节的内存
    if (stack->array == NULL) return 0;
    stack->capacity = 10; // 记录底层数组的容量
    stack->top = -1;  // 栈没有元素默认为-1

    return 1;
}

int pushStack(stack stack,E element)
{
    if (stack->top == stack->capacity - 1) // 扩容
    {
        int newCapacity = stack->capacity * 2;
        E* newArray = realloc(stack->array,newCapacity * sizeof(E));
        if (newArray == NULL) return 0;
        stack->array = newArray;
        stack->capacity = newCapacity;
    }

    stack->top++;
    stack->array[stack->top] = element;

    return 1;
}

E popStack(stack stack)
{
    if (stack->top == -1)
    {
        printf("栈为空,不能出栈\n");
        return -1;
    }

    E element = stack->array[stack->top];
    stack->top--;

    return element;
}

void printStack(stack stack)
{
    printf("|");
    for (int i = 0;i<=stack->top;i++)
    {
        printf("%d, ",stack->array[i]);
    }

    printf("\n");
}

int main()
{
    struct Stack stack;
    initStack(&stack);

    for(int i = 1;i<=20;i++)
    {
        pushStack(&stack,i);
    }

    printStack(&stack);

    printf("出栈的元素顺序:");
    while (1)
    {
        printf("%d, ",stack.array[stack.top]);
        popStack(&stack);
        if (stack.top == -1) break;

    }

    return 0;
}
相关推荐
托尼沙滩裤23 分钟前
【js面试题】js的数据结构
前端·javascript·数据结构
逆水寻舟1 小时前
算法学习记录2
python·学习·算法
羞儿1 小时前
【读点论文】基于二维伽马函数的光照不均匀图像自适应校正算法
人工智能·算法·计算机视觉
续亮~2 小时前
6、Redis系统-数据结构-03-压缩列表
数据结构·数据库·redis
青衫酒1452 小时前
中国剩余定理
算法
akthwyl3 小时前
2024年【安全员-C证】考试及安全员-C证免费试题
c语言·开发语言
鸽鸽程序猿3 小时前
【数据结构】顺序表
java·开发语言·数据结构·学习·算法·intellij idea
Chris-zz3 小时前
C++:继承
开发语言·c++·算法·学习方法
硕风和炜3 小时前
【LeetCode:3033. 修改矩阵 + 模拟】
java·算法·leetcode·矩阵·模拟
取加若则_4 小时前
C++入门(C语言过渡)
c语言·开发语言·数据结构·c++·算法