【数据结构和算法】了解认识栈,并实现栈的相关函数

news2024/11/17 23:58:28

到现在我们了解并认识了线性表的概念,动态、静态顺序表的建立,以及两种链表的实现,接下来我们要认识一个新的内容,新的概念,栈,是基于顺序表或者链表的一种新型数据结构。

目录

一、栈是什么?

二、栈的实现

1.实现的方式

2.实现栈的函数

1.初始化栈

2.入栈

3.出栈

4.查看栈顶元素

5.打印栈和清空栈

三、完整代码实现

1.链表实现栈

2.数组(顺序表)实现栈

总结


一、栈是什么?

栈:是一种特殊的线性表。其只允许在固定的一端进行插入和删除操作。进行数据的插入和删除的一端称为栈顶,另外的一端称为栈底。栈中的数据元素遵循先进后出(后进先出)的原则

之前在学习C语言的时候,就i听说过的两种概念

1.压栈:栈的插入操作叫做进栈、压栈、入栈等,插入数据在栈顶

2.出栈:栈的删除操作叫做出栈。出数据也在栈顶

 

二、栈的实现

1.实现的方式

有两种

1.我们可以通过顺序表的形式实现,因为进行尾插尾删除,代价小,就算是更改或者删除栈中指定的元素,不过也是移动位置而已。


如图所示:

结构体代码如下:

#define MAX 100
#define CAp 4 ///初始化的时候capacity的容量
#define Make 2//每一次增加的newCapacity的容量
//静态
typedef struct Stacknode {
	int data[MAX];//数据域
	int size;//表示元素个数
}Stack;
//动态
typedef struct Stacknode2 {
	int* data;//数据域
	int size;//表示元素个数
	int capacity;//表示当前容量
}Stack1;

2.通过链表的形式进行实现栈表

结构体如下:

//创建基础结构
typedef struct node {
	int data;
	struct node* next;
}ST;


//栈实际上就是一个只能进行头插头删的单向链表
//创建栈的头尾结点 结构体
typedef struct stack {
	struct node* top;//栈顶元素地址
	struct node* bottom;//栈底元素地址
	int size;//栈的元素个数
};

2.实现栈的函数

以链表实现栈为例,在本文结尾处,一并放置用数组实现栈的完整代码

1.初始化栈

结构体如上,使用的是上文的结构体类型

代码如下:


//初始化栈
struct stack* create_stack()
{
	struct stack* s = (struct stack*)malloc(sizeof(struct stack));
	s->size = 0;
	s->bottom = s->top = NULL;
	return s;
}

使用malloc函数,申请空间,将s的size大小置为0,bottom和top表示栈底栈顶都指向NULL

2.入栈

如图所示:

 代码如下:

//创建新的结点
struct node* create_node(int data) {
	struct node* newnode = (struct node*)malloc(sizeof(struct node));
	newnode->next = NULL;
	newnode->data = data;
	return newnode;
}

//入栈
//入栈首先要将准备入栈的元素封装成结点,和链表没有差别

void stackPush(struct stack* s, int x) {
	ST* newnode = create_node(x);
	newnode->next = s->top;
	s->top = newnode;
	s->size++;
}

3.出栈

如图所示:

代码如下:

//出栈
void stackPop(struct stack* s, int* x) {
//判断是否为空栈   如果是 空栈的话就  使得输出 Pop failed
	if (s->size == 0) {
		printf("Pop failed\n");
		exit(-1);
	
	}
	//创建结点临时变量  赋值得到栈顶元素
	ST* tmp = s->top;
	*x = tmp->data;//得到数值
	s->top = tmp->next;
	s->size--;
}

4.查看栈顶元素

代码如下:

//查看栈顶元素
void stackTop(struct stack* s, int* x) {
	if (s->size == 0) {
		printf("空栈~~\n");
		exit(-1);
	}

	*x = s->top->next->data;
}

5.打印栈和清空栈

代码如下:

