嵌入式入门Day23

news2024/12/26 12:36:37

数据结构Day4

  • 操作受限的线性表
    • 基本概念
    • 顺序栈
      • 顺序栈结构
      • 创建顺序栈
      • 判空和判满
      • 栈扩容
      • 入栈
      • 出栈
      • 遍历
      • 销毁栈
    • 链式栈
    • 队列
      • 基本概念
      • 顺序队列
        • 循环顺序队列定义
        • 循环队列的创建
        • 循环顺序队列的判空和判满
        • 循环顺序队列的入队
        • 循环顺序队列的遍历
        • 循环顺序队列的出队
        • 循环顺序队列的销毁
      • 链式队列
        • 链式队列的定义
        • 链式队列的创建
        • 链式队列的判空
        • 链式队列的入队
        • 链式队列的遍历
        • 链式队列的出队
        • 链式队列的销毁

在这里插入图片描述

操作受限的线性表

  1. 在显示生活中,我们可能使用的大多是操作受限的线性容器,都属于线性结构,但是只能进行部分操作
    • 做核酸:每次只能在队尾入队,在队头出队
    • 汽车过隧道:先进入隧道的车,先出隧道
    • 水杯:只能杯口加水,杯口出水
    • 手枪弹夹:先压入的子弹最后打出
  2. 只能在指定部位进行操作的线性表我们称为操作受限的线性表
  3. 分类
    • 栈:其插入和删除只允许出现在同一端的线性表称为栈
      特点:先进后出(FILO)或者后出先进(LIFO)
    • 队列:其插入和删除操作只允许在不同端进行的线性表称为队列
      特点:先进先出(FIFO)
    • 总结上述两个数据结构都是只允许在端点处进行操作的受限线性表

基本概念

  1. 栈:操作受限的线性表,其插入和删除只能在同一端进行
  2. 特点:后进先出(LIFO)
    • 栈顶:能够进行插入和删除的一端称为栈顶
    • 栈底:不能被操作的一端称为栈底
  3. 分类
    • 顺序栈:顺序存储的栈
    • 链式栈:链式存储的栈

顺序栈

顺序栈结构

typedef int datatype;
typedef struct 
{
	datatype *data; 	//顺序表指针
	int top; 			//栈顶标记位
	int size; 			//栈空间标志
}SeqStack, *SeqStack_ptr;

创建顺序栈

//创建顺序栈
SeqStack_ptr stack_create(int size)
{
	//申请栈的空间
	SeqStack_ptr S = (SeqStack_ptr)malloc(sizeof(SeqStack));
	if (NULL == S)
	{
		printf("创建失败\n");
		return NULL;
	}
	//申请存储容器的空间
	S->data = (datatype *)malloc(sizeof(datatype)*size);
	if (NULL == S->data)
	{
		printf("创建失败\n");
		//释放栈的空间
		free(S);
		return NULL;
	}
	//均申请成功之后,整个顺序栈才创建成功
	S->top = -1;
	S->size = size;
	return S;
}

判空和判满

//判空
int stack_empty(SeqStack_ptr S)
{
	//判断栈的合法性,栈是否正常指向顺序表
	if (NULL == S || S->data == NULL)
	{
		printf("非法栈\n");
		return -1;
	}
	//栈顶标记为 -1 既是空
	return S->top == -1;
}
//判满
int stack_full(SeqStack_ptr S)
{
	//合法性判断
	if (NULL == S || S->data == NULL)
	{
		printf("非法栈\n");
		return -1;
	}
	//判断栈顶标记是否已经到达上限
	return S->top == S->size-1;
}

栈扩容

static int stack_expend(SeqStack_ptr S)
{
	//合法性判断
	if (NULL == S)
	{
		printf("非法栈\n");
		return -1;
	}
	//在堆区申请原本两倍的空间
	datatype *temp = (datatype *)malloc(sizeof(datatype)*S->size*2);
	if (NULL == temp)
	{
		printf("扩容失败\n");
		return -1;
	}
	//将之前空间的内容拷贝到新的空间中
	memcpy(temp, S->data, sizeof(datatype)*S->size);
	//释放之前的空间
	free(S->data);
	//将顺序表指针重新定位到新空间
	S->data = temp;
	//空间标志位翻倍
	S->size *= 2;
}

入栈

//入栈
int stcak_push(SeqStack_ptr S, datatype e)
{
	//合法性判断
 	if (NULL == S)
 	{
 		printf("非法栈\n");
		return -1;
 	}
	//栈满判断
	if (stack_full(S))
	{
		stack_expend(S);	
	}
	//先更新标志位,再更新数据
	S->top++;
	S->data[S->top] = e;
	return 0;
}

