怎样在 C 语言中实现栈?

🍅关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会!
📙C 语言百万年薪修炼课程 通俗易懂,深入浅出,匠心打磨,死磕细节,6年迭代,看过的人都说好。

分割线

文章目录

  • 如何在 C 语言中实现栈
  • 一、栈的基本概念
  • 二、栈的操作
  • 三、使用数组实现栈
  • 四、使用链表实现栈
  • 五、两种实现方式的比较
    • (一)空间复杂度
    • (二)时间复杂度
    • (三)灵活性
    • (四)适用场景
  • 六、栈的应用场景
    • (一)函数调用
    • (二)表达式求值
    • (三)括号匹配
    • (四)回溯算法
  • 七、总结

分割线


如何在 C 语言中实现栈

在 C 语言中,栈(Stack)是一种常见的数据结构,它遵循后进先出(Last In First Out,LIFO)的原则。这意味着最后添加到栈中的元素将首先被移除。

一、栈的基本概念

栈是一种线性数据结构,具有以下特点:

  1. 栈顶(Top):栈的顶部元素,是进行插入和删除操作的一端。
  2. 栈底(Bottom):栈的底部元素,是相对固定的一端。

二、栈的操作

常见的栈操作包括:

  1. push:将元素压入栈顶。
  2. pop:弹出栈顶元素。
  3. peek(或者 top):获取栈顶元素但不弹出。
  4. isEmpty:判断栈是否为空。

三、使用数组实现栈

以下是使用数组来实现栈的 C 语言代码示例:

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>#define MAX_SIZE 100typedef struct {int items[MAX_SIZE];int top;
} Stack;// 初始化栈
void initStack(Stack *stack) {stack->top = -1;
}// 判断栈是否为空
bool isEmpty(Stack *stack) {return stack->top == -1;
}// 判断栈是否已满
bool isFull(Stack *stack) {return stack->top == MAX_SIZE - 1;
}// 压入元素到栈
void push(Stack *stack, int element) {if (isFull(stack)) {printf("Stack Overflow!\n");return;}stack->items[++stack->top] = element;
}// 弹出栈顶元素
int pop(Stack *stack) {if (isEmpty(stack)) {printf("Stack Underflow!\n");return -1;}int element = stack->items[stack->top];stack->top--;return element;
}// 获取栈顶元素但不弹出
int peek(Stack *stack) {if (isEmpty(stack)) {printf("Stack is empty!\n");return -1;}return stack->items[stack->top];
}int main() {Stack stack;initStack(&stack);push(&stack, 10);push(&stack, 20);push(&stack, 30);printf("Top element: %d\n", peek(&stack));int poppedElement = pop(&stack);if (poppedElement!= -1) {printf("Popped element: %d\n", poppedElement);}printf("Top element after pop: %d\n", peek(&stack));return 0;
}

在上述代码中:

  • initStack 函数用于初始化栈,将栈顶指针设置为 -1,表示栈为空。
  • isEmpty 函数通过检查栈顶指针是否为 -1 来判断栈是否为空。
  • isFull 函数通过检查栈顶指针是否达到数组的最大索引来判断栈是否已满。
  • push 函数在压入元素之前,先检查栈是否已满。如果未满,将元素添加到栈顶,并更新栈顶指针。
  • pop 函数在弹出元素之前,先检查栈是否为空。如果不为空,返回栈顶元素,并更新栈顶指针。
  • peek 函数返回栈顶元素,但不修改栈的状态。

四、使用链表实现栈

