使用C语言实现链式栈

一、栈的基本概念

        栈(Stack)是一种数据结构,它遵循“后进先出”(LIFO, Last In First Out)的原则。这意味着最后一个插入栈的元素最先被删除,你可以理解成一堆盘子,每次只能取最上面的盘子,删除的时候也只能删除最上面的盘子。这样是不是更容易理解了呢?栈的基本操作包括:

  1. 入栈(Push):将一个元素压入栈顶。
  2. 出栈(Pop):将栈顶元素弹出并返回该元素。
  3. 查看栈顶元素(Top):返回栈顶元素的值,但不弹出该元素。
  4. 获取栈的大小(Size):返回栈中元素的个数。
  5. 栈的创建和销毁:创建一个新的空栈并初始化,销毁栈时释放所有元素的内存。

栈有两种主要的实现方式:数组(顺序栈)和链表(链式栈)。本文将重点介绍链式栈的实现方式。

二、链式栈的实现

        链式栈利用链表实现,栈顶对应链表的头结点。每个结点包含一个数据域和一个指向下一个结点的指针。栈的操作在链表的头部进行,具体来说:

  • 入栈操作:每次添加新元素时,新元素成为链表的头结点。新的头结点指向原来的头结点。
  • 出栈操作:每次删除元素时,删除的是链表的头结点。删除后,原头结点的下一个结点成为新的头结点。

三、栈的结构定义

我们首先定义栈中元素的类型,以及链表结点和栈的结构体。

#include <stdio.h>
#include <stdlib.h>

// 定义栈中元素的类型
#define eleType int

// 定义链表结点的结构体
typedef struct Node 
{	
    eleType data;        // 数据域
    struct Node* next;   // 指针域
} Node;

// 定义栈的结构体
typedef struct
{
    Node* head;          // 栈顶指针
    size_t size;         // 栈的大小
} stack;
  • eleType 定义了栈中元素的类型,这里我们定义为 int 类型。你可以根据需要修改为其他类型。
  • Node 结构体表示链表的结点,每个结点包含一个数据域和一个指向下一个结点的指针。
  • stack 结构体表示栈,包含一个指向栈顶结点的指针 head 和栈的大小 size

四、栈的创建

栈的创建函数用于初始化栈,使其处于空状态。

// 栈的创建函数
void StackCreate(stack* stk)
{
    stk->head = NULL;    // 初始化栈顶指针为NULL
    stk->size = 0;       // 初始化栈的大小为0
}
  • StackCreate 函数接收一个指向 stack 结构体的指针 stk,将 stkhead 初始化为 NULL,表示栈为空。
  • 同时,将 stksize 初始化为 0,表示栈的元素个数为零。

五、栈的销毁

栈的销毁函数用于释放栈中所有结点的内存,并将栈重置为初始状态。

// 栈的销毁函数
void StackDestroy(stack* stk)
{
    while (stk->head)    // 从头结点开始遍历,直到空结点
    {
        Node* next = stk->head->next; // 将头结点的后继结点存入到next变量中
        free(stk->head);              // 释放头结点所占空间
        stk->head = next;             // 将栈的头结点更新为next
    }
    stk->size = 0;       // 重置栈的大小为0
}
  • StackDestroy 函数接收一个指向 stack 结构体的指针 stk,循环遍历栈中的每个结点。
  • 在循环中,保存当前结点的下一个结点指针,释放当前结点的内存,然后将栈顶指针 head 更新为下一个结点。
  • 最后,将 size 重置为 0,表示栈已被清空。

六、入栈操作

入栈操作将一个新元素添加到栈顶。(一盘碟子上面加碟子doge~)

// 入栈函数
void StackPush(stack* stk, eleType element)
{
    Node* newNode = (Node*)malloc(sizeof(Node)); // 创建动态链表结点
    newNode->data = element;  // 将元素element赋值给data成员变量
    newNode->next = stk->head; // 将next结点指向栈当前的头结点
    stk->head = newNode;       // 更新头结点为newNode
    stk->size++;               // 更新栈的大小加1
}
  • StackPush 函数接收一个指向 stack 结构体的指针 stk 和一个元素 element
  • 创建一个新的结点 newNode,将 element 赋值给 newNode 的数据域 data
  • newNode 的指针域 next 指向当前的栈顶结点 head
  • stkhead 更新为 newNode,表示新结点成为栈顶。
  • size 加1,更新栈的大小。

