环形链表
一.简介:
环形链表也叫循环链表(可以是双链表、也可以是单链表),操作原理和单链表差不多,只是最后一个节点不在指向空(null)而是头(head),这里以单链表举例:
二.代码实现约瑟夫问题
1)构建一个单向的环形链表思路
- 先创建第一个节点,让first指向该节点,并形成环形
- 后面当我们每创建一个新的节点,就把该节点加入到已有的环形链表中即可。
2)遍历环形链表
- 先让一个辅助指针(变量)curBoy,指向first节点
- 然后通过一个while循环遍历该环形链表即可,curBoy.next == first结束
5. 约瑟夫问题小孩出圈的思路分析
1 | 1 .定义孩子类型 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public class Boy { private int no; //编号 private Boy next; //指向下一个节点 public int getNo() { return no; } public void setNo( int no) { this .no = no; } public Boy getNext() { return next; } public void setNext(Boy next) { this .next = next; } public Boy( int no) { this .no = no; } } |
1 | 2 .定义循环链表 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | public class CircleSingleLinkedList { private Boy first = new Boy(- 1 ); //添加小孩节点,构建一个环形链表 public void addBoy( int nums){ //参数校验 if (nums< 1 ){ System.out.println( "nums的值不正确" ); return ; } Boy curBoy = null ; //辅助指针 for ( int i = 1 ; i <= nums; i++) { //使用for循环创建环形链表 //根据编号创建小孩节点 Boy boy = new Boy(i); //如果是第一个小孩 if (i== 1 ){ first=boy; first.setNext(first); //构成一个换 curBoy=first; //将指针指向第一个节点 } else { curBoy.setNext(boy); boy.setNext(first); curBoy=boy; //指针后移 } } } /*遍历环形链表*/ public void showBoy(){ /*判断链表是否为空*/ if (first.getNext()== null ){ System.out.println( "环形链表为空!!!" ); return ; } Boy curBoy = first; while ( true ){ System.out.printf( "小孩的编号:%d\n" ,curBoy.getNo()); if (curBoy.getNext()==first){ //遍历完毕 break ; } curBoy=curBoy.getNext(); //指针后移 } } /*根据用户的输入计算出小孩出圈的顺序*/ /** * * @description:TODO * @params:1.第几个小孩开始2.表示数几下,3.最初有多少个小孩 * @return: * @author: sxw * @time: 2020/3/11 20:32 */ public void countBoy( int startNo, int countNum, int nums){ //参数校验 if (first == null ||startNo< 0 ||startNo>nums){ System.out.println( "输入参数有误,请重新输入" ); return ; } Boy helper = first; while ( true ){ //将指针指向最后一个节点 if (helper.getNext()==first){ break ; } helper=helper.getNext(); } //小孩报数,将first和helper移动K-1次 for ( int i = 0 ; i <startNo- 1 ; i++) { first=first.getNext(); helper=helper.getNext(); } //报数时将first和helper同时移动m-1次,然后出圈 //当圈内只有一个节点时循环结束 while ( true ){ if (helper==first){ //什么时候结束圈内只有一个节点 break ; } //让first和helper同时移动countNum次 for ( int i = 0 ; i <countNum- 1 ; i++) { first=first.getNext(); helper=helper.getNext(); } //这时first指向的是小孩出圈的节点 System.out.printf( "小孩%d出圈\n" ,first.getNo()); //first指向的小孩出圈 first=first.getNext(); helper.setNext(first); } System.out.printf( "最后留着圈中小孩编号%d\n" ,first.getNo()); } } |
3.进行测试
1 2 3 4 5 6 7 8 9 10 11 | public class JosepFu { public static void main(String[] args) { //测试构建和遍历环形链表是否ok CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList(); circleSingleLinkedList.addBoy( 5 ); circleSingleLinkedList.showBoy(); /*测试小孩出圈*/ circleSingleLinkedList.countBoy( 1 , 2 , 5 ); } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构