//清空栈
void make_stack_empty(struct stack* s) {
	s->size = 0;
	s->bottom = s->top ;
	//将栈底等于栈顶就可以  然后将size为0

}
void stackPrint(struct stack* s) {
	//打印栈表
	ST* list = s->top;
	printf("top -> ");
	while (list!=NULL) {
		printf("%d -> ", list->data);
		list = list->next;
	}
}

三、完整代码实现

1.链表实现栈

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<malloc.h>

//创建基础结构
typedef struct node {
	int data;
	struct node* next;
}ST;


//栈实际上就是一个只能进行头插头删的单向链表
//创建栈的头尾结点 结构体
typedef struct stack {
	struct node* top;//栈顶元素地址
	struct node* bottom;//栈底元素地址
	int size;//栈的元素个数
};
//表示每一个栈都是struct stack* 类型的,栈中的每一个怨怒是都是struct node *类型的  不仅需要为栈分配内存,还需要为压入栈中的元素分配内存

/*
node中的next指针用于让栈中上面的节点连接到下面的节点,stack中的top和bottom分别存放当前栈顶元素的地址和栈底元素的后一个位置的地址(NULL),
因为是用于指向栈中节点的指针,所以得是struct node* 类型。*/

//初始化栈
struct stack* create_stack()
{
	struct stack* s = (struct stack*)malloc(sizeof(struct stack));
	s->size = 0;
	s->bottom = s->top = NULL;
	return s;
}

//一开始栈是空的所以 size为0  top  bottom是NULL

//创建新的结点
struct node* create_node(int data) {
	struct node* newnode = (struct node*)malloc(sizeof(struct node));
	newnode->next = NULL;
	newnode->data = data;
	return newnode;
}

//入栈
//入栈首先要将准备入栈的元素封装成结点,和链表没有差别

void stackPush(struct stack* s, int x) {
	ST* newnode = create_node(x);
	newnode->next = s->top;
	s->top = newnode;
	s->size++;
}

//出栈
void stackPop(struct stack* s, int* x) {
//判断是否为空栈   如果是 空栈的话就  使得输出 Pop failed
	if (s->size == 0) {
		printf("Pop failed\n");
		exit(-1);
	
	}
	//创建结点临时变量  赋值得到栈顶元素
	ST* tmp = s->top;
	*x = tmp->data;//得到数值
	s->top = tmp->next;
	s->size--;
}

//查看栈顶元素
void stackTop(struct stack* s, int* x) {
	if (s->size == 0) {
		printf("空栈~~\n");
		exit(-1);
	}

	*x = s->top->next->data;
}

//清空栈
void make_stack_empty(struct stack* s) {
	s->size = 0;
	s->bottom = s->top ;
	//将栈底等于栈顶就可以  然后将size为0

}
void stackPrint(struct stack* s) {
	//打印栈表
	ST* list = s->top;
	printf("top -> ");
	while (list!=NULL) {
		printf("%d -> ", list->data);
		list = list->next;
	}
}
int main()
{
	struct stack *s = create_stack();
	stackPush(s, 1);
	stackPush(s, 2);
	stackPush(s, 3);
	stackPush(s, 4);
	stackPush(s, 5);
	stackPrint(s);
	int a = 0;
	stackPop(s,&a);
	printf("\n%d\n", a);
	stackPrint(s);
	return 0;
}

2.数组(顺序表)实现栈

#define _CRT_SECURE_NO_WARNINGS
#include"steck.h"
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
//栈是限定在一个表里面的一段进行插入删除操作的线性表
// 数据进出的顺序为先进后处
// 应用场景:网页浏览的时候的后退  编辑软件的撤销
// 
//创建栈  两个方式:数组(顺序表)和 单链表


//1.数组:选用数组用来做栈的存储结构,只需要在数组末尾进行操作即可,完美避开数组操作中挪动数据缺陷
      //   显然是可以用数组来做栈的存储结构
//2.单链表  :因为栈是吸纳星表的一段进行操作,所以一般是用链表头进行操作