七、出栈操作

出栈操作将栈顶元素移除,并返回该元素的值。(把最上面的碟子取下来doge~)

// 出栈函数
eleType StackPop(stack* stk)
{
    if (stk->size == 0)
    {
        printf("Stack underflow!\n");
        exit(1);    // 判断栈是否为空,如果为空,退出程序
    }
    
    eleType result = stk->head->data;  // 获取栈顶元素
    Node* next = stk->head->next;      // 保存下一个结点
    free(stk->head);                   // 释放当前栈顶结点
    stk->head = next;                  // 更新栈顶指针
    stk->size--;                       // 栈的大小减1
    return result;                     // 返回栈顶元素
}
  • StackPop 函数接收一个指向 stack 结构体的指针 stk
  • 首先检查栈是否为空,如果 size0,打印错误信息并退出程序。
  • 获取当前栈顶元素的数据域 data 并保存到 result
  • 保存当前栈顶结点的下一个结点指针 next
  • 释放当前栈顶结点的内存。
  • stkhead 更新为 next,即栈顶指针指向下一个结点。
  • size 减1,更新栈的大小。
  • 返回保存的栈顶元素 result

八、获取栈顶元素

该函数用于返回栈顶元素的值,但不移除该元素。

// 获取栈顶元素函数
eleType StackTop(stack* stk)
{
    if (stk->size == 0)
    {
        printf("Stack is empty!\n");
        exit(1);    // 判断栈是否为空,如果为空,退出程序
    }
    return stk->head->data;   // 返回栈顶元素
}
  • StackTop 函数接收一个指向 stack 结构体的指针 stk
  • 首先检查栈是否为空,如果 size0,打印错误信息并退出程序。
  • 返回当前栈顶结点的数据域 data

九、获取栈的大小

该函数用于返回栈中元素的个数。

// 获取栈的大小函数
int StackSize(stack* stk)
{
    return stk->size;    // 返回栈的大小
}
  • StackSize 函数接收一个指向 stack 结构体的指针 stk
  • 返回栈的大小 size

十、示例代码

我们通过一个示例来展示如何使用上述函数来操作栈。

int main() 
{
    stack stk;
    StackCreate(&stk);

    StackPush(&stk, 10);
    StackPush(&stk, 20);
    StackPush(&stk, 30);

    printf("Stack top element: %d\n", StackTop(&stk));
    printf("Stack size: %d\n", StackSize(&stk));

    printf("Popped element: %d\n", StackPop(&stk));
    printf("Stack top element: %d\n", StackTop(&stk));
    printf("Stack size: %d\n", StackSize(&stk));

    StackDestroy(&stk);
    printf("Stack size after destroy: %d\n", StackSize(&stk));

    return 0;
}
  • 创建一个栈 stk 并初始化。
  • 10, 20, 30 三个元素依次压入栈。
  • 获取并打印栈顶元素和栈的大小。
  • 弹出一个元素并打印弹出的元素、当前栈顶元素和栈的大小。
  • 销毁栈并打印销毁后的栈的大小。

输出结果:

Stack top element: 30
Stack size: 3
Popped element: 30
Stack top element: 20
Stack size: 2
Stack size after destroy: 0

总结 

        通过定义链表结点和栈结构体,我们能够创建、销毁、入栈、出栈、查看栈顶元素以及获取栈的大小。使用链表实现栈的关键在于对头结点的操作:

  • 入栈:每次添加新元素时,我们创建一个新的结点并将其设为新的头结点,新结点指向原来的头结点。
  • 出栈:每次删除元素时,我们删除当前的头结点,更新头结点为下一个结点。

这种实现方式充分利用了链表的动态内存分配特性,使得栈操作简单且高效。

希望对大家有所帮助,求赞支持一下~

  • 30
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值