嵌入式学习——数据结构(双向无头有环链表、内核链表、栈)——day48

1. 约瑟夫环问题——双向无头回环链表

1.1 问题描述

        给定 ( n ) 个人(编号为 ( 1, 2, \ldots, n )),他们围成一个圈。从第一个人开始报数,每报到第 ( k ) 个人时,杀掉这个人,然后从下一个人重新开始报数。重复这个过程,直到所有人都被杀死。约瑟夫环问题是要确定最后一个幸存者的编号。

1.2 实质

        每次删除循环链表中的一个节点,直到链表中仅剩一个节点结束

2. 双向无头循环链表代码

2.1 makefile

OBJ:=a.out
OBJS+=main.c doublelink.c
CCl=gcc$(OBJ):$(OBJS)$(CC) $^ -o $@
.PHONY:
clean:rm $(OBJ)
test:valgrind --tool=memcheck --leak-check=full ./$(OBJ)

2.2 double.h

#ifndef _DOUBLELINK_H_
#define _DOUBLELINK_H_typedef struct stu
{int id;char name[32];int score;
}DataType;typedef struct node
{DataType data;struct node *ppre;struct node *pnext;
}DouNode;typedef struct list
{DouNode *phead;int clen;
}DouList;extern DouList *create_dou_link();
extern int is_empty_dou_link(DouList *plist);
extern void dou_link_for_each(DouList *plist, int dir);
extern int push_head_dou_link(DouList *plist, DataType data);
extern int  push_tail_dou_link(DouList *plist, DataType data);
extern int pop_head_dou_link(DouList *plist);
extern int pop_tail_dou_link(DouList *plist);
extern void loop_dou_link(DouList *plist);
extern DouNode *Joseph_loop(DouList *plist);
extern void dou_link_for_remain(DouList *plist);#endif

2.3 double.c

#include "doublelink.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>DouList *create_dou_link()//创建标签
{DouList *plist = NULL;plist = (DouList *)malloc(sizeof(DouList));if (NULL == plist){perror("fail to malloc");return NULL;}plist->phead = NULL;plist->clen = 0;return plist;
}int is_empty_dou_link(DouList *plist)//判断空链表
{if (NULL == plist->phead){return 1;}return 0;
}int push_head_dou_link(DouList *plist, DataType data)//头插
{DouNode *pnode = NULL;pnode = malloc(sizeof(DouNode));if (NULL == pnode){perror("fail to malloc");return -1;}pnode->data = data;pnode->ppre = NULL;pnode->pnext = NULL;if (is_empty_dou_link(plist))//空链表直接插{plist->phead = pnode;}else{pnode->pnext = plist->phead;plist->phead->ppre = pnode;plist->phead = pnode;}plist->clen++;return 0;
}int push_tail_dou_link(DouList *plist, DataType data)//头插
{DouNode *p = NULL;DouNode *pnode = NULL;pnode = malloc(sizeof(DouNode));if (NULL == pnode){perror("fail to malloc");return -1;}pnode->data = data;pnode->ppre = NULL;pnode->pnext = NULL;if (is_empty_dou_link(plist))//空链表直接插{plist->phead = pnode;}else{   p = plist->phead;while (p->pnext != NULL){p = p->pnext;}p->pnext = pnode;pnode->ppre = p;}plist->clen++;return 0;
}int pop_head_dou_link(DouList *plist)//头删
{if (is_empty_dou_link(plist))//空链表直接结束程序{return -1;}DouNode *pfree = NULL;pfree = plist->phead;plist->phead = pfree->pnext;//标签指向第二个节点首地址if (plist->phead != NULL)//判断是否空链表{plist->phead->ppre = NULL;//将第二个节点的ppre变为NULL}free(pfree);plist->clen--;return 0;
}int pop_tail_dou_link(DouList *plist)//尾删
{if (is_empty_dou_link(plist))//空链表程序结束{return -1;}DouNode *pfree = NULL;pfree = plist->phead;while (pfree->pnext)//指针指向最后一个节点{pfree = pfree->pnext;}if (pfree->ppre != NULL)//链表有两个以上节点{pfree->ppre->pnext = NULL;}else //链表只有一个节点{plist->phead = NULL;}free(pfree);plist->clen--;return 0;
}void loop_dou_link(DouList *plist)//将非回环链表改为双向回环链表
{DouNode *ptmpnode = NULL;ptmpnode = plist->phead;while (ptmpnode->pnext != NULL)//将指针移动到末尾节点{ptmpnode = ptmpnode->pnext;}ptmpnode->pnext = plist->phead;plist->phead->ppre = ptmpnode;
}void dou_link_for_remain(DouList *plist)//打印约瑟夫回环一次处理后链表中剩下的成员信息
{int i = 0;DouNode *ptmpnode = plist->phead;for (i = 0; i < plist->clen; i++){printf("%d  ", ptmpnode->data.id);printf("%s  ", ptmpnode->data.name);printf("%d\n", ptmpnode->data.score);ptmpnode = ptmpnode->pnext;}printf("=========================\n");
}DouNode *Joseph_loop(DouList *plist)//约瑟夫回环、实质是删除链表节点直到留下最后一个节点为止
{DouNode *pfreenode = NULL;//DouNode *ptmpnode = NULL;//指向回环ptmpnode = plist->phead;while (ptmpnode != ptmpnode->pnext)//判断回环是否只剩下一个节点{pfreenode = ptmpnode;//指向当前所在回环的位置pfreenode = pfreenode->pnext->pnext;//回环向后移动两个单位pfreenode->ppre->pnext = pfreenode->pnext;pfreenode->pnext->ppre = pfreenode->ppre; ptmpnode = pfreenode->pnext;//记录要删除的回环的下一个位置,保证循环的延续if (pfreenode == plist->phead)//判断要删除的节点是否是表头后的第一个节点、若是,给表头接入要删除节点的下一个节点{plist->phead = ptmpnode;}free(pfreenode);plist->clen--;dou_link_for_remain(plist);//打印链表中剩下的节点信息}return ptmpnode;
}