出栈

//出栈
int stack_pop(SeqStack_ptr S)
{
	//合法性和栈空判断
	if (NULL == S || stack_empty(S))
	{
		printf("出栈失败\n");
		return -1;
	}
	//先出栈,再动标志位
	datatype e = S->data[S->top];
	S->top--;

	return 0;
}

遍历

//遍历
int stack_show(SeqStack_ptr S)
{
	//合法性和栈满判断
	if (NULL == S || stack_empty(S))
	{
		return -1;
	}
	
	//遍历输出
	printf("从栈顶到栈底的元素依次为:");
	for (int i = S->top; i >= 0; i--)
	{
		printf("%d\t",S->data[i]);
	}
	putchar(10);
}

销毁栈

//销毁栈
void stack_destroy(SeqStack_ptr S)
{
	//判断指针是否为空
	if (NULL == S)
	{
		return;
	}
	//栈空间内顺序表指针是否为空
	if (NULL == S->data)
	{
		//为空 	直接释放栈指针
		free(S);
		S = NULL;
		return;
	}
	//均不为空 	先释放顺序表,再释放栈指针
	free(S->data);
	free(S);
	S = NULL;
	return;

}

链式栈

  1. 概念:链式存储的栈
  2. 实现方式:
    • 只进行头插和头删的单向链表就是一个链式栈
      单向链表的头部就是栈顶,尾部就是栈底
    • 只进行尾插和尾删的单向链表就是一个链式栈
      单向链表的尾部就是栈顶,单向链表的头部就栈底
    • 更加倾向于使用第一种形式,因为尾插和尾删的实现方式每一次操作都需要遍历一次整个栈

队列

基本概念

  1. 操作受限:插入和删除只能在不同端进行
  2. 队头:允许删除操作的一端称为队头
  3. 队尾:允许插入操作的一端称为队尾
  4. 分类:
    • 顺序队列:顺序存储的队列
    • 链式队列:链式存储的队列

顺序队列

  1. 普通顺序队列
    • 有一个连续的存储空间存储队列
    • 有一个变量标记队头元素的下标
    • 有一个变量标记队尾元素的下标
  2. 普通顺序队列的弊端:
    假溢满:队列中仍有空间存储变量,但是队尾到达上线后却判断队列已满无法存储新的数据
  3. 为了解决此问题,一般使用循环顺序队列
循环顺序队列定义
#define MAX 8

typedef int datatype;

typedef struct 
{
	datatype data[MAX]; 	//队列存储容器
	int head; 				//头指针
	int tail; 				//尾指针
}SeqQueue, *SeqQueue_ptr;

循环队列的创建
//创建循环队列
SeqQueue_ptr queue_create()
{
	//申请顺序队列空间
	SeqQueue_ptr Q = (SeqQueue_ptr)malloc(sizeof(SeqQueue));
	if (NULL == Q)
	{
		printf("创建失败\n");
		return NULL;
	}
	//初始化两个指针
	Q->head = 0;
	Q->tail = 0;
	return Q;
}

循环顺序队列的判空和判满
//判空
int queue_empty(SeqQueue_ptr Q)
{
	//合法性判断
	if (NULL == Q)
	{
		printf("非法队列\n");
		return -1;
	}
	//队头和队尾同指向时为空
	return Q->head == Q->tail;
}
//判满
int queue_full(SeqQueue_ptr Q)
{
	//合法性判断
	if (NULL == Q)
	{
		printf("非法队列\n");
		return -1;
	}
	//因为队满条件不能和队空条件一样
	//此处直接判断Q->tail+1和Q->head
	//并且存在Q套圈的现象
	//模上表长用于归零
	return (Q->tail+1)%MAX == Q->head;
}

循环顺序队列的入队
//入队
int queue_push(SeqQueue_ptr Q,datatype e)
{
	//合法性和队满判断
	if (NULL == Q || queue_full(Q))
	{
		printf("入队失败\n");
		return -1;
	}
	//数据更新
	Q->data[Q->tail] = e;
	//同判队满操作防止下标越界
	Q->tail = (Q->tail+1)%MAX;
	return 0;
}

循环顺序队列的遍历
//遍历
void queue_show(SeqQueue_ptr Q)
{
	//合法性和队空判断
	if (NULL == Q || queue_empty(Q))
	{
		printf("非法队列\n");
		return;
	}
	//顺序表的遍历
	printf("从队头到队尾的元素分别为:");
	for (int i = Q->head ; i != Q->tail; i = (i+1)%MAX)
	{
		printf("%d\t",Q->data[i]);	
	}
	putchar(10);
}