//进行头插头删  是用链表更好 效率更高


//1.用数组的方式
typedef int StackDataType;
typedef struct Stcak {
    StackDataType* data;
    int top;
    int capacity;   //数据域和元素个数
}ST;

//初始化
void StackInit(ST* ps) {
    ps->data = (StackDataType*)malloc(sizeof(StackDataType) * 4);
    if (ps->data == NULL) {
        printf("malloc failed\n");
        exit(-1);
    }
    ps->top = 0;
    ps->capacity = 4;

}
//压栈
void StackPush(ST* ps, int x) {
    assert(ps);//断言
    //满了就扩容
    if (ps->top == ps->capacity) {
        StackDataType* tmp = (StackDataType*)realloc(ps->data, sizeof(StackDataType) * ps->capacity * 2);
        if (tmp == NULL) {
            printf("realloc failed\n");
            exit(-1);
        }
        else {
            ps->data = tmp;
            ps->capacity *= 2;

        }
    }
    ps->data[ps->top] = x;
    ps->top++;

}
//出栈
void StackPop(ST* ps) {
    //出栈是将最后一个元素放出来  先进后出
    assert(ps);
    assert(ps->top > 0);//断言进行判断是否栈为空  即top!=0
    ps->top--;
    //直接减减就可以  没有了对应元素 的数据  如果再次压栈的话 会把之前的数据进行更改
}

//取得栈顶元素
StackDataType StackTop(ST* ps) {
    assert(ps);
    assert(ps->top > 0);
    return ps->data[ps->top - 1];//因为top栈顶始终要保持比元素个数大一,保证压栈的时候先压栈然后再加加
//所以取栈顶元素 的时候 top-1
}

//销毁栈
void StackDestory(ST* ps) {
    assert(ps);
    free(ps->data);
    //释放数组data的空间
    ps->data = NULL;
    ps->top = ps->capacity = 0;

}

//求栈中元素个数
int StackSize(ST* ps) {
    assert(ps);
    return ps->top;
}
//判断是否为空
bool StackEmpty(ST* ps) {
    assert(ps);
    return ps->top == 0;
}
void StackPrint(ST* ps) {
    //打印栈表
    assert(ps);
    for (int i = 0; i < ps->top; i++) {
        printf("%d ", ps->data[i]);
    }
    printf("\n");
}
int main()
{
    ST s;
    ST *ps=&s;
  /*  StackInit(&ps);
    StackPush(&ps, 1);
    StackPush(&ps, 2);
    StackPush(&ps, 3);
    StackPush(&ps, 4);
    StackPush(&ps, 5);
    StackPrint(&ps);*/
    StackInit(ps);
    StackPush(ps, 1);
    StackPush(ps, 2);
    StackPush(ps, 3);
    StackPush(ps, 4);
    StackPush(ps, 5);
    StackPop(ps);//出栈成功
    StackPrint(ps);
    printf("%d \n", StackTop(ps));//取得栈顶元素
    printf("%d \n", StackSize(ps));//获得栈表元素个数
    StackDestory(ps);
    StackPrint(ps);//销毁栈表成功
    return 0;
}

总结

栈是限定在一个表里面的一段,对其进行插入删除操作的线性表,数据进出的顺序为先进后处,应用场景:网页浏览的时候的后退  编辑软件的撤销,实际上栈的功能就这样,学会顺序表以及链表的使用,对于栈来讲,只是懂得头擦头删,理解概念了,就好掌握并实现栈。

下文,我们会讲解一下队列,和栈相似,但是另有不同,敬请期待吧,感谢大家支持!!!

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

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

相关文章

RabbitMQ入门中篇

本篇博文目录一.Spring整合RabbitMQ1.导入依赖2.生产者3.消费者4.测试二.SpringBoot整合RabbitMQ1.导入依赖2.生产者3.消费者4.测试三.代码下载一.Spring整合RabbitMQ 在spring项目中使用RabbitMQ的Exchange模式的Topics&#xff0c;项目分为消费者spring项目和生产者spring项目…

