2020-08-25

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

约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将出圈,最后剩下一个,例如N=5,M=2,出圈的顺序是:2 4 1 5 3。这里使用单向环形链表来处理约瑟夫问题,单向环形链表其实就是在原有单链表的基础上将尾结点指向头结点,从而构成一个单向环形链表。

单向环形链表的构建方法:

(1)定义一个cur辅助指针接收每次创建好的结点,当创建第一个结点时,把first赋给cur。First指向first构成环
(2)把每次创建好的node结点赋给cur(相当于first.next = node)
(3)把每次创建好的node结点指向first构成环
(4)把cur = node后移

单向环形链表的遍历方法:

(1)定义一个辅助指针cur,循环遍历一次输出一次cur
(2)当cur.next == first时退出循环

使用单向链表创建单向环形链表示意图:

在这里插入图片描述

约瑟夫问题:

(1)定义n(需要创建的节点)  m(需要数多少下)  startNO(从第几个开始)
(2)定义一个cur结点,事先放在单向环形链表最后一个结点
(3)将first(头指针)和cur(辅助指针)移动startNo - 1次,为了设定好初始位置
(4)循环遍历进行报数,每次报数时将first(头指针)和cur(辅助指针)移动m - 1次,为了得到报数的位置,将得到的first输出并出圈(first = first.next  cur.next = first)	
(5)当cur=first此时退出循环

在这里插入图片描述

以下为实现代码:

package com.java;

public class Josephu {
    public static void main(String[] args) {
        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
        circleSingleLinkedList.addNode(5);
        circleSingleLinkedList.count(1,2,5);
    }

}
//定义一个不带头结点的单向环形链表
class CircleSingleLinkedList {
    Node first = null;

    //1、单向环形链表的构造
    public void addNode(int n)
    {
        //判断n的值是否有效
        if (n < 1){
            System.out.println("n的值有误");
            return;
        }
        Node cur = null;//定义一个辅助指针
        for (int i = 1; i <= n ; i++) {
            Node node = new Node(i);
            if (i == 1)//如果是第一个结点
            {
                first = node;//node放入头结点
                first.next = first;//构成环形单链表
                cur = first;//把cur定义为第一个结点
            }else{
                cur.next = node;//把cur结点指向node(下一个节点)
                node.next = first;//构成环
                cur = node;//后移
            }
        }

    }

    //2、遍历单向环形链表
    public void list()
    {
        //预处理,判断单向链表是否只有一项
        if (first == null)
        {
            System.out.println("单向环形链表无数据!");
            return;
        }
        Node cur = first;
        //当cur.next = first说明已经遍历完毕
        while (true)
        {
            System.out.println(cur);
            if (cur.next == first)break;
            cur = cur.next;
        }
    }

    //3、约瑟夫问题,报数
    //startNo --->从第几个节点开始数
    //m --->需要数多少下
    //n --->最初的节点数
    public void count(int startNo,int m,int n) {
        Node cur = first;//定义一个辅助指针
        //预处理判断接收的数据是否有误
        if (first == null || startNo < 1 || startNo > m) {
            System.out.println("数据有误");
            return;
        }
        //把辅助指针放在环的最后一个节点
        while (true)
        {
            if (cur.next == first)break;
            cur = cur.next;//后移
        }
        //把first指针与辅助指针移动stratNo-1次
        for (int i = 0; i < startNo - 1; i++) {
            first = first.next;
            cur = cur.next;
        }
        //此时进行报数
        while (true)
        {
            if (cur == first)break;//此时说明表中只有一个节点
            //让first指针与cur指针同时移动m-1次
            for (int i = 0; i < m - 1; i++) {
                first = first.next;
                cur = cur.next;
            }
            //此时把结点输出出来
            System.out.println(first);
            //再后移一次,为下次输出节点做准备
            first = first.next;
            cur.next = first;
        }
        System.out.println("此时最后一个节点为:" + first);
    }


}


class Node
{
    private int no;//声明编号
    public Node next;//定义下一个指向指针

    public Node(int no) {
        this.no = no;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }

    @Override
    public String toString() {
        return "Node{" +
                "no=" + no +
                '}';
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值