数据结构(顺序栈——c语言实现)

news2024/11/22 19:52:41

栈的基本概念:

       栈是限制在一端进行插入操作和删除操作的线性表(俗称堆栈),允许进行操作的一端称为“栈顶”,另一固定端称为“栈底”,当栈中没有元素时称为“空栈”

       特点:先进后出(FILO)或后进先出(LIFO)

栈的优点

  1. 方便快捷:栈的操作非常明确,主要包括Push(压栈)和Pop(弹栈)两个操作,非常方便快捷。

  2. 逻辑清晰:栈的特性使得程序的逻辑非常清晰,因为它保证了操作的顺序和依赖关系。例如,在函数调用中,每进入一个函数,都会将临时变量作为栈帧入栈;当被调用函数执行完成返回后,将这个函数对应的栈帧出栈。这种顺序关系使得程序更易于理解和维护。

  3. 节省空间:栈是一种线性的数据结构,通常只需要在内存中分配一块连续的空间来存储元素,因此可以节省空间。此外,栈的插入和删除操作(即压栈和弹栈)通常只涉及栈顶元素,因此这些操作的时间复杂度较低,通常为O(1)。

  4. 支持递归:栈的特性使得它可以支持递归调用,这是一种非常便利的编程方式。递归调用本身就是一个不断压栈和弹栈的过程,栈能够很好地记录每一层递归的状态,从而确保递归调用的正确性和安全性。

栈的应用场景

  1. 函数调用:操作系统会给每个线程分配一块内存空间,这块内存被组织成栈结构。每进入一个函数,都会将临时变量作为栈帧入栈;当被调用函数执行完成返回后,将这个函数对应的栈帧出栈。这样,就可以保证函数调用的正确性和安全性。

  2. 表达式求值:编译器通过两个栈来实现表达式的求值。一个栈用来保存操作数,另一个栈用来保存运算符。从左到右遍历表达式,当遇到数字时,将其压入操作数栈;当遇到运算符时,将其与运算符栈栈顶元素进行比较,并根据优先级决定是压入栈还是进行运算。

  3. 括号匹配:在编写代码或处理文本时,经常需要检查括号是否匹配。可以使用栈来保存未匹配的左括号,从左到右依次扫描字符串。当扫描到左括号时,将其压入栈中;当扫描到右括号时,从栈顶取出一个左括号进行匹配。这种方法可以高效地检查括号是否匹配。

  4. 浏览器的前进和后退功能:浏览器的前进和后退功能也可以看作是一个栈的应用。当用户浏览网页时,可以将每个网页的URL压入栈中;当用户点击后退按钮时,可以从栈中取出上一个网页的URL并跳转过去。同样地,当用户点击前进按钮时,可以从另一个栈(记录前进历史的栈)中取出下一个网页的URL并跳转过去。

 顺序栈:

       顺序栈是指采用地址连续的存储空间(如数组)来依次存储栈中的数据元素。在顺序栈中,栈底位置是固定不变的,通常设置在数组空间的起始处,而栈顶位置则随着入栈和出栈操作的进行而发生变化。因此,需要用一个整型变量(通常称为“栈顶指针”或“top”)来记录当前栈顶元素在数组中的位置。

#ifndef _SEQSTACK_H
#define _SEQSTACK_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//表尾为栈顶,表头为栈底
typedef int Type;
typedef struct{
    //Type data[size];
    Type *data;    //栈存储空间的首地址
    size_t size;      //保存栈空间的长度,无符号的长整形
    int top;       //栈顶元素的下标
}stack;            //顺序栈

//创建栈
stack *create_stack(size_t size);
//判满
int full_stack(stack *s);
//判空 空为0非空为1
int empty_stack(stack *s);
//压栈
void push_stack(stack *s,Type data);
//弹栈
Type pop_stack(stack *s);
//获取栈顶元素
Type get_stack(stack *s);
//初始化
void init_stack(stack *s);
//回收
void free_stack(stack **s);

#endif

       对于顺序栈,我这次采用跟之前不同的方法去创建,之前都是在一开始就规定了大小,但是这一次我们在功能函数中创建的时候再去定它的大小,所以在定义结构体的时候里面就有三个成员,一个为Type *类型的指针,用来接收数组的首地址,第二个用来保存栈空间的长度,第三个成员是用来保存栈顶元素下标的一个变量。

#include "seqstack.h"