循环顺序队列的出队
//出队
int queue_pop(SeqQueue_ptr Q)
{
	//合法性和队空判断
	if (NULL == Q || queue_empty(Q))
	{
		printf("出队失败\n");
		return -1;
	}
	//头指针后移,防止越界
	Q->head = (Q->head+1)%MAX;
	return 0;

}

循环顺序队列的销毁
//销毁队列
void queue_destroy(SeqQueue_ptr Q)
{
	//判断是否需要销毁
	if (NULL == Q)
	{
		return ;
	}
	//直接释放队列空间
	free(Q);
	Q = NULL;
}

链式队列

  1. 实现方式:
    • 使用单向链表进行头插尾删来实现:此时链表的头部称为队尾,链表的尾部称为队头
    • 使用单向链表进行头删尾插来实现:此时链表的头部称为对头,链表的尾部称为队尾
  2. 以上两种方式,都涉及到对链表尾部的操作,每次进行对尾部的操作是,都需要遍历整个链表,比较麻烦
  3. 此时,我们可以设置两个指针,分别指向单向链表的头部和尾部,删除时,直接头删,插入时,使用尾指针进行尾插
链式队列的定义
//定义数据类型
typedef char datatype;

//定义链表节点
typedef struct Node
{
	union 
	{
		int len; 			//头节点指针域
		datatype data; 		//普通节点指针域
	};
	struct Node *next; 		//记录后继节点
}Node, *Node_ptr;

//定义链式队列
typedef struct LinkQueue
{
	Node_ptr head; 			//定位队头
	Node_ptr tail; 			//定位队尾
}LinkQueue, *LinkQueue_ptr;

链式队列的创建
//创建链式队列
LinkQueue_ptr queue_create()
{
	//在堆区申请队列的空间
	LinkQueue_ptr L = (LinkQueue_ptr)malloc(sizeof(LinkQueue));
	if (NULL == L)
	{
		printf("链式队列创建失败\n");
		return NULL;
	}

	//在堆区申请链表的空间
	Node_ptr H = (Node_ptr)malloc(sizeof(Node));
	if (NULL == H)
	{
		//若失败则释放先前申请的队列结构体空间
		printf("链表创建失败\n");
		free(L);
		L = NULL;
		return NULL;
	}
	//头节点初始化
	H->len = 0;
	H->next = NULL;
	//指针指向链表
	L->head = H;
	L->tail = H;
	return L;
}

链式队列的判空
//判空
int queue_empty(LinkQueue_ptr L)
{
	//合法性判断
	if (NULL == L)
	{
		printf("非法队列\n");
		return -1;
	}
	//头尾指针同指向时链表为空
	return L->tail == L->head;
}

链式队列的入队
//入队
int queue_push(LinkQueue_ptr L, datatype e)
{
	//合法性判断
	if (NULL == L)
	{
		printf("链表非法\n");
		return -1;
	}
	//申请节点封装新数据
	Node_ptr p = (Node_ptr)malloc(sizeof(Node));
	if (NULL == p)
	{
		printf("节点申请失败\n");
		return -1;
	}
	//新节点初始化
	p->data = e;
	p->next = NULL;
	
	//利用尾指针完成尾插
	L->tail->next = p;
	//更新尾指针
	L->tail = p;

	//表长变化
	L->head->len++;
	return 0;
}

链式队列的遍历
//遍历
void queue_show(LinkQueue_ptr L)
{
	//队列节点合法性判断,链表指针判断,队空判断
	if (NULL == L || NULL == L->head || queue_empty(L))
	{
		printf("遍历失败\n");
		return;
	}
	//遍历队列
	printf("从队头到队尾的元素分别为:");
	Node_ptr q = L->head->next;
	while (q)
	{
		printf("%c\t", q->data);
		q = q->next;
	}
	putchar(10);
}

链式队列的出队
//出队
int queue_pop(LinkQueue_ptr L)
{
	//队列节点合法性判断,链表指针判断,队空判断
	if (NULL == L || NULL == L->head || queue_empty(L))
	{
		printf("出队失败\n");
		return -1;
	}
	//头删
	Node_ptr p = L->head->next;
	L->head->next = p->next;
	free(p);
	p = NULL;
	L->head->len--;
	//如果链表已空
	if (NULL == L->head->next)
	{
		//尾指针归位,防止野指针
		L->tail = L->head;
	}


	return 0;
}

