【数据结构】使用循环链表结构实现约瑟夫环问题

目录

1.循环链表的定义

2.约瑟夫环问题

3.创建循环链表

4.删除节点操作

5.打印所有节点

6.实现约瑟夫环问题的完整程序代码


🌈嗨!我是Filotimo__🌈。很高兴与大家相识,希望我的博客能对你有所帮助。

💡本文由Filotimo__✍️原创,首发于CSDN📚。

📣如需转载,请事先与我联系以获得授权⚠️。

🎁欢迎大家给我点赞👍、收藏⭐️,并在留言区📝与我互动,这些都是我前进的动力!

🌟我的格言:森林草木都有自己认为对的角度🌟。

1.循环链表的定义

循环链表与常规链表的区别在于,其尾节点指向头节点,形成一个环形结构。循环链表可以分为单向循环链表和双向循环链表两种类型。

单向循环链表的定义为:每个节点包含一个数据元素和指向下一个节点的指针,而最后一个节点的指针会指向第一个节点,形成一个环形结构。

双向循环链表的定义为:每个节点包含一个数据元素以及两个指针,一个指向前一个节点,一个指向后一个节点,而第一个节点的前驱指针指向最后一个节点,最后一个节点的后继指针指向第一个节点,也形成了一个环形结构。

这种结构使得循环链表可以从任意节点开始遍历,并且可以方便地在链表中插入或删除节点。它可以通过不断重复遍历整个链表来实现循环的效果。

2.约瑟夫环问题

约瑟夫环问题是一个经典的数学问题,假设 n 个人站成一个环状,从第一个人开始报数,每次报到 m 的人出列,再从下一个人开始重新报数,直到所有人都出列。最后剩下的人的编号即为最后的获胜者。

解决约瑟夫环问题的步骤(设定问题的输入为n个人和要出局的报数m):

1. 将n个人编号为1到n。
2. 从第一个人开始报数,报到m的人出局。
3. 从出局的人的下一个人开始重新报数,继续报到m的人出局。
4. 重复第3步,直到只剩下一个人为止。

3.创建单向循环链表

typedef struct node {
    int number;
    struct node* next;
} person;

// 初始化一个循环链表,表示圆桌上的人
person* initlink(int n) {
    person* head = (person*)malloc(sizeof(person));
    head->number = 1;
    head->next = NULL;
    person* cyclic = head;
    
    // 创建 n-1 个节点,并连接成循环链表
    for (int i = 2; i <= n; i++) {
        person* body = (person*)malloc(sizeof(person));
        body->number = i;
        body->next = NULL;
        cyclic->next = body;
        cyclic = cyclic->next; 
    }
    
    cyclic->next = head;
    return head;
}

定义一个名为person的结构体,由整型变量number和指向下一节点的指针next构成。

函数initlink用于初始化一个循环链表,表示圆桌上的人。函数首先创建一个头节点,然后使用for循环创建其他的节点并连接成循环链表。最后返回头节点。

这段代码用于创建一个循环链表,其中头节点的number字段表示第一个人在圆桌上的位置,后续节点的number字段按顺序递增,最后一个节点的next字段指向头节点形成一个循环链表结构。

4.约瑟夫环求解过程

// 找到第 k 个人并开始报数,数到第 m 个人出列
void findandkillk(person* head, int k, int m) {
    person* tail = head;
    while (tail->next != head) {
        tail = tail->next;
    }
    
    person* p = head;
    while (p->number != k) {
        tail = p;
        p = p->next;
    }
    
    // 从第 k 个人开始报数,直到只剩下一个人
    while (p->next != p) {
        for (int i = 1; i < m; i++) {
            tail = p;
            p = p->next;
        }
        
        // 删除第 m 个人出列,并释放内存
        tail->next = p->next;
        printf("出列人的编号为: %d\n", p->number);
        
        person* temp = p;
        p = p->next;
        free(temp);
    }
    
    printf("出列人的编号为: %d\n", p->number);
    free(p);
}