//创建栈
stack *create_stack(size_t size)
{
    stack *s = (stack *)malloc(sizeof(stack));
    if(NULL == s)
    {
        perror("create stack malloc");
        return NULL;
    }
    s->size = size;
    s->top = -1;
    s->data = (Type *)malloc(sizeof(Type)*size);
    if(NULL == s->data)
    {
        perror("create array  malloc");
        free(s);
        return NULL;
    }
    return s;
}
//判满 满为0,不满为1
int full_stack(stack *s)
{
    if(NULL == s)
    {
        puts("stack is NULL");
        return -1;
    }
    return s->top == s->size-1?0:1;
}
//判空 空为0非空为1
int empty_stack(stack *s)
{
    if(NULL == s)
    {
        puts("stack is NULL");
        return -1;
    }
    return s->top == -1?0:1; 
}
//压栈
void push_stack(stack *s,Type data)
{
    if(!full_stack(s))
    {
        puts("栈已满");
        return;
    }
    else
        s->data[++s->top] = data;
}
//弹栈
Type pop_stack(stack *s)
{
    if(0 == empty_stack(s))
    {
        puts("栈为空,无法操作");
    }
    else
        return s->data[s->top--];
}
//获取栈顶元素
Type get_stack(stack *s)
{
    if(NULL == s)
    {
        puts("stack is NULL");
    }
    if(0 == empty_stack(s))
    {
        puts("空栈,无法获取栈顶元素");
    }
    else
        return s->data[s->top];
}
//初始化
void init_stack(stack *s)
{
    if(NULL == s)
    {
        puts("stack is NULL");
        return;
    }
    s->top = -1;
}
//回收
void free_stack(stack **s)
{
    if(NULL == *s)
    {
        puts("stack is NULL");
        return;
    }
    free((*s)->data);
    free(*s);
    *s = NULL;
}

创建:stack *create_stack(size_t size)

       在这里创建函数跟之前的有所区别,这里的创建我们需要传参,传入所需要创建顺序栈空间的大小;首先创建这个结构体,然后给结构体里的size赋值;因为一开始栈为空栈,没有元素,所以栈顶元素的下标为-1,然后就是顺序栈的空间大小,这个也需要我们开辟,将开辟的空间的首地址赋值给结构体里面的data,之后就通过操作结构体里的data来操作栈;因为这里开辟了两次空间,所以要进行两次判断,来判断开辟空间是否成功。

判满:int full_stack(stack *s)

       顺序栈的判满其实就是看栈顶元素的下标是否与栈长度减去一相等,如果相等证明放满,不等则没有放满;满返回0,不满返回1。

判空:int empty_stack(stack *s)

       判空和判满类似,判空就是看栈顶元素下标top与-1是否相等,如果相等证明栈为空,不相等则栈非空,空返回0,非空返回1。

压栈:void push_stack(stack *s,Type data)

        因为顺序栈是有大小的,所以在压栈之前我们需要判断栈是否放满,如果放满就不能再进行压栈操作,直接return结束即可;如果没有放满那就可以进行压栈,压栈先让栈顶元素下标top++,然后再赋值;顺序栈压栈操作其实就相当于数组的赋值,每次赋值都先让top往后移再赋值,这样top保存的就是最后一个元素的下标。

弹栈:Type pop_stack(stack *s)

       弹栈首先需要判断栈是否为空,如果是空的就无法进行弹栈操作;因为是顺序栈,因此弹栈操作也只需要将弹出的元素作为函数返回值,然后栈顶元素下标往前移动一位即可,下次压栈到这个位置会将原来的值覆盖,因此并不会对压栈造成影响。

获取栈顶元素:Type get_stack(stack *s)

       获取栈顶元素就是直接将top下标对应的元素当做函数返回值返回即可,当然在获取栈顶元素之前需要判断栈是否为空,如果为空就无法获取栈顶元素,就打印一个提示,告诉用户空栈无法获取栈顶元素。

初始化:void init_stack(stack *s)

       顺序栈的初始化和之前顺序表的初始化是一样的,在顺序栈这里只需让栈顶元素的下标top为-1即可,这样在下次压栈的时候就算里面有值也会被覆盖,所以不会对后续操作产生影响。

回收:void free_stack(stack **s)

       回收需要注意的点就是我们在创建的时候不仅创建了结构体,还给顺序栈开辟了空间,因此在回收的时候需要先将存放元素的空间释放,然后再释放存放结构体的空间;当然传参需要传二级指针,我们需要得到的是指针的地址,将存放元素的空间和存放结构体的空间都释放之后再让指针指向NULL就完成了回收。

