环形链表实现约瑟夫问题

约瑟夫问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3。

代码实现:

package com.xsw.linklist.linklist;

import com.xsw.linklist.bean.Node;

/**
 * 环形单链表 解决约瑟夫问题
 */
public class SimpleCircleLinklist {
    public Node head;
    //添加
    public void add(int num){
        if (num<1){
            return ;
        }
        Node cur = null ; //辅助指针,指向最后一个节点
        for (int i=1;i<=num;i++){
            if (i==1){//初始化第一个节点,并指向头节点
                head = new Node(i);
                head.setNext(head); //形成环形链表
                cur = head ;
            }else{
                Node node = new Node(i);//初始化其他节点
                cur.setNext(node);//将最后节点指针指向新加入的节点
                node.setNext(head); //将新加入的节点指向头节点
                cur = cur.getNext() ; //后移辅助指针
            }
        }
    }

    /**
     * 解决约瑟夫问题:N个人围成一圈,从第k个开始报数,第M个将被杀掉,最后剩下一个,
     * 其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3。
     *
     * 实现思路:
     *      1、被杀掉即意味着从链表中删除该节点 因此定义 pre、target指针
     *      2、当pre=target时,说明链表中只剩一个节点
     * @param n n个人
     * @param k 从第k个开始报数
     * @param m 第m个被杀掉
     */
    public void dealJoseph(int n,int k,int m) {
        if (n < m || n < 2 || m < 0) {
            System.out.println("输入参数有误!");
        }
        this.add(n);//初始化环形链表
        int count = 1 ; //计数器
        Node pre = head; //辅助指针,被杀掉的人的前一个(先定位到尾结点)
        Node target = head; //杀掉的人(先定位到头节点)
        //1、先遍历把pre定位到尾结点for
        for (int i = 1; i < n; i++) {
            pre = pre.getNext();//遍历结束后pre就指向了尾结点
        }

        // 2、先定位到第k个人
        for (int i = 1; i < k; i++) {
            target = target.getNext();
            pre = pre.getNext();
        }
        //3.开始杀人
        while(pre!=target){ //如歌pre等于target,说明链表中只剩下一个人,存活
            if (count == m){ //target就是当前要干掉的
                //杀掉,从链表中移除
                System.out.println(target.getData()+"被杀掉");
                pre.setNext(target.getNext());
                target = target.getNext() ;
                count = 1 ;//重新计数
            }else{
                //移动pre、target指针
                pre = pre.getNext();
                target = target.getNext() ;
                count++ ; //报数
            }
        }
        System.out.println("幸存者是:"+pre.getData());
    }

    //遍历
    public void list(){
        Node cur = head ; //辅助节点帮助遍历
        while(true){
            if (cur.getNext()==head){
                System.out.println(cur.getData());
                break;
            }
            System.out.println(cur.getData());
            cur = cur.getNext() ;
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值