除了使用数组,我们还可以使用链表来实现栈。以下是使用链表实现栈的 C 语言代码示例:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>typedef struct Node {int data;struct Node *next;
} Node;typedef struct {Node *top;
} Stack;// 初始化栈
void initStack(Stack *stack) {stack->top = NULL;
}// 判断栈是否为空
bool isEmpty(Stack *stack) {return stack->top == NULL;
}// 压入元素到栈
void push(Stack *stack, int element) {Node *newNode = (Node *)malloc(sizeof(Node));if (newNode == NULL) {printf("Memory allocation failed!\n");return;}newNode->data = element;newNode->next = stack->top;stack->top = newNode;
}// 弹出栈顶元素
int pop(Stack *stack) {if (isEmpty(stack)) {printf("Stack Underflow!\n");return -1;}Node *temp = stack->top;int element = temp->data;stack->top = stack->top->next;free(temp);return element;
}// 获取栈顶元素但不弹出
int peek(Stack *stack) {if (isEmpty(stack)) {printf("Stack is empty!\n");return -1;}return stack->top->data;
}// 打印栈
void printStack(Stack *stack) {Node *current = stack->top;printf("Stack: ");while (current!= NULL) {printf("%d ", current->data);current = current->next;}printf("\n");
}int main() {Stack stack;initStack(&stack);push(&stack, 10);push(&stack, 20);push(&stack, 30);printStack(&stack);int poppedElement = pop(&stack);if (poppedElement!= -1) {printf("Popped element: %d\n", poppedElement);}printStack(&stack);printf("Top element: %d\n", peek(&stack));return 0;
}

在这个链表实现的栈中:

  • 每个节点包含数据和指向下一个节点的指针。
  • initStack 函数将栈顶指针初始化为 NULL,表示空栈。
  • push 函数创建一个新节点,将其数据设置为要压入的元素,并将其链接到当前栈顶节点之前,更新栈顶指针。
  • pop 函数如果栈不为空,删除栈顶节点,返回其数据,并更新栈顶指针,同时释放已删除节点的内存。
  • peek 函数返回栈顶节点的数据。
  • printStack 函数用于打印栈中的所有元素。

五、两种实现方式的比较

(一)空间复杂度

  • 数组实现:在创建栈时需要预先分配固定大小的连续内存空间。如果栈的实际使用空间小于预分配的空间,会造成一定的内存浪费;如果栈的实际使用空间超过预分配的空间,还需要进行扩容操作,可能涉及到数据的复制和内存的重新分配,增加了额外的开销。
  • 链表实现:每个节点在需要时动态分配内存,不会造成内存的预先浪费。但是,每个节点除了存储数据外,还需要额外的空间来存储指针,因此会有一些额外的内存开销。

(二)时间复杂度

  • 数组实现:
    • push 操作:在栈未满的情况下,时间复杂度为 O(1)
    • pop 操作:在栈不为空的情况下,时间复杂度为 O(1)
    • 访问栈顶元素:时间复杂度为 O(1)
  • 链表实现:
    • push 操作:需要创建新节点并更新指针,时间复杂度为 O(1)
    • pop 操作:需要删除节点并更新指针,时间复杂度为 O(1)
    • 访问栈顶元素:时间复杂度为 O(1)

总体来说,两种实现方式在常见操作的时间复杂度上是相同的。

(三)灵活性

  • 数组实现:由于数组的大小是固定的,在需要动态调整栈的大小时,操作相对复杂。
  • 链表实现:可以更灵活地添加和删除元素,不需要考虑固定大小的限制。

(四)适用场景

  • 数组实现:适用于事先知道栈的最大规模,并且对内存使用较为敏感的场景。
  • 链表实现:适用于无法确定栈的最大规模,或者需要更灵活地管理栈的空间的场景。

六、栈的应用场景

(一)函数调用

在计算机程序中,当一个函数调用另一个函数时,系统会将当前函数的执行上下文(包括参数、局部变量、返回地址等)压入栈中。当被调用函数执行完毕后,系统从栈中弹出之前保存的执行上下文,恢复到调用函数继续执行。

(二)表达式求值

在对算术表达式进行求值时,可以使用栈来存储操作数和运算符。通过按照特定的规则进行入栈和出栈操作,可以实现表达式的正确求值。

(三)括号匹配

检查一段包含括号(如 ()[]{})的文本中括号是否匹配,可以使用栈来辅助判断。遇到左括号入栈,遇到右括号时与栈顶的左括号进行匹配,如果匹配成功则弹出栈顶元素,否则表示括号不匹配。

(四)回溯算法

在一些需要回溯的算法中,如深度优先搜索、八皇后问题等,可以使用栈来保存中间状态,以便在需要时进行回溯。