测试(主函数)

#include "seqstack.h"
int main(int agrc,char *agrv[])
{
    stack *s = create_stack(5);
    puts("压栈,将1,2,3,依次压入栈中");
    push_stack(s,1);
    push_stack(s,2);
    push_stack(s,3);
    puts("弹栈,将栈顶元素弹出");
    printf("%d\n",pop_stack(s));
    puts("获取栈顶元素");
    printf("%d\n",get_stack(s));
    puts("回收");
    free_stack(&s);
    printf("s=%p\n",s);
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Windows系统用C++做一个点名工具

目录 一、前言 二、主要技术点 三、准备工作 四、主界面 1.绘制背景图 2、实现读取花名册功能 3.实现遍历花名册功能 4.实现储存功能 4.1创建数据库 4.2存储数据到数据库表 4.3读取数据库表数据 一、前言 人总是喜欢回忆过去&#xff0c;突然回忆起…

前端监控之sourcemap精准定位和还原错误源码

一、概述 在前端开发中&#xff0c;监控和错误追踪是确保应用稳定性和用户体验的重要环节。 随着前端应用的复杂性增加&#xff0c;JavaScript错误监控变得尤为重要。在生产环境中&#xff0c;为了优化加载速度和性能&#xff0c;前端代码通常会被压缩和混淆。这虽然提升了性…

算法编程题-排序

算法编程题-排序 比较型排序算法冒泡排序选择排序插入排序希尔排序堆排序快速排序归并排序 非比较型排序算法计数排序基数排序 本文将对七中经典比较型排序算法进行介绍&#xff0c;并且给出golang语言的实现&#xff0c;还包括基数排序、计数排序等非比较型的算法的介绍和实现…

Jenkins修改LOGO

重启看的LOGO和登录页面左上角的LOGO 进入LOGO存在的目录 [roottest-server01 svgs]# pwd /opt/jenkins_data/war/images/svgs [roottest-server01 svgs]# ll logo.svg -rw-r--r-- 1 jenkins jenkins 29819 Oct 21 10:58 logo.svg #jenkins_data目录是我挂载到了/opt目录&…

【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段

文章目录 一、MyBatis-Plus简介二、快速入门1、环境准备2、将mybatis项目改造成mybatis-plus项目&#xff08;1&#xff09;引入MybatisPlus依赖&#xff0c;代替MyBatis依赖&#xff08;2&#xff09;配置Mapper包扫描路径&#xff08;3&#xff09;定义Mapper接口并继承BaseM…

云讷科技Kerloud无人飞车专利发布

云讷科技Kerloud无人飞车获得了“一种室内外两用的四旋翼无人飞车”的实用新型专利证书&#xff0c;作为科教社区第一款四旋翼飞车&#xff0c;这项技术结合了无人机和无人车的优势&#xff0c;提供了一种能够在多种环境下使用的多功能飞行器。 这项设计的优势如下&#xff…

Applied Intelligence投稿

一、关于手稿格式&#xff1a; 1、该期刊是一个二区的&#xff0c;模板使用Springer nature格式&#xff0c; 期刊投稿要求&#xff0c;详细期刊投稿指南&#xff0c;大部分按Soringernature模板即可&#xff0c;图片表格声明参考文献命名要求需注意。 2、参考文献&#xff…

Spark SQL大数据分析快速上手-完全分布模式安装

【图书介绍】《Spark SQL大数据分析快速上手》-CSDN博客 《Spark SQL大数据分析快速上手》【摘要 书评 试读】- 京东图书 大数据与数据分析_夏天又到了的博客-CSDN博客 Hadoop完全分布式环境搭建步骤-CSDN博客,前置环境安装参看此博文 完全分布模式也叫集群模式。将Spark目…

零基础上手WebGIS+智慧校园实例(1)【html by js】

请点个赞收藏关注支持一下博主喵&#xff01;&#xff01;&#xff01; 等下再更新一下1. WebGIS矢量图形的绘制&#xff08;超级详细&#xff01;&#xff01;&#xff09;&#xff0c;2. WebGIS计算距离&#xff0c; 以及智慧校园实例 with 3个例子&#xff01;&#xff01;…

[开源] 告别黑苹果!用docker安装MacOS体验苹果系统

没用过苹果电脑的朋友可能会对苹果系统好奇&#xff0c;有人甚至会为了尝鲜MacOS去折腾黑苹果。如果你只是想体验一下MacOS&#xff0c;这里有个更简单更优雅的解决方案&#xff0c;用docker安装MacOS来体验苹果系统。 一、项目简介 项目描述 Docker 容器内的 OSX&#xff08…

IDEA:2023版远程服务器debug

很简单&#xff0c;但是很多文档没有写清楚&#xff0c;wocao 一、首先新建一个远程jvm 二、配置 三、把上面的参数复制出来 -agentlib:jdwptransportdt_socket,servery,suspendn,address5005 四、然后把这串代码放到服务器中&#xff08;这里的0.0.0.0意思是所有IP都能访问&a…

卷积神经网络的padding是什么?如何计算?

文章目录 为什么需要padding&#xff1f;1.Valid Padding&#xff08;有效填充&#xff09;2.Same Padding&#xff08;相同填充&#xff09;2.1.如何计算padding&#xff1f;1. 计算总 padding2. 分配 padding&#xff1a; 2.2.举例子1. 步幅为 1 的 Same Padding2. 步幅不为 …

介绍一下strncmp(c基础)

strncmp是strcmp的进阶版 链接介绍一下strcmp(c基础)-CSDN博客 作用 比较两个字符串的前n位 格式 #include <string.h> strncmp (arr1,arr2,n); 工作原理&#xff1a;strcmp函数按照ACII&#xff08;字符编码顺序&#xff09;比较两个字符串。它从两个字符串的第一…

列出D3的所有交互方法,并给出示例

D3.js 提供了丰富的交互方法&#xff0c;可以用来增强图表的用户交互体验。以下是一些常用的交互方法及其示例&#xff1a; 1. 鼠标事件 on("mouseover", function) 用途: 当鼠标悬停在元素上时触发。示例:svg.selectAll(".bar").on("mouseover&qu…

丹摩征文活动 | AI创新之路,DAMODEL助你一臂之力GPU

目录 前言—— DAMODEL&#xff08;丹摩智算&#xff09; 算力服务 直观的感受算力提供商的强大​ 平台功能介绍​ 镜像选择 云磁盘创建 总结 前言—— 只需轻点鼠标,开发者便可拥有属于自己的AI计算王国 - 从丰富的GPU实例选择,到高性能的云磁盘,再到预配置的深度学习…

基于大数据爬虫数据挖掘技术+Python的网络用户购物行为分析与可视化平台(源码+论文+PPT+部署文档教程等)

#1024程序员节&#xff5c;征文# 博主介绍&#xff1a;CSDN毕设辅导第一人、全网粉丝50W,csdn特邀作者、博客专家、腾讯云社区合作讲师、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老…

六、卷积神经网络(CNN)基础

卷积神经网络&#xff08;CNN&#xff09;基础 前言一、CNN概述二、卷积层2.1 卷积2.2 步幅(Stride)2.3 填充(Padding)2.4 多通道卷积2.5 多卷积计算2.6 特征图大小计算2.7 代码演示 三、池化层3.1 池化层计算3.1.1 最大池化层3.1.2 平均池化层 3.2 填充(Padding)3.3 步幅(Stri…

国标GB28181视频平台EasyCVR视频融合平台H.265/H.264转码业务流程

在当今数字化、网络化的视频监控领域&#xff0c;大中型项目对于视频监控管理平台的需求日益增长&#xff0c;特别是在跨区域、多设备、高并发的复杂环境中。EasyCVR视频监控汇聚管理平台正是为了满足这些需求而设计的&#xff0c;它不仅提供了全面的管理功能&#xff0c;还支持…

Jmeter中的断言(四)

13--XPath断言 功能特点 数据验证&#xff1a;验证 XML 响应数据是否包含或不包含特定的字段或值。支持 XPath 表达式&#xff1a;使用 XPath 表达式定位和验证 XML 数据中的字段。灵活配置&#xff1a;可以设置多个断言条件&#xff0c;满足复杂的测试需求。 配置步骤 添加…

实验室管理解决方案:Spring Boot技术

6系统测试 6.1概念和意义 测试的定义&#xff1a;程序测试是为了发现错误而执行程序的过程。测试(Testing)的任务与目的可以描述为&#xff1a; 目的&#xff1a;发现程序的错误&#xff1b; 任务&#xff1a;通过在计算机上执行程序&#xff0c;暴露程序中潜在的错误。 另一个…