单向环形链表解决Josephu问题

单向环形链表解决Josephu问题


/**
 * Josephu 问题: 设编号为1,2,… n 的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列
 * 他的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止
 * 
 * 构建一个单向的环形链表:
 * 先创建第一个节点,让first指向该节点,并形成环形
 * 后面当我们每创建一个新节点,就把该节点加入到已有的环形链表
 * 
 * 遍历环形链表:
 * 先让一个辅助指针 curBoy 指向first节点
 * 然后通过一个while循环遍历该环形链表   curBoy.next == first 结束
 * 
 * 1.  需求创建一个辅助指针(变量) helper , 事先应该指向环形链表的最后这个节点.
 * 补充: 小孩报数前,先让 first 和  helper 移动 k - 1次
 * 2.  当小孩报数时,让first 和 helper 指针同时移动  m  - 1 次
 * 3.  这时就可以将first 指向的小孩节点 出圈
 * first = first .next 
 * helper.next = first  
 * 
 * @author Rocco_L
 *
 */



//首先先创建一个节点
class Boy{
 private int no;   //节点的编号
 private Boy next;   //指向下一个节点,默认 null
 public Boy(int no){
  this.no=no;
 }
 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;
 }
 
}


//创建环形的单项链表
class CircleSingleLinkedList{
 //创建一个first节点,当前没有编号
 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++){
   
   Boy boy = new Boy(i);
   
   if(i==1){
    first= boy;
    first.setNext(first);//构成环状
    curBoy = first;  //让curBoy指向第一个小孩
   }else{
    curBoy.setNext(boy);
    boy.setNext(first);
    curBoy = boy;
   }
   
  }
 }
 
//遍历环形链表
 public void showBoy(){
  //判断链表是否为空
  if(first == null){
   System.out.println("没有任何小孩");
   return;
  }
  //因为first不能动,因此我们仍然使用一个辅助指针完成遍历
  Boy curBoy = first;
  while(true){
   System.out.printf("小孩的编号 %d \n",curBoy.getNo());
   if(curBoy.getNext()==first){
    break;
   }
   curBoy = curBoy.getNext();  //curBoy后移
  }
  
 }


/**
  * 根据用户的输入,计算处小孩出圈的顺序
  * @param starNo    表示从第几个小孩开始 数数
  * @param countNum  表示数几下
  * @param nums  表示最初有多少小孩在圈中
  */
 public void countBoy(int starNo, int countNum , int nums){
  //先对数据校验
  if(first == null || starNo<1 || starNo> nums){
   System.out.println("参数有误,请重新输入");
   return;
  }
  
  Boy helper = first;
  while(true){
   if(helper.getNext() == first ){ //说明helper指向最后小孩节点
    break;
   }
   helper = helper.getNext();
  }
  //小孩报数前,先让first和helper移动k-1次
  for(int j = 0; j <starNo -1 ; j++){
   first = first.getNext();
   helper = helper.getNext();
  }
  //当小孩报数时,让first和helper指针同时的移动m-1次,然后出圈
  //这里是一个循环操作,直到圈中只有一个节点
  while(true){
   if(helper == first){//说明圈中只有一人
    break;
   }
   for(int j=0 ; j<countNum - 1 ; j++){
    first = first.getNext();
    helper = helper.getNext();
   }
   System.out.printf("小孩%d出圈\n",first.getNo());
   
   first = first.getNext();
   helper.setNext (first);
  }
  System.out.printf("最后留在权重的小孩编号%d \n",helper.getNo());
  
 }
 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值