【数据结构算法经典题目刨析(c语言)】环形链表的约瑟夫问题

news2024/11/24 17:16:04

 

💓 博客主页:C-SDN花园GGbond

⏩ 文章专栏:数据结构经典题目刨析(c语言)

一.前言: 

前言——著名的Josephus问题

据说著名犹太 Josephus有过以下的故事:在罗⻢⼈占领乔塔帕特后,39个犹太⼈与Josephus及他的朋友躲到⼀个洞中,39个犹太⼈决定宁愿死也不要被⼈抓到,于是决定了⼀个⾃杀 ⽅式,41个⼈排成⼀个圆圈,由第1个⼈开始报数,每报数到第3⼈该⼈就必须⾃杀,然后再由下⼀ 个重新报数,直到所有⼈都⾃杀⾝亡为⽌。 历史学家 然⽽Josephus和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与⾃⼰安排在 第16个与第31个位置,于是逃过了这场死亡游戏。

 二.题目描述:

三.题目解析 

题目的意思就是从环形链表的第一个节点开始数,数到第 m 的时候释放对应的节点,然后从下个节点又从1开始数,然后继续释放节点。所以我们要做的就是通过循环不断删除指定位置的节点。比如有5个节点,在删除第二个节点之前,得先让第一个节点的 next 指向第三个。
不过题目现在还没有链表,我们得先来创建一个。

下面这个图演示有五个节点,m = 2的情况 

 图解:

 

 

四.解题思路 

解决思路是用环形链表来模拟报数和离开
解决问题分三步
1. 实现申请单个环形链表的方法
2.创建环形链表
3.对链表循环遍历,实现报数和删除,返回最后剩下的节点的编号
 

 五.解题步骤

1.实现申请单个环形链表的方法 


动态申请一块节点大小的空间,并对数据和指针初始化(数据部分存储节点的编号,指针部分指向节点自身,默认自循环)
返回创建节点的地址

struct ListNode
{   //链表结构
    int val;
    struct ListNode* next;
};
typedef struct ListNode ListNode;//类型重定义
ListNode* NewNode(int a)//申请单个链表节点
{
    ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
    if (newnode == NULL)
    {
        exit(1);
    }
    newnode->val = a;
    newnode->next = newnode;//默认节点自循环
    return newnode;
}
2.创建环形链表


a. 先创建第一个节点作为首节点,创建首尾指针都指向该节点

(先单独创建一个节点,是因为根据题目描述,链表至少有一个节点,并且先单独申请一个节点可以保证链表不会空,省去后面申请节点时对链表判空的步骤)

b. 然后循环创建n个节点,尾插在链表上
c. 出循环后,把尾节点的next指针指向首节点
d. 返回链表的尾指针(返回尾指针是因为下一步骤要删除链表某个节点需要找到它的前一个节点,而环形链表返回尾指针可以同时获得尾节点和首节点)

 

ListNode* CreatList(int n)//根据n创建环形链表
{
    ListNode* phead = NewNode(1);//创建链表第一个节点
    ListNode* ptail = phead;
    for (int i = 2; i <= n; i++)//将新节点尾插到链表
    {
        ListNode* newnode = NewNode(i);
        ptail->next = newnode;
        ptail = ptail->next;
    }
    ptail->next = phead;//成环
    return ptail;//返回尾指针相当于得到了尾指针和头指针
}
 3.对链表循环遍历,实现删除,

a. 首先创建遍历指针的前一个节点的指针,初始指向尾节点

创建遍历链表的指针,初始指向尾节点的下一个节点,也就是首节点
创建一个计数器,初始为1

b. 进入while循环(循环执行的条件是遍历链表的指针所指向的节点的next指针不指向它自己,也就是说链表只有一个节点时结束循环)
循环内部,对计数器进行判断
如果计数器等于要报的数m,删除该节点,计数器重置为1
如果不等于要报数的m,两个指针向后移动,计数器++

c. 退出循环时,返回最后剩下的节点所对应的编号

注意:
返回编号之前不要忘记释放最后一个节点动态申请的空间

int ysf(int n, int m)
{
    ListNode* prev = CreatList(n);//创建环形链表,和指向前一个节点的指针
    ListNode* pcur = prev->next;//创建遍历链表的指针
    int count = 1;
    while (pcur->next != pcur)//循环结束的条件是某个节点自循环
    {
        if (count == m)//如果报数到m,删除节点
        {
            prev->next = pcur->next;
            free(pcur);
            pcur = prev->next;
            count = 1;
        }
        else //如果不是m,指针移动,计数器++
        {
            prev = pcur;
            pcur = pcur->next;
            count++;
        }
    }
    int ret = pcur->val;
    free(pcur);
    pcur = NULL;
    return ret;
}

六:完整代码实现 