2.4 main.c

#include <stdio.h>
#include <stdlib.h>
#include "doublelink.h"int main(void)
{DataType stus[] = {{1, "doinb", 100},{2, "lwx", 67},{3, "lqs", 99},{4, "tian", 98},{5, "gimgoon", 78},{6, "xinyi", 88},{7, "nuguri", 99},{8, "khan", 77},{9, "bo", 94},{10, "xiaolaohu", 60}};DouNode *ptmpnode = NULL;int i = 0;DouList *plist = create_dou_link();//表头创建if (NULL == plist){return -1;}for (i = 0; i < sizeof(stus) / sizeof(stus[0]); i++)//给链表中插入结构体中的所有内容{push_tail_dou_link(plist, stus[i]);//尾插}dou_link_for_each(plist, 1);dou_link_for_each(plist, 0);loop_dou_link(plist);//创建双向回环链表ptmpnode = Joseph_loop(plist);//约瑟夫回环printf("%s\n", ptmpnode->data.name); return 0;
}

2.5  判断单向链表是否有环

        利用快慢指针,慢指针走一步,快指针走两步

        快指针每走一步,判断是否为空或者是否与慢指针相遇,相遇为有环链表

3. 内核链表(有头、双向循环链表)

3.1 定义

        Linux内核链表是一种双向循环链表,它的实现非常简洁而高效,主要通过一些宏和内联函数来操作链表。链表节点的结构定义在头文件 <linux/list.h> 中。

3.1 offsetof宏

        获取结构体某个成员到结构体开头的偏移量

3.2 container_of宏

        通过offsetof偏移量获取结构体的首地址

3. 栈

3.1 定义

        栈(Stack)是一种抽象的数据结构,它遵循后进先出(LIFO, Last In First Out)的原则。也就是说,最后放入栈中的元素最先被取出。

3.2 栈的基本操作

        1. 入栈、压栈:将一个元素放入栈顶。

        2. 出栈、弹栈:从栈顶移除一个元素。

        3. 取栈顶元素:查看栈顶元素但不移除它。

        4. 判断栈是否为空:检查栈中是否有元素。

3.3 分类

        (1)按实现方式分类:栈分为顺序栈和链式栈

        1. 顺序栈

               使用数组实现的栈,数组中的元素按顺序存储。优点是实现简单,访问效率高;缺点是栈的容量固定,扩展不便。 

        2. 链式栈

        使用链表实现的栈,链表的每个节点存储一个栈元素。优点是栈的容量可以动态扩展;缺点是指针操作复杂,访问效率相对较低。

        (2)按用途来分类

        1. 操作系统栈

        用于管理程序执行时的函数调用,保存函数调用的返回地址、本地变量等信息。操作系统栈通常是顺序栈,采用固定大小。

                1. 局部变量

                2. 函数的形参、返回值

                3. 函数调用关系——保护现场、恢复现场