Centos7安装kvm服务器

Centos7安装kvm服务器什么是kvm检查硬件是否支持kvm虚拟化启用嵌套虚拟化(可选)查看是否启用嵌套虚拟化嵌套虚拟化立即生效(临时)重新加载模块并验证虚拟机硬件直通虚拟机内查看嵌套虚拟化是否成功安装kvm服务器安装kvm的所有包(不推荐)启动libvirt服务查看是否正确设置了虚拟化…

Linux操作系统之线程安全

一、引入线程安全关于strtok函数不能在多线程中使用&#xff0c;为什么&#xff1f;运行结果原因如下&#xff1a;在strtok内部会有一个全局变量静态指针&#xff08;static char* ptr&#xff09;&#xff0c;一开始指针指向主线程的a&#xff0c;等到后面子线程开始分割时&am…

18 Java反射reflect(类加载+获取类对象+通用操作+设计模式+枚举+注解)

Java反射18 反射reflect18.1 类的加载18.2 Class对象18.3 获取类对象的3种方法18.4 反射通用操作18.4.1 常见方法18.4.2 通用操作18.5 设计模式18.5.1 概念18.5.2 好处18.5.3 工厂设计模式18.5.4 单例模式18.6 枚举18.7 注解18.7.1 概念18.7.2 定义注解18.7.3 注解属性类型18.7…

知名休闲服饰品牌——慕尚集团借力泛微实现统一办公、业务协同

客户简介 宁波中哲慕尚控股有限公司&#xff08;以下简称慕尚集团&#xff09;是中国知名的由新零售模式驱动的休闲时尚服饰多品牌运营公司。 旗下品牌有GXG,gxgjeans,gxg.kids,MODE COMMUTER等&#xff0c;覆盖时尚男女装、童装市场和其他时尚领域。2019年5月慕尚集团正式登…

不要在线上滥用CopyOnWriteArrayList,姿势不对性能真的很拉胯

从JDK1.5版本&#xff0c;JAVA提供了线程安全的List增强版CopyOnWriteArrayList&#xff0c;其保持线程安全的方式是&#xff1a;每次修改数据时&#xff0c;不会直接修改数据&#xff0c;而是把数据复制出来一份&#xff0c;对复制出来的数组进行操作。 通过这样的机制&#…

【图像算法】马赛克识别

【目的】 校验视频中出现马赛克的频率&#xff0c;抽象成将视频切割成图片&#xff0c;对每张代测图片进行自动化验证。 【实现】 图像边缘检测算法识别 算法步骤&#xff1a; 使用高斯滤波器&#xff0c;以平滑图像&#xff0c;滤除噪声。计算图像中每个像素点的梯度强度和…

buuctf-web-[BJDCTF2020]Easy MD51

打开环境一个简单的页面查看源代码一个get传参&#xff0c;随便输入试试看输入1,1",1,均无反应&#xff0c;每次遇到这种有输入框的都以为是sql注入&#xff0c;但是题目为md5标头里面看到提示select * from admin where passwordmd5($pass,true)搜索相关漏洞&#xff0c;…

gost 常用tunnel配置示例(隧道模式)

gost是用golang语言实现的一个安全隧道。地址位于&#xff1a;https://github.com/ginuerzh/gost是一个不可多得的隧道工具。至于什么是隧道&#xff1f; 就是可以通过这个工具传输一些其他协议的数据。就像这个样子。隧道有什么用呢&#xff1f;可以起到一些加速的作用或者流量…

Array.prototype.from()

Array.from() 用于将类数组对象或可迭代对象转化为一个新的浅拷贝数组实例。 let arr Array.from({length:3},(_,i)>({id:item-${i1}}))console.log(arr)Array.from()转换数组 // Array.from 转换成数组let arr2 Array.from(chixinAwen)console.log(arr2) 示例&#xff1a…

如何免安装使用 Python?推荐 17 个在线的 Python 解释器