struct ListNode
{   //链表结构
    int val;
    struct ListNode* next;
};
typedef struct ListNode ListNode;//类型重定义
ListNode* NewNode(int a)//申请单个链表节点
{
    ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
    if (newnode == NULL)
    {
        exit(1);
    }
    newnode->val = a;
    newnode->next = newnode;//默认节点自循环
    return newnode;
}
ListNode* CreatList(int n)//根据n创建环形链表
{
    ListNode* phead = NewNode(1);//创建链表第一个节点
    ListNode* ptail = phead;
    for (int i = 2; i <= n; i++)//将新节点尾插到链表
    {
        ListNode* newnode = NewNode(i);
        ptail->next = newnode;
        ptail = ptail->next;
    }
    ptail->next = phead;//成环
    return ptail;//返回尾指针相当于得到了尾指针和头指针
}
int ysf(int n, int m)
{
    ListNode* prev = CreatList(n);//创建环形链表,和指向前一个节点的指针
    ListNode* pcur = prev->next;//创建遍历链表的指针
    int count = 1;
    while (pcur->next != pcur)//循环结束的条件是某个节点自循环
    {
        if (count == m)//如果报数到m,删除节点
        {
            prev->next = pcur->next;
            free(pcur);
            pcur = prev->next;
            count = 1;
        }
        else //如果不是m,指针移动,计数器++
        {
            prev = pcur;
            pcur = pcur->next;
            count++;
        }
    }
    int ret = pcur->val;
    free(pcur);
    pcur = NULL;
    return ret;
}

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

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

相关文章

C#初级——List 容器

容器 在C#中&#xff0c;容器通常指的是用于存储和组织数据的集合类。 本文介绍的容器是动态数组&#xff1a;List<T> 内部使用数组来存储元素&#xff0c;当添加元素超出当前数组容量时&#xff0c;会自动调整大小&#xff08;扩容&#xff09;。 list容器 List<&g…

【ARM】ArmDS中Coretex-M处理器GPIO时钟使能代码分析

1、 文档目标 了解ArmDS中Coretex-M处理器GPIO时钟使能代码&#xff0c;掌握GPIO时钟使能的流程及其依据。 2、 问题场景 在应用Coretex-M处理器进行项目开发时&#xff0c;GPIO的使用&#xff0c;是任何一个开发人员必须掌握的内容。 3、软硬件环境 1&#xff09;、软件版本…

vue项目Nginx部署启动

1.vue打包 &#xff08;1&#xff09;package.json增加打包命令 "scripts": {"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --host 10.16.14.110","start": "npm run dev","un…

11部门公布第二批国家数字乡村试点地区名单

近日&#xff0c;中央网信办、农业农村部、国家发展改革委、工业和信息化部、民政部、生态环境部、商务部、文化和旅游部、中国人民银行、市场监管总局、国家数据局联合印发通知&#xff0c;公布第二批国家数字乡村试点地区名单&#xff08;附后&#xff09;&#xff0c;并对组…

深入分析 Android ContentProvider (十)

文章目录 深入分析 Android ContentProvider (十)ContentProvider 的高级使用及最佳实践&#xff08;续&#xff09;1. ContentProvider 与异步加载使用 CursorLoader 进行异步数据加载 2. 动态权限请求动态请求权限示例 3. ContentProvider 的缓存优化使用 LruCache 实现内存缓…

优化 GitHub 体验的浏览器插件「GitHub 热点速览」

上周&#xff0c;GitHub 有个“安全问题”——CFOR&#xff08;Cross Fork Object Reference&#xff09;冲上了热搜&#xff0c;该问题的表现是&#xff1a; 远程仓库的提交内容任何人可以访问&#xff0c;即使已被删除。只需要拿到 commit ID源/Fork 的项目地址&#xff0c;任…

猫头虎分享AI写真系统架构分析

摘要 AI写真系统 是目前最受欢迎的技术之一&#xff0c;本文将详细介绍该系统的架构和实现&#xff0c;包括 前端框架Uni-app、后端框架Saas、AI Agent后端框架dify和langchain&#xff0c;以及通义千问 GPT-4 MJ DALL-E 3的应用。无论是技术小白还是大佬&#xff0c;都能从…

docker安装人大金仓最新数据库

1.下载docker版本人大金仓数据库 1.1 点击人大金仓网址&#xff0c;下载镜像包 1.2 上传镜像包并导入镜像 在这里插入代码片 #上传后导入镜像2.启动人大金仓数据库容器 docker run -tid \ --privileged \ --name kingbase \ -v /opt/kingbase/data:/home/kingbase/userdata…

2024思维导图软件大赏:哪些工具让知识管理更轻松

如果你是上班族&#xff0c;有时候会议需要头脑风暴&#xff0c;收到的信息总是杂乱无章令人头疼。这时候使用幕布思维导图这样的工具就如同智慧的灯塔&#xff0c;他会帮我们指引准确的方向。 1.福昕思维导图 链接直达&#xff1a;https://www.pdf365.cn/naotu/ 这个思维导…