3.4 数据结构中的栈——链式栈

4. 面试考点

        区分满增栈、满减栈、空增栈、空减栈(前提:仅限于顺序栈,数组方式构成的)

4.1 满栈和空栈——判断栈顶所在位置是否存有数据而非整个栈有没有数据

        1. 满栈:栈顶所在位置有数据

                入栈操作流程:先向上移动栈顶指针,再将数据压入栈中

        2. 空栈:栈顶所在位置没有数据

                入栈操作流程:先将数据压入栈顶,再向上移动栈顶指针


 

4.2 增栈和减栈——判断栈的生长方向

        0x1000与0x2000,内存高地址为0x2000,内存低地址为0x1000

        1. 增栈:数据入栈时栈顶指针向内存高地址移动

        2. 减栈:数据入栈时栈顶指针向内存低地址移动

(1) 满增栈

        1. 出栈时:栈顶指针向内存高地址移动,再向栈顶入栈数据,

        2. 出栈时:出栈数据,栈顶指针向内存低地址移动,

(2) 满减栈

(3) 空增栈

        1. 出栈时:先向栈顶入栈数据,栈顶指针向内存高地址移动

        2. 出栈时:栈顶指针向内存低地址移动,出栈数据

(4) 空减栈

5. 数据结构中的栈——链式栈

5.1 代码

(1)makefile

OBJ:=a.out
OBJS+=main.c stack.c
CCl=gcc$(OBJ):$(OBJS)$(CC) $^ -o $@
.PHONY:
clean:rm $(OBJ)
test:valgrind --tool=memcheck --leak-check=full ./$(OBJ)

注意:在终端输入make test可以测试销毁是否成功以及是否有内存泄漏

(2)stack.h

#ifndef _STACK_H_
#define _STACK_H_typedef int DataType;typedef struct stact_node
{DataType data;struct stact_node *pnext;
}StackNode;typedef struct Stack
{StackNode *ptop;int clen;
}StackList;extern StackList *create_stack();
extern int is_empty_stack(StackList *plist);
extern int push_stack(StackList *plist, DataType data);//入栈头插
extern void stack_for_each(StackList *plist);
extern int pop_stack(StackList *plist, DataType *pdata);//出栈头删
extern void clear_stack(StackList *plist);
extern void destory_stack(StackList *plist);
extern int get_stack_top(StackList *plist, DataType *pdata);#endif

(3)stack.c

#include <stdio.h>
#include <stdlib.h>
#include "stack.h"StackList *create_stack()
{StackList *plist = malloc(sizeof(StackList));if (NULL == plist){perror("fail to malloc");return NULL;}plist->ptop = NULL;plist->clen = 0;return plist;
}int is_empty_stack(StackList *plist)
{if (NULL == plist->ptop){return 1;}return 0;
}int push_stack(StackList *plist, DataType data)//入栈头插
{StackNode *pnode = malloc(sizeof(StackNode));if (NULL == pnode){perror("fail to malloc");return -1;}pnode->data = data;pnode->pnext = NULL;pnode->pnext = plist->ptop;plist->ptop = pnode;plist->clen++;return 0;
}void stack_for_each(StackList *plist)
{StackNode *ptmp = plist->ptop;while (ptmp != NULL){printf("%d ", ptmp->data);ptmp = ptmp->pnext;}printf("\n");
}int pop_stack(StackList *plist, DataType *pdata)//出栈头删
{if (is_empty_stack(plist)){return -1;}StackNode *pfree = plist->ptop;plist->ptop = pfree->pnext;if (pdata != NULL)//传入非空地址,将删除的节点的数据传出{*pdata = pfree->data;}free(pfree);plist->clen--;return 0;
}void clear_stack(StackList *plist)//清空栈区
{while (!is_empty_stack(plist)){pop_stack(plist, NULL);}
}void destory_stack(StackList *plist)
{if (!is_empty_stack(plist)){clear_stack(plist);}free(plist);
}int get_stack_top(StackList *plist, DataType *pdata)//获得栈顶数据
{if (is_empty_stack(plist)){return -1;}*pdata = plist->ptop->data;return 0;
}

(4)main.c