安装 Python 很容易&#xff0c;但或许你正在用智能手机/平板电脑&#xff0c;在用不允许安装软件的电脑&#xff0c;或者因为其它原因无法安装 Python。那么&#xff0c;如何通过免安装的方式使用 Python 呢&#xff1f; 本文将介绍 17 个免费的 Python 解释器和交互式 Shell…

百里挑一,4款免费又实用的软件,用一次就爱上

好看的皮囊千篇一律&#xff0c;实用的软件百里挑一&#xff0c;下面几款软件都是笔者收集多年所得&#xff0c;实用且免费。 1、坚果云 这是一款颠覆许多人认知的网盘工具&#xff0c;免费使用无广告&#xff0c;不限速的优点就比某度网盘强百倍&#xff0c;支持任何设备&…

AOP案例:测量业务层接口万次执行时间

测量业务层接口万次执行时间1. 准备1.1 service层&#xff1a;1.2 dao层&#xff1a;1.3 SpringConfig配置类&#xff1a;2. AOP2.1 通知类2.2 测试类&#xff1a;3. 问题及改进1. 准备 需求&#xff1a;任意业务层接口执行均可显示执行的时长&#xff1b; 切入点配置&#x…

(day9) 自学Java——常用API

AIP就是Java已经写好的各种功能的java类 目录 1.Math 2.System 3.Runtime 4.Object 5.对象工具类Objects 6.BIgInteger 7.BigDecima 8.正则表达式 (1)爬虫 (2)带条件爬取&#xff0c;贪婪爬取和识别正则的两个方法 (3)捕获分组和非捕获分组 9.JDK7以前时间相关类 …

一起自学SLAM算法:12.3 autoware导航系统

连载文章&#xff0c;长期更新&#xff0c;欢迎关注&#xff1a; 上面介绍的ros-navigation和riskrrt导航系统主要都是用于机器人的低速导航&#xff0c;并且大多基于2D地图。而autoware导航系统主要用于无人驾驶汽车的高速导航&#xff0c;并且基于3D地图。除了所导航速度高一…

软件工程(一)——软件开发模型和方法

目录 &#xff08;一&#xff09;软件开发方法 &#xff08;二&#xff09;瀑布模型 &#xff08;三&#xff09;原型模型 &#xff08;四&#xff09;螺旋模型与增量模型 &#xff08;五&#xff09;V模型、喷泉模型、RAD模型 (六) 统一过程&#xff08;RUP&#xff09; …

idea 中 connot run program “svn“ 系统找不到文件

idea 中 connot run program “svn“ 系统找不到文件1. idea中svn的问题1.1 idea connot run program "svn"1.1.1 解决办法-重装svn1.2 idea中check out灰色不可用1.2.1 解决办法—装插件1. idea中svn的问题 1.1 idea connot run program “svn” 如图&#xff1a;…

2023年机床工具行业研究报告

第一章 行业概况 生产和销售机床工具的行业。机床是指制造机器的机器&#xff0c;亦称工作母机或工具机&#xff0c;习惯上简称机床。一般分为金属切削机床、锻压机床和木工机床等。现代机械制造中加工机械零件的方法很多&#xff1a;除切削加工外&#xff0c;还有铸造、锻造、…

【ES实战】索引生命周期管理(一)

索引生命周期管理IL&#xff2d;&#xff08;index lifecycle management&#xff09; 文章目录索引生命周期管理IL&#xff2d;&#xff08;index lifecycle management&#xff09;概述版本矩阵主要概念索引生命周期阶段的过渡阶段的执行生命周期中的操作生命周期策略索引翻滚…

AzureRT:一款能够实现各种Azure红队技战术的PowerShell模块

关于AzureRT AzureRT是一款能够实现各种Azure红队技战术的PowerShell模块&#xff0c;在AzureRT的帮助下&#xff0c;广大研究人员可以从攻击者的角度来与Azure和Azure AD进行交互&#xff0c;以此来测试目标环境的安全性。 AzureRT可以帮助广大研究人员测试和处理基于访问令…