从第k个人开始报数,每次报到第m个人就将其出列。

先用循环找到链表中的尾节点,即满足tail->next = head的节点。

再用循环找到链表中编号为k的节点,并在找到之前更新尾节点的位置。

再用循环进行报数和出列操作,直到链表中只剩下最后一个人。循环中的内层循环每次进行m-1次迭代,找到第m个人之前的节点并更新尾节点的位置。随后,删除第m个人,并释放其内存。外层循环在每次迭代之后更新当前节点的位置,并继续进行报数和出列操作。

最后,输出剩下的最后一个人的编号,并释放其内存。

5.实现约瑟夫环问题的完整程序代码

#include <stdio.h>
#include <stdlib.h>

typedef struct node {
    int number;
    struct node* next;
} person;

// 初始化一个循环链表,表示圆桌上的人
person* initlink(int n) {
    person* head = (person*)malloc(sizeof(person));
    head->number = 1;
    head->next = NULL;
    person* cyclic = head;
    
    // 创建 n-1 个节点,并连接成循环链表
    for (int i = 2; i <= n; i++) {
        person* body = (person*)malloc(sizeof(person));
        body->number = i;
        body->next = NULL;
        cyclic->next = body;
        cyclic = cyclic->next; 
    }
    
    cyclic->next = head;
    return head;
}

// 找到第 k 个人并开始报数,数到第 m 个人出列
void findandkillk(person* head, int k, int m) {
    person* tail = head;
    while (tail->next != head) {
        tail = tail->next;
    }
    
    person* p = head;
    while (p->number != k) {
        tail = p;
        p = p->next;
    }
    
    // 从第 k 个人开始报数,直到只剩下一个人
    while (p->next != p) {
        for (int i = 1; i < m; i++) {
            tail = p;
            p = p->next;
        }
        
        // 删除第 m 个人出列,并释放内存
        tail->next = p->next;
        printf("出列人的编号为: %d\n", p->number);
        
        person* temp = p;
        p = p->next;
        free(temp);
    }
    
    printf("出列人的编号为: %d\n", p->number);
    free(p);
}

int main() {
    printf("输入圆桌上的人数 n: ");
    int n;
    scanf("%d", &n);
    person* head = initlink(n);
    
    printf("从第 k 人开始报数 (k > 1 且 k < %d): ", n);
    int k;
    scanf("%d", &k);
    
    printf("数到第 m 个人出列:");
    int m;
    scanf("%d", &m);
    
    findandkillk(head, k, m);
    
    return 0; 
}

代码中的主要函数有initlink和findandkillk。

initlink函数根据输入的人数 n,初始化一个循环链表。循环链表中的每个节点都存储一个人的编号,编号从 1 到 n。该函数返回链表的头节点指针。

findandkillk函数用于解决约瑟夫环问题。它接收初始化好的循环链表的头节点指针,起始编号 k 和报数间隔 m 作为参数。首先,它找到从第 k 个人开始报数的位置,并且记录该位置的上一个节点,即tail。接着,通过迭代法,每次报数到第 m 个人时,将其从链表中删除,并释放相应的内存空间。直到链表中只剩一个节点时,停止迭代,并输出最后剩下的那个人的编号。

在main函数中,用户输入要解决的约瑟夫环问题的相关参数,然后调用findandkillk函数进行求解。

程序截图如下:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenAI 增强安全团队并赋予董事会对危险人工智能的否决权

OpenAI 在扩展其内部安全流程方面的举措以应对有害 AI 的威胁&#xff0c;OpenAI高层推出了一份更新的“准备框架”。OpenAI 的目标是识别、分析和决定如何应对他们正在开发的模型中的“灾难性”风险。他们通过对模型的四个风险类别进行评估&#xff0c;并根据风险级别制定相应…