链式队列的销毁
//销毁队列
void queue_destroy(LinkQueue_ptr L)
{ 	
	//销毁条件判断
	if (NULL == L)
	{
		return;
	}
	if (NULL == L->head)
	{
		//不指向链表时,直接释放队列
		free(L);
	}
	//都有所指向时,先让所有元素出队,然后释放链表,最后释放指针
	while (!queue_empty(L))
	{
		queue_pop(L);
	}
	free(L->head);
	free(L);
	L = NULL;
}

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

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

相关文章

C语言实验 一维数组

时间:2024.12.3 一、实验 7-1 交换最小值和最大值 #include<stdio.h> int main() {int n, a[10], i, min = 0, max = 0;scanf("%d", &n);for (i = 0; i < n; i++){scanf("%d",&a[i]);}for (i = 0; i < n; i++){if (a[min] > a[i…

聚合支付系统官方个人免签系统三方支付系统稳定安全高并发

系统采用fastadmin框架独立全新开发&#xff0c;安全稳定,系统支持代理、商户、码商等业务逻辑。 针对最近一-些JD&#xff0c;TB等业务定制&#xff0c;子账号业务逻辑API 非常详细&#xff0c;方便内置对接! 注意&#xff1a;系统没有配置文档很使用教程&#xff0c;不清楚…

HTMLCSS 奇幻森林:小熊的甜蜜蛋糕派对大冒险

这个 HTML 页面包含了一个背景、多个下落的蛋糕图片和一个左右移动的loopy图片,实现了一个小熊吃蛋糕的效果 演示效果 HTML&CSS <!DOCTYPE html> <html><head><meta charset"utf-8" /><title>ideal life</title><style…

电脑关机的趣味小游戏——system函数、strcmp函数、goto语句的使用

文章目录 前言一. system函数1.1 system函数清理屏幕1.2 system函数暂停运行1.3 system函数电脑关机、重启 二、strcmp函数三、goto语句四、电脑关机小游戏4.1. 程序要求4.2. 游戏代码 总结 前言 今天我们写一点稍微有趣的代码&#xff0c;比如写一个小程序使电脑关机&#xf…

OpenSSL 自建CA 以及颁发证书(网站部署https双向认证)

前言 1、前面写过一篇 阿里云免费ssl证书申请与部署&#xff0c;大家可以去看下 一、openssl 安装说明 1、这部分就不再说了&#xff0c;我使用centos7.9&#xff0c;是自带 openssl的&#xff0c;window的话&#xff0c;要去下载安装 二、CA机构 CA机构&#xff0c;全称为…

在M3上面搭建一套lnmp环境

