C语言 数据结构 栈的顺序表示和实现-程序员宅基地

技术标签: c语言    数据结构与算法  数据结构  

栈的顺序表示和实现


栈的存储结构可以是顺序表或链表,该篇为顺序表存储
栈是后进先出的数据结构

1 顺序栈结构

栈结构体
top永远指向下一个

typedef struct Stack
{
                           
    DataType data[maxn]; // 作为栈元素的存储方式,数据类型为DataType
    int top;             // top即栈顶指针,data[top-1]表示栈顶元素,top==0代表空栈
    int base;            // base即栈底指针
} Stack;                 //构建一个名字是stack类型的结构体,包含三个部分

2 基本操作函数

  1. 初始化一个栈
    返回一个结构体指针,空栈
Stack *InitStack()
{
    
    Stack *p = (Stack *)malloc(sizeof(Stack));
    if (p == NULL)
        return NULL;         //分配失败返回空指针
    p->base = p->top = 0; //栈底等于栈顶 即建立一个空栈
    return p;
}
  1. 入栈
    定义枚举类型bool,其中false=0,true=1。
typedef enum
{
    
    false,
    true
} bool;
  • 传入栈的结构体指针,以及传入元素,从栈顶加入栈,top+1,top永远指向下一个
  • 成功返回true,失败返回false
bool StackPushStack(Stack *p, DataType dt)
{
    
    if (p->top - p->base == maxn)
        return false;
    p->data[p->top] = dt; // dt存入栈中
    p->top++;             // 栈顶指针+1
    return true;
}

  1. 出栈
    传入栈的结构体指针,从栈顶移除该元素,top-1
bool StackPopStack(Stack *p)
{
    
    if (p->base == p->top)
        return false;
    --p->top;
    return true;
}
  1. 清空栈
void StackClear(Stack *p)
{
    
    p->top = 0; // 栈顶指针指向栈底
}
  1. 获取栈顶元素
DataType StackGetTop(Stack *p)
{
    
    return p->data[p->top - 1]; //  数组中栈元素从 0 开始计数,所以实际获取元素时,下标为 栈顶元素下标 减一;
}
  1. 获取栈大小
int StackGetSize(Stack *p)
{
    
    return p->top; //  因为只有在入栈的时候,栈顶指针才会加一,所以它正好代表了栈元素个数;
}
  1. 栈的判空
bool StackIsEmpty(Stack *p)
{
    
    return !StackGetSize(p); //判断是否为空栈
}

  1. 打印栈
void PrintStack(Stack *p)
{
    
    if (StackIsEmpty(p))
    {
    
        printf("栈为空\n");
    }
    else
    {
    
        printf("从栈顶开始:\t");
        for (int i = 1; i <= StackGetSize(p); i++)
        {
    
            printf("%d\t", p->data[p->top - i]);
        }
    }
}

3 整体代码

该程序分为两个文件,“Stack.h"与"test3.c”
将数据结构类型定义(typedef)部分与基础操作函数放在头文件Stack.h
主函数以及其他部分放在test3.c

test3.c

  • 为检验代码可行性,设计main()函数验证
  • 功能:
    • 往栈输入数据
    • 打印测试,依次打印栈元素(从栈顶开始)
    • 栈大小测试,返回栈的大小
    • 出栈测试,栈顶元素出栈
    • 取栈顶测试,返回栈顶元素
#include <stdio.h>
#include <stdlib.h>

#define DataType int // DataType用这个宏定义来统一代表栈中数据的类型,这里将它定义为整型,根据需要可以定义成其它类型,例如浮点型、字符型、结构体 等等;
#define maxn 1005  // 代表我们定义的栈的最大元素个数

#include "Stack.h"



int main()
{
      
    DataType e;
    Stack *p = InitStack();
    printf("请输入栈元素(输入-1结束):");
    scanf("%d", &e);
    while (e != -1)
    {
    
        StackPushStack(p, e);
        //printf("请输入栈元素(输入-1结束):");
        scanf("%d", &e);
    }
    PrintStack(p);
    printf("\n");
    printf("栈的大小为%d\n", StackGetSize(p));
    
    printf("出栈测试:\n");
    StackPopStack(p);
    PrintStack(p);

    printf("\n");
    printf("取栈顶测试:\n");
    e = StackGetTop(p);
    printf("取出的栈顶为%d\n", e);

    return 0;
}

Stack.h

typedef enum
{
    
    false,
    true
} bool;

typedef struct Stack
{
                            // 栈结构体
    DataType data[maxn]; // 作为栈元素的存储方式,数据类型为DataType
    int top;             // top即栈顶指针,data[top-1]表示栈顶元素,top==0代表空栈
    int base;            // base即栈底指针
} Stack;                 //构建一个名字是stack类型的结构体,包含三个部分



//初始化一个栈
Stack *InitStack()
{
    
    Stack *p = (Stack *)malloc(sizeof(Stack));
    if (p == NULL)
        return NULL;         //分配失败返回空指针
    p->base = p->top = 0; //栈底等于栈顶 即建立一个空栈
    return p;
}