LLC数字控制TMS320F28034,2-根据原理图配置GPIO控制引脚

LLC数字控制TMS320F28034&#xff0c;2-根据原理图配置GPIO控制引脚 LLC数字控制TMS320F28034&#xff0c;2-根据原理图配置GPIO控制引脚1 TMS320F280341.1 GPIO概述1.2 GPIO寄存器说明1.3 GPIO寄存器使用注意事项 2 项目原理图介绍2.1 GPIO使用介绍2.2 功能引脚使用说明 3 软件…

5、注册字符类设备

字符设备 cdev结构体 Linux中使用cdev结构体描述一个字符设备。结构体定义在include/linux/cdev.h 文件中&#xff0c; struct cdev{struct kobject kobj;struct module *owner; //所属模块const struct file_operations *ops; //文件操作结构体struct list_head lis…

Spring Cloud 集成 Nacos、openfeign 错误解决

前言&#xff1a; 在集成 Nacos 和 openfeign 的时候&#xff0c;过程出现了一点小曲折&#xff0c;这里简单分享一下&#xff0c;希望可以帮助到有需要的朋友。 Spring boot 版本如下&#xff1a; <version>2.4.5</version>Spring Alibaba 版本如下&#xff1a…

【狂神】多线程(含内部类、Lambda)

整体参考 一、线程 1、多任务&#xff1a; 现实中太多这样同时做多件事情的例子了&#xff0c;看起来是多个任务都在做&#xff0c;其实本质上我们的大脑在同一时间依旧只做了一件事情。 2、多线程&#xff1a; 原来是一条路&#xff0c;慢慢因为车太多了&#xff0c;道路…

程序员面试 “八股文”在实际工作中是助力、阻力还是空谈?

“八股文”在实际工作中是助力、阻力还是空谈&#xff1f; 作为现在各类大中小企业面试程序员时的必问内容&#xff0c;“八股文”似乎是很重要的存在。但“八股文”是否能在实际工作中发挥它“敲门砖”应有的作用呢&#xff1f;有IT人士不禁发出疑问&#xff1a;程序员面试考…

[FBCTF2019]RCEService (PCRE回溯绕过和%a0换行绕过)

json格式输入ls出现index.php 这道题原本是给了源码的&#xff0c;BUUCTF没给 源码&#xff1a; <?phpputenv(PATH/home/rceservice/jail);if (isset($_REQUEST[cmd])) {$json $_REQUEST[cmd];if (!is_string($json)) {echo Hacking attempt detected<br/><br/…

WebLogic: CVE-2020-14882/14883【getshell】

记录第一次getshell公网设备 漏洞介绍 CVE-2020-14882&#xff1a;允许 未授权 的用户绕过管理控制台 &#xff08;Console&#xff09;的权限验证访问后台 CVE-2020-14883&#xff1a;允许后台任意用户通过HTTP协议 执行任意命令 使用这两个漏洞组成的利用链&#xff0c;可通过…

ECCV`24 | 比DragDiffusion快100倍!RegionDrag:快·准·好的图像编辑方法!港大牛津

文章链接&#xff1a;https://arxiv.org/pdf/2407.18247 github链接&#xff1a;https://github.com/LuJingyi-John/RegionDrag 亮点直击 引入了一种基于区域的图像编辑方法&#xff0c;以克服基于点拖拽方法的局限性&#xff0c;利用更丰富的输入上下文来更好地对齐编辑结果与…

排序算法:归并排序,golang实现

目录 前言 归并排序 代码示例 1. 算法包 2. 归并排序代码 3. 模拟程序 4. 运行程序 5. 从大到小排序 归并排序主要操作 1. 合并 2. 分割&#xff08;Divide&#xff09;与递归排序&#xff08;Conquer&#xff09; 总体思想 循环次数测试 假如 10 条数据进行排序…

虾皮笔试0620-编程题

难度偏易&#xff0c;给出解题思路。 按照空格分割字符串&#xff0c;每个字符串用双指针反转小写字母。 记录原来位置到二维数组&#xff0c;排序&#xff0c;从小到达购买&#xff0c;再把英雄对应之前的位置排序输出。 先变成循环链表&#xff0c;找到旋转后的头节点&#x…

day2 PS教程——搞定图层的使用方法,效率大翻倍

day2 PS教程——搞定图层的使用方法&#xff0c;效率大翻倍 目录 1.图层 智能对象 2.蒙版 与智能对象绑定 使用橡皮——镂空 剪切模板 上放图片&#xff0c;下放图形&#xff0c;按ALT同时&#xff0c;点击两图层间的即可 底下可以放黑色背景 选中多个图层后&#xff0…