在Android手机设置中启动ESIM

eSIM测试配置文件仅用于实验室测试。 1.到“设置”->“网络和互联网”->“SIM”&#xff0c;确认没有eSIM配置文件。 2.启动拨号程序&#xff0c;然后按短代码****#3746878#**#*&#xff08;****#ESIMTEST#**#**&#xff09; 有一个弹出通知“eSIM测试模式已启用” 3.返…

【JavaScript设计模式】Singleton Pattern

单例是可以被实例化一次的类&#xff0c;并且可以被全局访问。这个实例可以在整个应用程序中共享&#xff0c;这使得singleton非常适合管理应用程序中的全局状态。 首先&#xff0c;让我们看看使用ES2015类的单例是什么样子的。在这个例子中&#xff0c;我们将构建一个Counter…

ASP.NET MVC+EntityFramework图片头像上传

1&#xff0c;先展示一下整体的效果 2&#xff0c;接下来展示用户添加以及上传头像代码、添加用户界面 前端代码如下&#xff1a; <div class"form-group">Html.LabelFor(model > model.img, "头像&#xff1a;", htmlAttributes: new { class &…

【Linux】ip命令使用

ip命令 用于管理与配置网络接口和路由表。 ip命令的安装 ip 命令来自 iproute2 软件包&#xff0c;在 CentOS 7 中默认已安装。 yum install -y iproute 语法 ip [ OPTIONS ] OBJECT { COMMAND | help }ip [ -force ] -batch filename选项及作用 执行令 &#xff1a; ip …

计算机组成原理第4章-(存储器)【上】

存储器分类 对于计算机中存储器的分类&#xff0c;方法有很多&#xff0c;不同的方法之间是独立的&#xff0c;为此我们简单讲述两种分类 方法&#xff1a;“存取方式分类”、“在计算机中作用分类”。 -->按存取方式分类 按存取方式分类可以将存储器分为&#xff1a;“…

水经微图Web新版发布

水经微图Web新版已经上线&#xff0c;在该版本中主要新增了态势箭头标绘、文本要素标注和显示网页气泡等功能。 在本文中&#xff0c;我们将为大家分享新增的功能项&#xff0c;以及原有功能作的一些优化等。 当前版本 当前版本号为&#xff1a;1.4.0-beta 如果你发现该版…

JavaSE 泛型

目录 1 泛型类的定义1.1 为什么需要泛型1.2 泛型的概念1.3 泛型的分类 2 泛型类2.1 泛型类的定义2.2 泛型类的例子2.3 泛型类的实例化2.3.1 实例化语法2.3.2 裸类型(Raw Type) 2.4 泛型类的定义-类型边界2.5 泛型类的使用-通配符(Wildcards)2.5.1 基本概念2.5.2 通配符-上界2.5…

14、Kafka 请求是怎么被处理的

Kafka 请求是怎么被处理的 1、处理请求的 2 种常见方案1.1、顺序处理请求1.2、每个请求使用单独线程处理 2、Kafka 是如何处理请求的&#xff1f;3、控制类请求和数据类请求分离 无论是 Kafka 客户端还是 Broker 端&#xff0c;它们之间的交互都是通过 “请求 / 响应” 的方式完…

Hypervisor Display架构

Hypervisor Display架构部分 1&#xff0c;所有LA侧的APP与显示相关的调用最终都会交由SurfaceFlinger处理 2&#xff0c;SurfaceFlinger会最终调用android.hardware.graphics.composer2.4-service服务 3&#xff0c;android.hardware.graphics.composer2.4-service服务会调用G…

针对企业的泄密,天锐绿盾提出十大解决方案

01 防止公司内部数据泄密 通过动态加解密技术&#xff0c;有效防止公司内部数据泄密。即员工在创建、编辑文档时会被自动加密存放在硬盘上&#xff0c;防止员工故意或由于疏忽而造成泄密或对文件恶意破坏。 管理思路>> ● 不改变员工使用习惯、不改变文件格式、不改变…