#include <stdio.h>
#include <stdlib.h>
#include "stack.h"int main(void)
{DataType tmpdata = 0;DataType data[] = {1, 2, 3, 4, 5};StackNode *ptmpnode = NULL;int i = 0;int ret = 0;StackList *plist = create_stack();//创建栈表头if (NULL == plist){return -1;}for (i = 0; i < sizeof(data) / sizeof(data[0]); i++)//入栈所有数据{push_stack(plist, data[i]);//入栈头插}stack_for_each(plist);//遍历打印所有数据#if 0for (i = 0; i < sizeof(data)/sizeof(data[0]); i++)//获取栈顶元素并打印,出栈数据,打印栈中的剩下元素{printf("======== %d ========", i);ret = get_stack_top(plist, &tmpdata);if (0 == ret){printf("ptop data:%d   ", tmpdata);}pop_stack(plist, NULL);stack_for_each(plist);//遍历打印所有数据}
#endif#if 0clear_stack(plist);//清理栈中所有节点if (is_empty_stack(plist)){printf("clear_stack success!\n");}
#endif#if 1destory_stack(plist);
#endifreturn 0;
}

5.2  应用

                1. 撤回操作

                2. 浏览器返回上一层操作

                3. 计算器

6.

中缀表达式

        前缀表达式

        后缀表达式

        

        

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

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

相关文章

【Git】 -- Part1 -- 基础操作

1. Git简介 Git 是一个开源的分布式版本控制系统&#xff0c;由 Linus Torvalds 于 2005 年开发&#xff0c;主要用于源代码管理。Git 允许多名开发者共同合作处理同一个项目&#xff0c;跟踪每个文件的修改&#xff0c;并且在必要时回滚到之前的版本。 Linus Torvalds是Linux…

面试突击:深入理解 Java 中的异常

本文已收录于&#xff1a;https://github.com/danmuking/all-in-one&#xff08;持续更新&#xff09; 前言 哈喽&#xff0c;大家好&#xff0c;我是 DanMu。今天想和大家聊聊 Java 中的异常。异常处理是一种重要的概念&#xff0c;因为程序总是会出现各种意料之外的问题&…

通过xml配置实现数据动态导入导出Excel

spring-dj-excel-common.jar 一个可以通过动态配置 xml 建立 Excel 与数据关系现实数据导入导出的 spring 组件包&#xff0c;在 xml 配置文件里&#xff0c;你可以很方便的定义 Excel - sheet 表列头文本与数据表、数据实体属性的对应关系&#xff0c;对于创建 Excel 文件&…

尽管担任社长 宫崎英高95%时间还是在做游戏

宫崎英高表示&#xff0c;虽然他是 FromSoftware 工作室的社长&#xff0c;但他日常工作的绝大部分时间都是在指导游戏开发。因魂系列大获成功而成为 FromSoftware 社长的宫崎英高在接受《卫报》采访时表示&#xff0c;企业高管生活并不是他的兴趣所在。 “我喜欢帮助年轻的监督…

cesium for unity 打包webgl失败,提示不支持

platform webgl is not supported with HDRP use the Vulkan graphics AR instead.

Linux-PXE批量安装

一、部署 PXE 远程安装服务 在大规模的 Linux 应用环境中&#xff0c;如 Web 群集、分布式计算等&#xff0c;服务器往往并不配备光驱设备&#xff0c;在这种情况下&#xff0c;如何为数十乃至上百台服务器裸机快速安装系统呢&#xff1f;传统的 USB光驱、移动硬盘等安装方法显…

双向滑动选择器

插件地址:https://ext.dcloud.net.cn/plugin?id3940 注意: 当改变值是,让滑块自动滑动需要调用: this.$refs.powerSlider.updateValue(that.tempPowerValue[0], that.tempPowerValue[1], false); <view style"width: 90%;margin: 15px"><cj-slider ref…

CAS Apereo 5.3.16 实现单点登录

1.CAS部署 服务端下载地址&#xff1a;cas5.3 1.下载好打开后&#xff0c;复制target/cas/WEB-INF/classes/META-INF/spring.factories target/cas/WEB-INF/classes/services下的Apereo-10000002.json和HTTPSandIMAPS-10000001.json target/cas/WEB-INF/classes下的applicati…

挑战Midjourney,融合近百个SD大模型的通用模型AlbedoBase XL

