循环链表Java数据结构篇(即约瑟夫环问题)

本章学习目录

一,环形链表的介绍
  • 循环链表:是另一种形式的链式存储结构。类似于单链表,但是它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。
  • 逻辑结构图
    流程
二,约瑟夫环的问题
  • 约瑟夫环问题:(Josephus问题)约瑟夫问题(有时也称为约瑟夫斯置换,是一个计算机科学和数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环。又称“丢手绢问题”.),
  • 理解:即解决在一个n节点的圈子中,从某一个位置开始数,数到m并取出该节点,反复操作,直至环取空;
三,环形链表的节点类
package com.环形链表;

public class Node {
    public int no;//编号
    public Node next;//指向下一个节点

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

四,环形链表的建立和打印
public class CircleSingleLinkedList {
    //创建第一个节点
    private Node firstNode=null;
    //方法一:构建环
    //方法二:打印环内节点
    //方法三:约瑟夫环问题的解决(配合法一用)
    }
  • 构建环
    /**
     * 向环中添加节点,即构建环形链表
     * @param num,添加节点的数量
     */
    public void addNodeNum(int num){
        //判断num合法
        if (num<1){
            System.out.println(num+"不能构成环");
            return;
        }
        //使用for循环来创建环形链表
        //定义一个辅助节点,初始值为firstNode
        Node temp=firstNode;
        for (int i=1;i<=num;i++){
            //根据编号创建环形链表内的节点
            Node node=new Node(i);
            if (i==1){
                firstNode=node;
                firstNode.next=firstNode;//构成环
                temp=firstNode;
            }else{
                temp.next=node;//将辅助节点后移
                node.next=firstNode;//成环,让最后生成的节点指向第一个节点
                temp=node;
            }
        }
    }

  • 打印环内节点
    /**
     * 打印环形链表
     */
    public void printNodeList(){
        //判断链表是否为空
        if (firstNode==null){
            System.out.println("链表为空");
            return;
        }
        //创建辅助节点,直接从firstNode开始遍历,
        Node temp=firstNode;
        while (true){
            System.out.println("节点编号"+temp.no);
            if (temp.next==firstNode){
                break;
            }else {
                temp=temp.next;
            }
        }
    }

  • 约瑟夫环问题
    /**
     * 约瑟夫环问题
     * @param startnum 从startnum节点开始数
     * @param countnum 数countnum次
     * @param num 总共有num个节点
     */
    public void findNodeBynum(int startnum,int countnum,int num){
        //先校验数据合理性
        if (startnum<1||startnum>num||firstNode==null){
            System.out.println("参数有误");
            return;
        }
        //创建要给辅助指针,帮助完成小孩出圈
        Node temp=firstNode;
        //通过while循环,将temp指向first的前一个节点
        while (true){
            if (temp.next==firstNode){
                break;
            }
            temp=temp.next;
        }
        //for循环目的:让first和temp分别移动到第startnum的节点和startnum的前一个处
        for (int i=1;i<startnum;i++){
            firstNode=firstNode.next;
            temp=temp.next;
        }
        System.out.println("开始节点:"+firstNode.no);
        //用于计算第count次出圈
        int count=0;
        //通过while循环找出要出来的节点
        while (true){
            if (firstNode==temp){
                break;
            }
            //for循环找出要出圈的节点
            for (int j=1;j<countnum;j++){
                firstNode=firstNode.next;
                temp=temp.next;
            }
                count++;
            System.out.println("第"+count+"次出来的节点"+firstNode.no);
            //让对应节点出圈,并保证环的连通性
            firstNode=firstNode.next;
            temp.next=firstNode;
        }
        System.out.println("最后的节点是"+temp.no);
    }
五,约瑟夫环问题的解决
  • 环形链表的节点类在目录三
  • 操作类如下:
package com.环形链表;
/**
*先构建环形链表
*对链表进行出圈
*/
public class CircleSingleLinkedList {
    //创建第一个节点
    private Node firstNode=null;
    /**
     * 向环中添加节点,即构建环形链表
     * @param num,添加节点的数量
     */
    public void addNodeNum(int num){
        //判断num合法
        if (num<1){
            System.out.println(num+"不能构成环");
            return;
        }
        //使用for循环来创建环形链表
        //定义一个辅助节点,初始值为firstNode
        Node temp=firstNode;
        for (int i=1;i<=num;i++){
            //根据编号创建环形链表内的节点
            Node node=new Node(i);
            if (i==1){
                firstNode=node;
                firstNode.next=firstNode;//构成环
                temp=firstNode;
            }else{
                temp.next=node;//将辅助节点后移
                node.next=firstNode;//成环,让最后生成的节点指向第一个节点
                temp=node;
            }
        }
    }
    /**
     * 约瑟夫环问题(和上面的方法一起使用)
     * @param startnum 从startnum节点开始数
     * @param countnum 数countnum次
     * @param num 总共有num个节点
     */
    public void findNodeBynum(int startnum,int countnum,int num){
        //先校验数据合理性
        if (startnum<1||startnum>num||firstNode==null){
            System.out.println("参数有误");
            return;
        }
        //创建要给辅助指针,帮助完成小孩出圈
        Node temp=firstNode;
        //通过while循环,将temp指向first的前一个节点
        while (true){
            if (temp.next==firstNode){
                break;
            }
            temp=temp.next;
        }
        //for循环目的:让first和temp分别移动到第startnum的节点和startnum的前一个处
        for (int i=1;i<startnum;i++){
            firstNode=firstNode.next;
            temp=temp.next;
        }
        System.out.println(firstNode.no);
        //用于计算第count次出圈
        int count=0;
        //通过while循环找出要出来的节点
        while (true){
            if (firstNode==temp){
                break;
            }
            //for循环找出要出圈的节点
            for (int j=1;j<countnum;j++){
                firstNode=firstNode.next;
                temp=temp.next;
            }
                count++;
            System.out.println("第"+count+"次出来的节点"+firstNode.no);
            //让对应节点出圈,并保证环的连通性
            firstNode=firstNode.next;
            temp.next=firstNode;
        }
        System.out.println("最后的节点是"+temp.no);
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值