使用环形链表解决约瑟夫(丢手帕)问题
约瑟夫问题:
设编号为1,2,3...n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依此类推,直到所有人出列为止,由此产生一个出队编号的序列,并求出最后出列的人是哪个?
1.先死后活:
将问题简化成:有4个人围坐一圈,从编号1的人开始报数,数到2的人出列,依次类推。
2.创建节点类:
1 /** 2 * 节点类 3 * @author SCOTT 4 * 5 */ 6 public class Child { 7 /*编号*/ 8 int no; 9 /*下一个节点*/ 10 Child next; 11 12 public Child(int no){ 13 this.no = no; 14 } 15 }
3.创建环形链表,并返回第一个节点
1 /** 2 * 创建一个环形链表 3 * @param head 指定第一个节点的头指针 4 * @param num 环形链表个数 5 * @return 返回指定第一个节点的头指针 6 */ 7 private static Child createCircleLink(Child head,int num){ 8 //要报障head不改变,让cur游走各个节点之间 9 Child cur = null; 10 for(int i=0;i<num;i++){ 11 Child child = new Child(i+1); 12 if(i==0){ 13 head = child; 14 child.next = child; 15 }else{ 16 cur.next = child; 17 child.next = head; 18 } 19 cur = child; 20 } 21 return head; 22 }
4.测试环形链表是否创建成功
1 /** 2 * 遍历环形链表节点 3 * @param head 4 */ 5 private static void ergodicCircleLink(Child head){ 6 if(head == null) 7 return; 8 9 Child cur = head; 10 while(cur.next != head){ 11 System.out.println("当前节点:"+cur.hashCode()+"\t下一个节点:"+cur.next.hashCode()); 12 cur = cur.next; 13 } 14 //当前cur指向最后一个节点 15 System.out.println("当前节点:"+cur.hashCode()+"\t下一个节点:"+cur.next.hashCode()); 16 }
5.环形链表创建成功后,就可以玩游戏了
1 /** 2 * 从第一个人开始数,数2下 3 * @param head 4 * @param k 从k开始数 5 * @param m 数m下 6 * @param n 链表个数 7 */ 8 private static void play(Child head, int k, int m, int n){ 9 if(head == null) 10 return; 11 12 if(!(k>=1 && k<= n)){ 13 System.out.println("指定人数不在范围内,"+k+">"+n); 14 return; 15 } 16 17 //指向当前节点 18 Child cur = head; 19 //需要一个与cur相邻的并位于cur后一位的指针,初始位置让他指向最后一个节点,便于删除节点 20 Child tail = null; 21 while(cur.next != head){ 22 cur = cur.next; 23 } 24 tail = cur; 25 cur = head; 26 27 //找到第k个位置 28 for(int i=0;i<k-1;i++){ 29 cur = cur.next; 30 tail = tail.next; 31 } 32 33 while(cur != tail){ 34 //开始数数:移动一次,代表数了2下 35 for(int i=0;i<m-1;i++){ 36 cur = cur.next; 37 tail = tail.next; 38 } 39 System.out.println("第"+cur.no+"号小朋友出列!"); 40 //删除cur指向的节点 41 //让cur再往下移一个节点 42 cur = cur.next; 43 tail.next = cur; 44 } 45 System.out.println("获胜的小朋友:"+tail.no); 46 }
6.测试:
1 public static void main(String[] args) { 2 int n = 4; 3 int m = 2; 4 int k = 1; 5 //指向环形链表的第一个节点,便于链表的操作 6 Child head = null; 7 head = createCircleLink(head, n); 8 //ergodicCircleLink(head); 9 play(head, k, m, n); 10 }
标签:
数据结构与算法
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· 一个基于 .NET 开源免费的异地组网和内网穿透工具
· 《HelloGitHub》第 108 期
· Windows桌面应用自动更新解决方案SharpUpdater5发布
· 我的家庭实验室服务器集群硬件清单