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

目录

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.hqwc.cn/news/285722.html

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

相关文章

寒冷环境里人们为什么更爱高热脂类食物?多丽特膳解析

环境越冷&#xff0c;我们越离不开热呼呼的饮食&#xff0c;特别是热量高、油脂高的&#xff0c;这是因为寒冷的环境会引发我们的身体消耗更多的热量&#xff0c;当我们感到冷时&#xff0c;我们的身体会分泌肾上腺素以及其它分泌&#xff0c;这些分泌会使我们感到饥饿和口渴。…

OO AutoBackup 6: 自动备份同步文件工具箱软件

保护您的数据&#xff0c;让备份变得轻松简单。 概述 O&O AutoBackup 6 是一款功能强大的自动备份同步文件工具箱软件。通过实时监控您的文件和文件夹&#xff0c;O&O AutoBackup 6 确保您的重要数据始终得到保护。无论您是在工作还是在家庭环境中&#xff0c;这款软…

Docker介绍,Docker安装

docker镜像仓库官网 一、Docker的基本概念 1.Docker的三大核心组件 docker 镜像 --------docker images docker 仓库---------docker registeries docker 容器---------docker containers 2.Docker 镜像 Docker镜像是运行docker容器时的只读模板&#xff0c;每一个镜像由一…

电脑操作系统深度剖析:Windows、macOS和Linux的独特特性及应用场景

导言 电脑操作系统是计算机硬件和应用软件之间的桥梁&#xff0c;不同的操作系统在用户体验、性能和安全性方面有着独特的特色。电脑操作系统是计算机系统中的核心组件&#xff0c;不同的操作系统在设计理念、用户体验和应用领域上存在显著差异。本文将深入探讨几种常见的电脑操…

idea恢复默认出厂设置

idea恢复默认出厂设置 1、IDEA 2021 之后&#xff0c; 在顶部工具栏&#xff0c;选择 File | Manage IDE Settings | Restore Default Settings. 2、或者双击shift搜索Restore Default settings然后点击restore and restart

houdini 神经网络

实现个神经网络的3D可视化&#xff0c;美爆了&#xff01;-腾讯云开发者社区-腾讯云 https://vimeo.com/stefsietz GitHub - julrog/nn_vis: A project for processing neural networks and rendering to gain insights on the architecture and parameters of a model throu…

2023_Spark_实验二十九:Flume配置KafkaSink

实验目的&#xff1a;掌握Flume采集数据发送到Kafka的方法 实验方法&#xff1a;通过配置Flume的KafkaSink采集数据到Kafka中 实验步骤&#xff1a; 一、明确日志采集方式 一般Flume采集日志source有两种方式&#xff1a; 1.Exec类型的Source 可以将命令产生的输出作为源&…

【Linux】冯诺依曼体系结构与操作系统及其进程

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;了解冯诺依曼体系结构与操作系统&#xff0c;掌握…

Redis基础数据结构详解

大家好&#xff0c;我是伯约&#xff0c;希望这篇对大家有帮助&#xff0c;文章末尾放了我从小白到架构师多年的学习资料 1.String字符串 String是redis中最基本的数据类型&#xff0c;一个key对应一个value。 String类型是二进制安全的&#xff0c;意思是 redis 的 string 可以…

P40 Transformer

概述 语法剖析 一个样本有多个类别归属 机器自己决定输出几个东西&#xff0c;输出的长度为多少 seq2seq实现过程 addnorm 代表 residual noorm resudial: inputoutput &#xff1f;&#xff1f;&#xff1f; Decoder AT 语音或者语句起始的地方&#xff0c;会有一个 sp…

龙迅LT6211B,HDMI1.4转LVDS,应用于AR/VR市场

产品描述 LT6211B 是一款用于 VR/ 显示应用的高性能 HDMI1.4 至 LVDS 芯片。 对于 LVDS 输出&#xff0c;LT6211B 可配置为单端口、双端口或四端口。对于2D视频流&#xff0c;同一视频流可以映射到两个单独的面板&#xff0c;对于3D视频格式&#xff0c;左侧数据可以发送到一个…

nethuner无法ping无法apt

ping无法使用&#xff0c;会提示Socket: Permission denied&#xff0c;在解析的过程中会提示Temporary failure in name resolution. usermod -G 3003 root usermod -G 3003 kali接着 vim /etc/passwd下滑 找到 _apt 然后将_apt 的3004修改为3003 点击esc 输入 :wq 退出编辑模…