【数据结构与算法 刷题系列】环形链表的约瑟夫问题

news2024/11/26 8:18:52

💓 博客主页:倔强的石头的CSDN主页

📝Gitee主页:倔强的石头的gitee主页

⏩ 文章专栏:数据结构与算法刷题系列(C语言)

目录

一、问题描述

二、解题思路详解

解题思路

解题步骤

三、C语言代码实现


一、问题描述

前言——著名的Josephus问题

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

 

二、解题思路详解

解题思路

解决思路是用环形链表来模拟报数和离开
解决问题分三步
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. 返回链表的尾指针(返回尾指针是因为下一步骤要删除链表某个节点需要找到它的前一个节点,而环形链表返回尾指针可以同时获得尾节点和首节点)

 环形链表创建过程示意图

插入节点完成之后.......

最后将尾指针指向的节点的next指针指向首指针指向的节点

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;
}

三、C语言完整代码实现

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/1671538.html

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

相关文章

文件流-ASCII文件(中北大学-程序设计基础(2))

目录 题目 源码 结果示例 题目 编写程序实现以下功能&#xff1a;【要求处理ASCII文件】 &#xff08;1&#xff09;按职工号由小到大的顺序将5个员工的数据&#xff08;包括号码、姓名、年龄和工资&#xff09;输出到磁盘文件中保存&#xff1b; &#xff08;2&#xff…

服务器3389端口,服务器3389端口风险提示的应对措施

3389端口是Windows操作系统中远程桌面协议&#xff08;RDP&#xff09;的默认端口。一旦该端口被恶意攻击者利用&#xff0c;可能会导致未经授权的远程访问和数据泄露等严重安全问题。 针对此风险&#xff0c;强烈建议您采取以下措施&#xff1a; 1. 修改默认端口&#xff1a;…

八、e2studio VS STM32CubeIDE之内存使用情况窗口

目录 一、概述/目的 二、STM32CubeIDE Build Analyzer 三、e2studio Memory Usage 八、e2studio VS STM32CubeIDE之内存使用情况窗口 一、概述/目的 1、嵌入开发最大特点之一就是资源受限&#xff0c;关注芯片资源使用详情是优秀工程师的技能之一 2、Keil和IAR都不支持内存…

Linux性能压测指标信息

1、CPU使用 服务器CPU整体负载信息 可以查看top命令输出的第三行数据 查看多核CPU命令 mpstat -P ALL 和 sar -P ALL top命令执行后输入1 2、内存使用 top命令或者free命令来查看内存的信息&#xff0c;第一行是物理内存使用&#xff0c;第二行是虚拟内存使用(交换空间)。…

WebSocket建立网络连接——小案例

WebSocket是一种实现全双工通信的网络技术标准&#xff0c;它允许在用户的浏览器和服务器之间进行持久的、双向的通信。以下是对WebSocket的具体介绍&#xff1a; 实时性&#xff1a;与传统HTTP请求相比&#xff0c;WebSocket提供了更高效的实时数据交换方式。一旦建立连接&am…

【cpp】并发多线程 Unique

1. unique_lock 何时锁定资源。 unique_lock lock1 时候&#xff0c;还没有锁住资源。 实际是后面&#xff0c;显式的出发&#xff1a; 比如&#xff0c; lock.lock, 或 std::lock(lk1,lk2), 或者条件变量CV.wait(mtx, []{!re})。 #include <iostream> #include <mu…

虚拟仿真云平台在教育应用中的优势和意义

虚拟仿真云实验教学平台作为一种新型的教学方法&#xff0c;近年来在高校教育中得到了十分广泛的应用。它通过模拟真实的实验场景和实验操作&#xff0c;让学生在计算机上进行实验操作和数据处理&#xff0c;为学生提供了更加便捷、可靠、有效的实验学习环境。本文&#xff0c;…

ssm123基于java web的网上书城系统的设计与实现+vue

基于java web的网上书城系统的设计与实现vue 摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff0c;商品交易当然也不能排除在外&#xff0c;随着商品交易管理的不断成熟&#xff0c;它彻底改变了…

基于SpringBoot + Vue实现的考编(考研)论坛网站设计与实现+毕业论文

系统介绍 系统包含用户和管理员两个角色 用户&#xff1a;登录、注册、经验交流平台、发布帖子、回复帖子、查看公告信息、跳蚤市场&#xff08;商品购买、商品出售、商品评价&#xff09;、个人中心等功能 管理员&#xff1a;登录、个人中心、管理员管理、用户管理、基础数据管…

REACT 在组件之间共享状态