//入栈
bool StackPushStack(Stack *p, DataType dt)
{
    
    if (p->top - p->base == maxn)
        return false;
    p->data[p->top] = dt; // dt存入栈中
    p->top++;             // 栈顶指针+1
    return true;
}

//出栈
bool StackPopStack(Stack *p)
{
    
    if (p->base == p->top)
        return false;
    --p->top;
    return true;
}

//清空栈
void StackClear(Stack *p)
{
    
    p->top = 0; // 栈顶指针指向栈底
}

// 只读接口,获取栈顶元素,获取栈大小,栈的判空, 打印栈
DataType StackGetTop(Stack *p)
{
    
    return p->data[p->top - 1]; //  数组中栈元素从 0 开始计数,所以实际获取元素时,下标为 栈顶元素下标 减一;
}
int StackGetSize(Stack *p)
{
    
    return p->top; //  因为只有在入栈的时候,栈顶指针才会加一,所以它 正好代表了 栈元素个数;
}
bool StackIsEmpty(Stack *p)
{
    
    return !StackGetSize(p); //判断是否为空栈
}
void PrintStack(Stack *p)
{
    
    if (StackIsEmpty(p))
    {
    
        printf("栈为空\n");
    }
    else
    {
    
        printf("从栈顶开始:\t");
        for (int i = 1; i <= StackGetSize(p); i++)
        {
    
            printf("%d\t", p->data[p->top - i]);
        }
    }
}

4 运行结果

在这里插入图片描述

5 附加题

  • 判断回文字符串
  • 写一函数,判断给定的字符串是否中心对称。如字符串“abcba”、“abccba”均为中心对称,字符串“abcdba”不中心对称。要求利用Stack.h中已实现的有关栈的基本操作函数来实现。请把该函数添加到文件test3.c中的主函数前,并在主函数中添加相应语句进行测试。要求是回文串返回1,不是为0。
  • 步骤
    • 字符串前半部分依次入栈
    • 利用栈后进先出的特点,字符串后半部分依次与栈顶元素比较,比较一次,进行出栈操作一次
    • 难点在字符串中字符个数有奇偶之分,需要讨论,或者像我利用mid和len两个变量控制,能将两个情况合并起来。
int IsReverse(char *s)
{
    
    int mid,len;
    Stack *q = InitStack();

    len = strlen(s);
    mid = strlen(s)/2;

    for (int i = 0; i < mid; i++)
    {
    
        StackPushStack(q, s[i]);
    }

    for (int i = len%2?mid+1:mid ; i < len; i++)
    {
    
        if (StackGetTop(q) != s[i])
        {
    
            return 0;
        }       
        StackPopStack(q);
    }

    return 1;
}
  • 修改test3.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define DataType int // DataType用这个宏定义来统一代表栈中数据的类型,这里将它定义为整型,根据需要可以定义成其它类型,例如浮点型、字符型、结构体 等等;
#define maxn 1005  // 代表我们定义的栈的最大元素个数

#include "Stack.h"


int IsReverse(char *s)
{
    
    int mid,len;
    Stack *q = InitStack();

    len = strlen(s);
    mid = strlen(s)/2;

    for (int i = 0; i < mid; i++)
    {
    
        StackPushStack(q, s[i]);
    }

    for (int i = len%2?mid+1:mid ; i < len; i++)
    {
    
        if (StackGetTop(q) != s[i])
        {
    
            return 0;
        }       
        StackPopStack(q);
    }

    return 1;
}

int main()
{
      
    char s[15]; 
    scanf("%s",s);
    if(IsReverse(s)) printf("是回文字符串\n");
    else printf("不是回文字符串\n");

    return 0;
}

  • 运行结果
    在这里插入图片描述
    在这里插入图片描述
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_57345774/article/details/122459478

智能推荐

1.1.1 操作系统的层次结构、基本概念、功能和目标-程序员宅基地

文章浏览阅读5.5k次,点赞2次,收藏15次。01 | 熟悉的操作系统举例02 | 操作系统的层次结构03 | 操作系统的概念04 | 操作系统的功能和目标4.1 | 作为计算机系统资源的管理者1️⃣处理器(CPU)管理2️⃣存储器管理3️⃣文件管理4️⃣设备管理4.2 | 作为用户与计算机硬件系统之间的接口1️⃣命令接口2️⃣程序接口4.3 | 作为扩充机器(虚拟机)05 | 知识回顾与重点考点_操作系统的层次结构

Python常用标准库logging-程序员宅基地

文章浏览阅读454次,点赞23次,收藏14次。python logging的简单使用

信息安全:防火墙技术原理与应用._防火墙应用场景-程序员宅基地

文章浏览阅读2.5k次,点赞29次,收藏49次。防火墙是网络安全区域边界保护的重要技术。为了应对网络威胁,联网的机构或公司将自己的网络与公共的不可信任的网络进行隔离,其方法是根据网络的安全信任程度和需要保护的对象,人为地划分若干安全区域,这些安全区域有:公共外部网络;内联网;外联网(内联网的扩展延伸,常用作组织与合作伙伴之间进行通信);军事缓冲区域,简称 DMZ;它一般安装在不同的安全区域边界处,用于网络通信安全控制,由专用硬件或软件系统组成._防火墙应用场景