七、总结

在 C 语言中,我们可以使用数组或链表来实现栈。两种实现方式各有优缺点,应根据具体的应用场景选择合适的实现方式。理解栈的概念和实现原理对于解决许多编程问题非常有帮助,并且在实际的开发中有着广泛的应用。


分割线

🎉相关推荐

  • 📙C 语言百万年薪修炼课程 通俗易懂,深入浅出,匠心打磨,死磕细节,6年迭代,看过的人都说好。
  • 🍅博客首页-关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会!
  • 📙CSDN专栏-C语言修炼
  • 📙技术社区-墨松科技

C语言



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/374708.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IT运维也有自己的节日 724向日葵IT运维节,三大版本如何选?

“724运维节”&#xff0c;是2016年由开放运维联盟发起倡议&#xff0c;广大运维人员共同投票产生的属于运维人自己的节日。 对于运维人最大的印象&#xff0c;那就是工作都需要7x24小时待命&#xff0c;是名副其实的“日不落骑士”&#xff0c;这也是大家选择724这一天作为运…

【chatgpt消费者偏好】是什么驱动了游客持续旅游意愿?推文分享—2024-07-08

今天推文的主题是【chatgpt&消费者意愿】 第一篇&#xff1a;文章主要研究了什么因素驱动旅游者继续使用ChatGPT进行旅行服务&#xff0c;并从人类拟态的角度探讨了旅游者对ChatGPT的感知和使用意图。第二篇&#xff1a;本文探讨了ChatGPT-4在生成针对TripAdvisor上发布的…

【car】深入浅出学习机械燃油车知识、结构、原理、维修、保养、改装、编程

汽车的五大总成通常是指发动机、变速器、前后桥、车架和悬挂系统。 发动机&#xff1a;是汽车的动力来源&#xff0c;负责将燃料的化学能转化为机械能&#xff0c;驱动汽车行驶。常见的发动机类型有内燃机&#xff08;如汽油发动机、柴油发动机&#xff09;和电动机&#xff0…

什么是海外仓管理自动化?策略及落地实施步骤指南

作为海外仓的管理者&#xff0c;你每天都面临提高海外仓运营效率、降低成本和满足客户需求的问题。海外仓自动化管理技术为这些问题提供了不错的解决思路&#xff0c;不过和任何新技术一样&#xff0c;从策略到落地实施&#xff0c;都有一个对基础逻辑的认识过程。 今天我们整…

攻防世界 (Django @宽字节注入)Cat

这道题进来首先是让你输入域名&#xff0c;我输入了一个baidu.com发现无响应&#xff0c;输入127.0.0.1后发现执行了一个ping命令 我首先想到的就是命令注入&#xff0c;然而输入127.0.0.1||id 127.0.0.1&&id 127.0.0.1;ls;等后均显示无效的URL&#xff0c;很明显过滤了…

PyCharm 2023.3.2 关闭时一直显示正在关闭项目

文章目录 一、问题描述二、问题原因三、解决方法 一、问题描述 PyCharm 2023.3.2 关闭时一直显示正在关闭项目 二、问题原因 因为PyCharm还没有加载完索引导致的 三、解决方法 方法一&#xff1a; 先使用任务管理器强制关闭&#xff0c;下次关闭时注意要等待PyCharm加载完索…

Docker Push Docker Hub

首先可以参考 Docker | 将自己的docker镜像推送到docker hub[图文详情]_如何将自己的docker镜像上传到dockerhub上-CSDN博客 将自己的镜像打标签 和 镜像推送到 docker hub上的图文注意一下 1.打标签之前 docker tag paddleocr_fast_api:1.0 hmgx/wlx:3.0 2.打标签之后 3.开…

..质数..

先弄清楚我们在上小学时 学的概念。 1、什么是质因数&#xff1f; -质因数是指能够整除给定正整数的质数。每个正整数都可以被表示为几个质数的乘积&#xff0c;这些质数就是该数的质因数。质因数分解是将一个正整数分解成若干个质数相乘的过程。例如&#xff0c;数字 12…