APM固件编译和仿真

事情起因 主要想对无人机APM固件进行仿真的算法验证&#xff0c;因实际飞行的过程实际验证太浪费飞机了&#xff0c;所以就先试用仿真对算法进行仿真开发。 一&#xff0c;环境搭建 环境搭建我建议参考官方英文教程&#xff0c;英文教程写的比较全&#xff0c;不懂可以自己使…

科聪控制系统典型应用车型 —— 料箱机器人

料箱机器人即料箱AGV是一种智能化物流搬运设备&#xff0c;它可以代替人力完成出库入库和搬运工作&#xff0c;可根据出入库生产出货需求&#xff0c;将货物从起点运送到终点&#xff0c;自动柔性完成货到人货到点的操作。 提升仓储和物流效率的自动化利器 料箱机器人的投用能…

yolov5单目测距+速度测量+目标跟踪(算法介绍和代码)

要在YOLOv5中添加测距和测速功能&#xff0c;您需要了解以下两个部分的原理&#xff1a; 单目测距算法 单目测距是使用单个摄像头来估计场景中物体的距离。常见的单目测距算法包括基于视差的方法&#xff08;如立体匹配&#xff09;和基于深度学习的方法&#xff08;如神经网…

C语言--字符函数与字符串函数

大家好&#xff0c;我是残念&#xff0c;希望在你看完之后&#xff0c;能对你有所帮助&#xff0c;有什么不足请指正&#xff01;共同学习交流 本文由残念ing 原创CSDN首发&#xff0c;如需要转载请通知 个人主页&#xff1a;残念ing-CSDN博客&#xff0c;欢迎各位→点赞&#…

leetcode---76. 最小覆盖子串 [C++/滑动窗口+哈希表]

原题&#xff1a;76. 最小覆盖子串 - 力扣&#xff08;LeetCode&#xff09; 题目解析&#xff1a; 此题在这道题的基础上进行理解会更简单 leetcode --- 30. 串联所有单词的子串[C 滑动窗口/双指针]-CSDN博客 本题要求在s字符串中找到含有t字符串所有字符的最短子串。 也就是…

【lesson17】MySQL表的基本操作--表去重、聚合函数和group by

文章目录 MySQL表的基本操作介绍插入结果查询&#xff08;表去重&#xff09;建表插入数据操作 聚合函数建表插入数据操作 group by&#xff08;分组&#xff09;建表插入数据操作 MySQL表的基本操作介绍 CRUD : Create(创建), Retrieve(读取)&#xff0c;Update(更新)&#x…

XAgent的部署及运行

源代码clone git clone config 文件的修改 在XAgent源码目录&#xff0c;运行 vi .env&#xff0c; 修改以下配置条目 CONFIG_FILEassets/gpt-3.5-turbo_config.ymlpython环境 python >3.10 安装conda&#xff0c;通过conda激活python3.10的环境 wget https://repo.a…

josef约瑟 跳合位、电源监视继电器 HRTH-Y-2H2D DC220V

系列型号&#xff1a; HRTH-Y-2H2D-X-T跳位监视、合位监视、电源监控继电器&#xff1b; HRTH-Y-2Z-X-T跳位监视、合位监视、电源监控继电器&#xff1b; HRTH-Y-2H-X-T跳位监视、合位监视、电源监控继电器&#xff1b; HRTH-J-2H2D-X-T跳位监视、合位监视、电源监控继电器…

Axure中继器的基本使用

介绍中继器 在 Axure 中&#xff0c;中继器是一种交互设计元素&#xff0c;用于在不同页面之间传递数据或触发特定的事件。它可以帮助模拟真实的用户交互流程和页面之间的传递逻辑&#xff0c;继承关系用于描述两个元件之间的父子关系。通过使用继承关系&#xff0c;您可以创建…
最新文章