下载docker-desktop 官网下载docker-desktop 切换镜像源 {"builder": {"gc": {"defaultKeepStorage": "20GB","enabled": true}},"experimental": false,"registry-mirrors": ["https://docke…

WebSocket 通信说明与基于 ESP-IDF 的 WebSocket 使用

一、 WebSocket 出现的背景 最开始 客户端&#xff08;Client&#xff09; 和 服务器&#xff08;Server&#xff09; 通信使用的是 HTTP 协议&#xff0c;HTTP 协议有一个的缺陷为&#xff1a;通信只能由客户端&#xff08;Client&#xff09;发起。 在一些场景下&#xff0…

linux(centos) 环境部署,安装JDK,docker(mysql, redis,nginx,minio,nacos)

目录 1.安装JDK (非docker)1.1 将文件放在目录下&#xff1a; /usr/local/jdk1.2 解压至当前目录1.3 配置环境变量 2.安装docker2.1 验证centos内核2.2 安装软件工具包2.3 设置yum源2.4 查看仓库中所有docker版本&#xff0c;按需选择安装2.5 安装docker2.6 启动docker 并 开机…

CODESYS可视化秒表分批计时详细制作案例(一)

#制作一个在可视化界面可用于秒表计时的详细案例# 前言: 在电脑和手机的时钟上,都有一个秒表计时的功能。除此之外,在赛事上,也有更为专业的秒表计时器设备。举一反三,那么对于工控设备,为了衡量生产效率和节拍,引入了"Cycle Time(CT)"的概念,我们可以通…

openGauss开源数据库实战十八

文章目录 任务十八 openGauss逻辑结构:构:用户和权眼管理任务目标实施步骤一、准备工作二、用户和角色管理1.使用CREATE USER语句创建用户2.使用CREATE ROLE语句创建用户3.删除用户和角色 三、权限管理1.系统权限清理工作 任务十八 openGauss逻辑结构:构:用户和权眼管理 任务目…

Scratch游戏推荐 | 我的世界:平台冒险——像素世界的全新挑战! ⛏️

&#x1f3ae; Scratch游戏推荐 | 我的世界&#xff1a;平台冒险——像素世界的全新挑战&#xff01; ⛏️&#x1f30d; 今天给大家推荐一款精彩绝伦的Scratch平台冒险游戏——《我的世界&#xff1a;平台冒险 – 第二章》&#xff01;由atomicmagicnumber制作&#xff0c;这…

【java-数据结构篇】揭秘 Java LinkedList:链表数据结构的 Java 实现原理与核心概念

我的个人主页 我的专栏&#xff1a;Java-数据结构&#xff0c;希望能帮助到大家&#xff01;&#xff01;&#xff01;点赞❤ 收藏❤ 目录 1. Java LinkedList 基础 1.1 LinkedList 简介 1.2 LinkedList 的实现原理 1.3 LinkedList 与 ArrayList 的区别 2. 链表基础 2.1 链…

北斗道路运输车辆管理应用:违规驾驶行为监测、车辆编队管理、安全跟踪(车辆历史轨迹查询)、车辆动态位置数据的实时查看和管理

文章目录 场景概述解决方案应用案例合作构想场景概述 面向旅游大巴车、危险品运输车及重型载货运输车等车辆,利用北斗定位导航服务,结合互联网通信技术,实现车辆安全驾驶管理与调度,有效降低道路事故发生风险,提升道路运输管理水平及车辆调度能力。 解决方案 在车辆上安…

【ABAP——DAILOG_2】

文章目录 使用Tabstrip控件实现分页签效果标签页的修改使用Table Control控件实现表单输出表格控件使用向导创建Table ControlTable Control列的修改 用户通过界面输入数据&#xff0c;数据通过屏幕控件传递到ABAP/4程序中的变量&#xff0c;程序在PBO中准备数据并显示界面&…

资料文件夹转移工具5.2.3 |快速转移到D盘,释放C盘空间

这是一款支持将C盘的常用文件夹转移到其他磁盘分区的工具&#xff0c;提供仅变目录、复制资料和转移资料三种转移方式。该工具完全免费&#xff0c;单文件免安装&#xff0c;大小仅为546KB&#xff0c;非常适合需要释放C盘空间的用户。 大小&#xff1a;546KB 下载地址&#…

使用STM32CubeMX配置串口各种功能

使用STM32CubeMX配置串口各种功能 STM32CubeMX软件的安装接收空闲中断STM32CubeMX配置1.新建工程2. 选择芯片3. 选择时钟和下载方式4. 配置串口5.设置工程消息6.生成代码7.修改生成的代码 空闲中断DMA转运STM32CubeMX配置4.配置串口5.设置工程消息6.生成代码7.修改生成的代码 S…

Javascript中DOM操作和事件监听综合练习 (具备三种功能的轮播图案例)

#如何去实现图片轮播效果图&#xff0c;通过创建一个基本的 HTML 页面结构&#xff0c;包含用于展示轮播图片的区域、左右切换箭头以及放置轮播图片的容器。# 整体架构 一、CSS 样式 接下来创建一个 styles.css 文件来设置页面的样式&#xff0c;让轮播效果看起来更美观。定义…

无人设备遥控器之防水性能篇

无人设备遥控器的防水性能是评估其耐用性和适应不同环境能力的重要指标。随着无人设备技术的不断发展&#xff0c;越来越多的遥控器在设计时融入了防水元素&#xff0c;以满足用户在不同天气条件下的使用需求。 一、防水等级与标准 无人设备遥控器的防水性能通常通过防水等级来…

【JAVA】Java入门 - 循环结构进阶

第1关 for循环的进阶使用-嵌套循环&#xff08;1&#xff09; 第2关 for循环的进阶使用-嵌套循环&#xff08;2&#xff09; 第3关 99乘法表 第4关 综合练习之ATM取款机 第5关 选择题 D、BC、B

【AI系统】AI 编译器后端优化

AI 编译器后端优化 AI 编译器分为多层架构&#xff0c;最顶层由各种 AI 训练框架编写的神经网络模型架构&#xff0c;一般由 Python 编写&#xff0c;常见的 AI 训练框架有 PyTorch、MindSpore、PaddlePaddle 等。在导入 AI 编译器时需要用对应框架的 converter 功能转换为 AI…