链表之单向环形链表(约瑟夫问题)

1.单向环形链表介绍:单向环形链表就是单向链表的各个节点的指向形成一个环形,当链表由一个节点时,它的next指向自己,两个或两个以上则是最后一个的next指向第一个。

 

2.约瑟夫问题的介绍:设编号为12....n的n个人围坐一圈,约定编号为k(1<k<n)的人开始报数,数到m的那个人出列,它的下一位右从1开始报数,数到m的那个人出列,依此类推,直到所有人出队为止,由此产生一个出队编号的序列。

3.用单向环形链表解决约瑟夫问题的思路:

构建环形链表

① 先创建第一个节点,由first节点指向该节点,并形成环形。

②后面当我们每创建一个新的节点,就把该节点,加入到已有的环形链表即可。

遍历环形链表

①先让一个辅助指针(变量)curboy指向,指向first节点。

②然后通过while循环遍历该环形链表即可,curboy.next==first结束。

小孩出圈

① 需要创建一个辅助指针helper,事先应该指向链表的最后一个节点。

②小孩报数前,先让first指针和helper指针移动k-1次。

③当小孩报数报数,first和helper指针同时移动m-1次,这时让first指向的小孩出圈即可fist=first.next,helper.next=first.

4.代码实现:

public class Josepfu {
    public static void main(String[] args) {
        CircleList circleList = new CircleList();
        circleList.addList(5);
        circleList.showBoy();
        circleList.outBoy(1,2,5);
    }
}
// 构建单向环形链表
class CircleList{
    // 创建第一个first节点,没有编号。
    private Boy first=null;
    // 添加节点,构建环形单向链表
    public void  addList(int num){
        if(num<1){
            System.out.println("num数值不正确!!!");
            return;
        }
        Boy curBoy=null;// 辅助指针
        for(int i=1;i<=num;i++){
            Boy boy = new Boy(i);
            if(i==1){
                first=boy;
                boy.setNext(first); // 构成环
                curBoy=boy;

            }else{

                curBoy.setNext(boy);
                boy.setNext(first);
                curBoy=boy;
            }

        }
    }
    // 遍历当前环形链表
    public void showBoy(){
        if(first==null){
            System.out.println("环形链表为空~~~~");
        }
        Boy curBoy=first;
        while (curBoy!=null){
            System.out.printf("小孩编号 %d\n",curBoy.getNo());
            curBoy=curBoy.getNext();
            if(curBoy==first){
                break;
            }
        }

    }

    /**
     *
     * @param start  从那个小孩开始数
     * @param countNum   数多少个数
     * @param sum  一一共有多少人
     */
    // 根据输入,计算出圈顺序
    public void outBoy(int start,int countNum,int sum){
        if(first==null||start<1||start>sum){
            System.out.println("请输入正确的数");
            return;
        }
        // 辅助指针helper
        Boy helper=first;
        while(true) {
            if (helper.getNext() == first) {
                break;
            }
            helper = helper.getNext();
        }
        // 小孩报数前,先让first和helper指针移动start-1
        for(int i=0;i<start-1;i++){
            first=first.getNext();
            helper=helper.getNext();
        }
        // 当小孩报数前先让first和helper移动countNum-1再出圈。
        while(true){
            if(helper==first){
                break;
            }

        // 让first和helper移动countNum-1
        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",first.getNo());
    }
}

// 创建一个Boy类表示一个节点
class Boy{
    private int no;
    private Boy next;

    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;
    }
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值