Jenkins教程-18-常用插件-description-setter

上一小节我们学习了Jenkin常用插件Environment Injector的使用方法&#xff0c;本小节我们讲解一下Jenkin常用插件description-setter的使用方法。 在某些情况下&#xff0c;用户可能希望根据构建过程中的某些关键信息来自定义构建的描述&#xff0c;比如部署的用户信息、提交…

【蓄势·致远】 同为科技(TOWE)2024年年中会议

2024年7月2日-8日&#xff0c;同为科技&#xff08;TOWE&#xff09;召开2024年年中工作会议。会议回顾上半年总体工作情况&#xff0c;分析研判发展形势&#xff0c;规划部署下半年工作。 为期一周的工作会议&#xff0c;由同为科技&#xff08;TOWE&#xff09;创始人、董事长…

深入剖析C++的 “属性“(Attribute specifier sequence)

引言 在阅读开源项目源代码是&#xff0c;发现了一个有趣且特殊的C特性&#xff1a;属性。 属性&#xff08;attribute specifier sequences&#xff09;是在C11标准引入的。在C11之前&#xff0c;编译器特有的扩展被广泛用来提供额外的代码信息。例如&#xff0c;GNU编译器&…

水库大坝安全监测险情应对措施

汛期暴雨洪涝灾害发生后&#xff0c;为保证大坝及下游人民生命财产安全&#xff0c;应及时进行大坝安全现场检查和快速评估。评估内容包括大坝沉降和水平变形、裂缝、坝坡是否塌滑、下游坡是否存在集中渗漏或大面积渗水、溢洪道启闭设备能否正常运行、近坝库岸是否有大的滑坡体…

【python】PyQt5对象类型的判定,对象删除操作详细解读

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

汽车预约维修小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;技师管理&#xff0c;技师信息管理&#xff0c;用户预约管理&#xff0c;取消预约管理&#xff0c;订单信息管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;技师信息&a…

Ajax从零到实战

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…

Unity实现安卓App预览图片、Pdf文件和视频的一种解决方案

一、问题背景 最近在开发app项目&#xff0c;其中有个需求就是需要在app软件内显示图片、pdf和视频&#xff0c;一开始想的解决方案是分开实现&#xff0c;也就是用Image组件显示图片&#xff0c;找一个加载pdf的插件和播放视频的插件&#xff0c;转念一想觉得太麻烦了&#x…

Lumos学习王佩丰Excel第四讲:排序与选择

一、排序 1、简单排序&#xff1a;不要选中一列排序&#xff0c;不然只是局部排序&#xff0c;其他数据都会发生错乱。 2、多条件排序 3、2003版本中超过3个排序条件时如何处理&#xff1a;从最后一个条件到第一个条件倒着按照要求依次排序。 4、按颜色排序 5、自定义排序次序…

LabVIEW在半导体自动化测试中的应用

半导体制造的复杂性和精密度要求极高&#xff0c;每一个生产步骤都需要严格的控制和监测。自动化测试设备在半导体制造中起到了关键作用&#xff0c;通过精密测量和数据分析&#xff0c;确保产品质量和生产效率。本文介绍如何使用LabVIEW结合研华硬件&#xff0c;开发一个用于半…

腾讯广告优量汇Android一面凉经(2024)

腾讯广告优量汇Android一面凉经(2024) 笔者作为一名双非二本毕业7年老Android, 最近面试了不少公司, 目前已告一段落, 整理一下各家的面试问题, 打算陆续发布出来, 供有缘人参考。今天给大家带来的是《腾讯广告优量汇Android一面凉经(2024)》。 面试职位: 腾讯广告优量汇-SDK客…

ensp防火墙实验

实验拓扑图 实验要求 1&#xff0c;DMZ区内的服务器&#xff0c;办公区仅能在办公时间内(9:00-18:00)可以访问&#xff0c;生产区的设备全天可以访问。 2&#xff0c;生产区不允许访问互联网&#xff0c;办公区和游客区允许访问互联网 3&#xff0c;办公区设备10.0.2.10不允…