在SDXL的通用模型中&#xff0c;DreamShaperXL和juggernautXL这2款大模型一直都深受广大AI绘画者的喜爱&#xff0c;不可否认&#xff0c;这2款通用模型在很多方面表现都相当出色。 今天再给大家介绍一款基于SDXL的通用大模型&#xff1a;AlbedoBase XL&#xff0c;作者的目标…

iTextSharp 绘制pdf

一、新建项目&#xff1a;pdfdemo <ItemGroup><PackageReference Include"iTextSharp.LGPLv2.Core" Version"3.4.20" /> </ItemGroup>二、HomeController.cs using iTextSharp.text; using iTextSharp.text.pdf; using Microsoft.AspN…

UWA发布 | Unity手游性能年度蓝皮书

UWA本次发布的《2023-2024年度Unity手游性能蓝皮书》将汇总游戏行业使用Unity引擎进行手游开发过程中及游戏上线后的性能表现&#xff0c;从测试机型分布、引擎各模块开销、内存占用等方面剖析定位Unity手游性能瓶颈和趋势&#xff0c;反映了Unity手游行业的现状&#xff0c;帮…

【会议征稿,JPCS出版】第三届电力系统与能源技术国际学术会议(ICPSET 2024,7月5-7)

第三届电力系统与能源技术国际学术会议&#xff08;ICPSET 2024&#xff09;将于2024年7月5-7日在杭州举办。由浙江水利水电学院电机产业学院主办&#xff0c;AEIC学术交流中心承办&#xff0c;湖州市南浔创新研究院、南浔区科技局&#xff08;科协&#xff09;协办 。会议主要…

回溯算法练习题(2024/6/18)

1全排列 II 给定一个可包含重复数字的序列 nums &#xff0c;按任意顺序 返回所有不重复的全排列。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,2] 输出&#xff1a; [[1,1,2],[1,2,1],[2,1,1]]示例 2&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,…

rollup学习笔记

一直使用的webpack,最近突然想了解下rollup,就花点时间学习下. 一,什么是rollup? rollup 是一个 JavaScript 模块打包器&#xff0c;可以将小块代码编译成大块复杂的代码,比如我们的es6模块化代码,它就可以进行tree shaking,将无用代码进行清除,打包出精简可运行的代码包. 业…

【Java基础】

Java基础常见面试题总结(上) 基础概念与常识 Java 语言有哪些特点? 简单易学(语法简单,上手容易);面向对象(封装,继承,多态);平台无关性( Java 虚拟机实现平台无关性);支持多线程( C++ 语言没有内置的多线程机制,因此必须调用操作系统的多线程功能来进行多线程…

vue elementui table给表格中满足条件的每一条记录添加计时器

需求&#xff1a; 在前端给表格中给满足条件的每一条记录增加一个计时器&#xff0c;用于计算工作时长。 1.数据库中存储的有每条记录的作业开始时间&#xff0c;将当前时间和作业开始时间计算一个差值&#xff0c;作为作业时长的初始值&#xff1b; 2.把满足条件的每条记录绑…

Java中对象的比较

1. 对象的比较 在Java中&#xff0c;基本类型的对象可以直接比较大小&#xff0c;而自定义类型却不能 class Card {public int rank; // 数值public String suit; // 花色public Card(int rank, String suit) {this.rank rank;this.suit suit;}}public class TestPriori…

2008-2022年 全国31省-环境污染综合指数

环境污染综合指数是一个衡量环境污染程度或环境质量等级的抽象概括数值。它能够综合反映不同环境要素的污染情况&#xff0c;例如水污染指数和大气污染指数等。环境空气质量综合指数&#xff08;Air Quality Index, AQI&#xff09;是专门用来描述城市环境空气质量状况的一个指…

C++进阶之AVL树

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言进阶 数据结构初阶 Linux C初阶 C进阶​ ​​​​算法 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力&#xff0c;一起奔赴大厂 目录 一.前言 二.插入 三.旋转 3.1右旋 …

如何利用数据仓库进行业务分析:一名大数据工程师的视角

在大数据时代&#xff0c;数据的有效利用对企业的成功至关重要。 本文将基于上面的流程图&#xff0c;详细介绍如何利用数据仓库进行业务分析&#xff0c;并提供实际的例子和代码演示&#xff0c;以帮助读者更好地理解和应用相关技术。 数据仓库的基本流程 上图展示了一个典…