make,Makefile简易教程_make makefile-程序员宅基地

文章浏览阅读832次。一、概述make是一个类UNIX系统下的编译命令,也可以理解为一个项目管理工具,通过make可以按照自己指定的编译命令编译整个项目,相当于将在命令行的编译命令按序执行,省去了反复键入编译命令的麻烦。除此之外,如果手动执行编译命令,不仅费时难以记忆,最重要的是每执行一次编译命令,项目中的整个文件都要重新编译,即使是未修改过的文件,这在大型项目中是难以忍受的。而make就提供了一种完美的解决方案,它将要执行的编译命令通过特定的语法组织到Makefile文件中,每次只要执行make命令,就可以完成整个项目的构建_make makefile

SyntaxError: Non-ASCII character '\xe5' in file TestMain.py on line 4, but no encoding declared;-程序员宅基地

文章浏览阅读5.8k次。【问题描述】运行Python程序时报错,提示为:SyntaxError: Non-ASCII character '\xe5' in file TestMain.py on line 4, but no encoding declared;【原因分析】Python默认是以ASCII作为编码方式的,如果在自己的Python源码中包含了中文(或者其他非英语系的语言),此时即使你把自..._syntaxerror: non-ascii character '\xe5' in file

yolov8 瑞芯微RKNN和地平线Horizon芯片仿真测试部署_yolov8 rknn-程序员宅基地

文章浏览阅读1w次,点赞19次,收藏89次。yolov8 瑞芯微RKNN和地平线Horizon芯片仿真测试部署。包含模型、测试图片和完整测试代码。跟上技术的步伐,yolov8 首个板端芯片部署。_yolov8 rknn

随便推点

报表工具对比选型系列 - 容量及相关性能_网络设备性能容量报表-程序员宅基地

文章浏览阅读81次。报表上的计算比较复杂,常常是内存计算,报表工具能支持的容量也就是个重要的技术指标。我们当然希望报表占用的内存尽量少,这样同样内存空间可以容纳更大的报表(更多的单元格),也能支持更大的并发数量。本文将对比报表工具的容量及相关性能,看同样的内存(可用 jvm)空间下,谁能支持更多的单元格数,以及同样规模报表的计算性能。产品还是三款:润乾报表 V2018、FineReport V10.0、smartbi V9,涉及报表数据来源的均为同库同表。测试的用例都是最简单的报表格式,具体可参考下面的说明。用例一_网络设备性能容量报表

公司软件开发人员绩效评价标准_软件开发人员绩效考核可以量化的指标有-程序员宅基地

文章浏览阅读1.7k次。 总则: 通过量化的指标准确的评定软件开发人员的绩效,从而对薪酬分配提供可靠的依据。 基本说明: 绩效评价,包括业绩考核和能力评定。对软件开发人员的绩效评定,每一项问答表现优秀加一分,表现不佳扣一分,表现平平不得分,最后计算总分。 业绩考核: 此项考核主要考核在一定时间内软件开发人员的任务完成情况。主要包括有以下指标:目标的完成度、难易度、贡献度。 目标完成度 ●完_软件开发人员绩效考核可以量化的指标有

ESP32/ESP8266_esp32 软复位后不停重启-程序员宅基地

文章浏览阅读1.3k次。用乐鑫的这些芯片主要是图arduino能快速搭建工程好开发,遇到的问题也都是arduino开发环境下的,EDP-IDF只在刚拿着玩的时候用过(属实难用)。有一个个人建议,如果没有热风枪或者焊接水平一般,建议远离ESP32-PICO-D4这种侧面几乎没有焊点的QFN封装芯片,检查虚焊短路能让人怀疑人生。_esp32 软复位后不停重启

Lua 面向对象-程序员宅基地

文章浏览阅读838次,点赞24次,收藏5次。基于Lua 实现类的封装,

基于Springboot外卖系统14:菜品新增模块+多个数据表操作+文件上传下载复用_flavors.foreach(dishflavor -> { dishflavor.setdish-程序员宅基地

文章浏览阅读2w次。在该Controller的方法中,不仅需要保存菜品的基本信息,还需要保存菜品的口味信息,需要操作两张表,所以我们需要在DishService接口中定义接口方法,在这个方法中需要保存上述的两部分数据。_flavors.foreach(dishflavor -> { dishflavor.setdishid(dishdto.getid()); });

AD器件距离过近报错 AD修改丝印的距离间距_ad中丝印间距规则怎么改-程序员宅基地

文章浏览阅读1.8w次,点赞21次,收藏80次。今天画板子遇见了一个间距报错,图片如下我当时想着,修改丝印的间距就可以了,查找了一些资料之后发现是这样修改并且我将其修改到了0但是结果还是如上图一样,报错。最后发现除此之外,我们还需要修改元件之间的电气距离修改完成之后就OK!..._ad中丝印间距规则怎么改

推荐文章

热门文章

相关标签