有时&#xff0c;您希望两个组件的状态始终一起变化。要做到这一点&#xff0c;请从他们俩身上删除状态&#xff0c;将其移动到他们最近的共同父级&#xff0c;然后通过道具将其传递给他们。这被称为提升状态&#xff0c;这是编写 React 代码时最常见的事情之一。 举例提升状态…

2024年3月 青少年等级考试机器人理论真题三级

202403 青少年等级考试机器人理论真题三级 第 1 题 流程图图例如下&#xff0c;与该图例功能对应的选项是&#xff1f;&#xff08; &#xff09; A&#xff1a;开始/结束 B&#xff1a;输入/输出 C&#xff1a;判断 D&#xff1a;处理 第 2 题 Arduino UNO/Nano主控板&am…

机器人学导论实验1—CoppeliaSim 平台介绍及初步使用BJTU

1. 实验内容分析 对实验内容的理解及关键点&#xff1a; 理解这个实验的关键点在于理解如何使用CoppeliaSim和MATLAB来控制和操作机器人。需要熟悉这两个工具的基本操作&#xff0c;例如如何加载场景、如何修改机器人参数、如何使用MATLAB客户端程序来控制机器人等。此外&#…

开源分布式爬虫管理平台:性能强悍!!【送源码】

简介 基于 Golang 的分布式爬虫管理平台&#xff0c;支持 Python、NodeJS、Go、Java、PHP 等多种编程语言以及多种爬虫框架。 谁适合使用 Crawlab? 网路爬虫工程师&#xff1a; 通过集成爬虫程序到 Crawlab&#xff0c;网路爬虫工程师可以聚焦于爬虫的核心解析逻辑&#xff0…

C语言学习【C语言基本数据类型二】

C语言学习【C语言基本数据类型二】 _Bool类型 C99标准添加了_Bool类型&#xff0c;用于表示布尔值&#xff0c;即逻辑值true和false&#xff0c;原则上仅占用1位存储空间&#xff1b; float、double和long double 记数法示例 C标准规定&#xff0c;float类型必须至少能表示…

2024CCPC郑州站超详细题解(含题面)ABFHJLM(河南全国邀请赛)

文章目录 前言A Once In My LifeB 扫雷 1F 优秀字符串H 随机栈J 排列与合数L Toxel 与 PCPC IIM 有效算法 前言 这是大一博主第一次参加xcpc比赛&#xff0c;虽然只取得了铜牌&#xff0c;但是收获满满&#xff0c;在了解了和别人的差距后会更加激励自己去学习&#xff0c;下面…

Linux修炼之路之权限

目录 引言 一&#xff1a;Linux中用户的分类 二&#xff1a;在Linux中的权限 1.权限的两种属性 1.人的属性 2.事物属性 -主要以文件属性为主 3.文件权限值的两种表示方式方法 2.更改文件访问者(拥有者&#xff0c;所属组&#xff0c;其他人)权限属性 3.更改文件的拥有…

vue3专栏项目 -- 四、前后端结合(下)

一、async 和 await 1、使用async 和 await 改造异步请求 在接触后端API以后就遇到了越来越多的异步请求&#xff0c;现在我们就使用async 和 await 改造异步请求。 async function是把返回内容包裹成个Promise返回Promise await 它在async function里面才起作用&#xff0…

【全开源】JAVA上门家政服务系统源码微信小程序+微信公众号+APP+H5

功能介绍 用户端&#xff1a;精准分类、支持家政、维修、万能服务、一口价、报价、线上、各类家政服务、优惠专区、师傅入驻、商家入驻、我的需求、补费明细、我的投诉 师傅端&#xff1a;接单池、消息通知、接单管理、今日订单、师傅入驻、我的钱包、实名认证 商家端&#…

【排序算法】之希尔排序

一、算法介绍 希尔排序(Shell Sort)是插入排序的一种&#xff0c;它是针对直接插入排序算法的改进。希尔排序又称缩小增量排序&#xff0c;因 DL.Shell 于 1959 年提出而得名。它通过比较相距一定间隔的元素来进行&#xff0c;各趟比较所用的距离随着算法的进行而减小&#xf…

系统设计 —— 随用户扩展

单服务器设置&#xff1a; 在单服务器设置中&#xff0c;所有内容都运行在一台服务器上。这包括网页应用程序、数据库、缓存等。 1*HQXZgCc5Vh8KooJHwKfzjw.png 图1.1 请求流程 1.最终用户通过域名&#xff08;myurl.com&#xff09;访问网站。请求发送到 DNS&#xff0c;将域名…