意见箱
恒创运营部门将仔细参阅您的意见和建议,必要时将通过预留邮箱与您保持联络。感谢您的支持!
意见/建议
提交建议

java-Java_约瑟夫环详尽分享_个人文章

来源:恒创科技 编辑:恒创科技编辑部
2024-01-31 03:04:59
Java_约瑟夫环详尽分享

先看代码后看分享

1. 约瑟夫环代码
下面是完整代码与注释
public class LinkedNode<T> {
    //设置私人的对象
    private T data; //定义泛型数据域
    private LinkedNode<T> next; //定义后继引用域
    
    public LinkedNode() {    //无参构造函数,构造空结点
        data = null;next = null;
    }

    public LinkedNode(T element){    //构造函数,构造数据域为element值的结点
        data = element;next= null;
    }

    public T getData() {    //获取数据域data的值
        return data;
    }

    public void setData(T data) {    //设置数据域data值
        this.data = data;
    }

    public LinkedNode<T> getNext() {    //获取next值
        return next;
    }

    public void setNext(LinkedNode<T> next) {    //设置next值
        this.next = next;
    }
}


public class datatype {
    private int id;    //存放我们的id
    private int password;    //存放我们的密码

    public datatype() {    //构造无参构造函数,构造空结点
    }

    public datatype(int id, int password) { //构造函数,让其与引入的内容对接
        this.id = id;
        this.password = password;
    }

    public int getId() {    //获取我们的id值
        return id;
    }

    public void setId(int id) {    //设置我们的id值
        this.id = id;
    }

    public int getPassword() {    //获取我们的密码
        return password;
    }

    public void setPassword(int password) {    //设置我们的密码
        this.password = password;
    }
}

import java.util.Scanner;

 class CList<T> {
    private LinkedNode<T> rear ;//生成一个节点,定义尾指针

    public CList() {
        rear = null;
    }

    public LinkedNode<T> getRear() {
        return rear;
    }

    public void setRear(LinkedNode<T> rear) {
        this.rear = rear;
    }

    public T yunxingCircular(int m) {
        if (isEmpty()){//判断是否为空
            throw new RuntimeException("空表");
        }
        else {//如果不是空表,判断当前是否是一个元素
            if (rear.getNext() == rear) {//如果只有一个元素
                LinkedNode<T> cz = rear;//设置一个新节点,承载rear节点
                rear = null;//让此时rear的值为null,即删除此处元素
                return cz.getData();//返回此时用于承载节点的数据域
            }
            else {//如果不是只有一个元素
                int a = 1;//定义第一个个人报数为1
                while (a < m) {//当报数上限值<该次密码值时
                    rear = rear.getNext();//尾指针向后移一位
                    a++;//报数值加一
                }
                LinkedNode<T> cz = rear.getNext();//设置新节点承载rear的后一个节点
                rear.setNext(rear.getNext().getNext());//让rear的引用域为之前rear的下下一个节点的地址
                return cz.getData();//返回承载节点cz的数据域
            }
        }
    }

    public void insert(T element){//用于表达插入元素进约瑟夫表的方法
        LinkedNode<T> cr = new LinkedNode<T>(element);//设置一个新节点cr,其数据域为element
        if (rear == null){//如果rear值为null,即只有一个元素
            rear = cr;//rear此时就等于刚刚插入的新节点cr
            rear.setNext(rear);//加入一个元素之后,rear的下一个元素还是rear,构成了循环
        }
        else {//如果不是一个元素
            cr.setNext(rear.getNext());//插入的元素的引用域就是此时尾指针指向元素的引用域中的地址,即与当时的尾结点相接
            rear.setNext(cr);//此时尾指针指向元素的引用域为cr元素
            rear = cr;//再把尾指针向后移一位
        }
    }

     public boolean isEmpty() {//用于判断循环链表为空的方法
         if (rear == null)//根据rear是否=null来判断返回的值是true还是false
             return true;
         else
             return false;
     }


}

public class Ysf {
   public static void main(String[] args) {
       CList zx = new CList();//建立一个Clist的对象
       Scanner sr =  new Scanner(System.in);
       System.out.println("请输入环内人数");
       int peoples = sr.nextInt();//确定环内总人数
       System.out.println("请输入初始密码值");
       int password  = sr.nextInt();
       int jl = 1;//用于跟随记录第几几人的密码值
       do {
           System.out.println("请输入第"+jl+"人的密码值");
           int password0 =sr.nextInt();//挨个输入每一个人的密码值
           datatype jd = new datatype(jl,password0);//创建datatype的节点,节点内存储着每一个人和其对应的密码值
           zx.insert(jd);//将节点依次加入到约瑟夫环内
           jl++;//记录数就加一
       }while (jl <= peoples);//只要记录数不超出人数
       int b = 0;
       while (b<peoples){//当人数小于people数时
           datatype  c = (datatype) zx.yunxingCircular(password);//将初始密码值加进去去运行约瑟夫环
           System.out.println(c.getId());//输出c对象的id值
           password = c.getPassword();//让密码值更新,去寻找
           b++;//再次循环执行
       }
   }
}
2. 什么是约瑟夫环

约瑟夫1环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。通常解决这类问题时把编号从0~n-1,最后结果+1即为原问题的解。

3. 理解约瑟夫环3.1 完成节点类和数据类定义

在真正开始设计我们的约瑟夫环之前,我们需要有节点类数据类的支撑,如下所示


java-Java_约瑟夫环详尽分享_个人文章

下方LinkedNode就是我们的节点类
public class LinkedNode<T> {
    //设置私人的对象
    private T data; //定义泛型数据域
    private LinkedNode<T> next; //定义后继引用域
    
    public LinkedNode() {    //无参构造函数,构造空结点
        data = null;next = null;
    }

    public LinkedNode(T element){    //构造函数,构造数据域为element值的结点
        data = element;next= null;
    }

    public T getData() {    //获取数据域data的值
        return data;
    }

    public void setData(T data) {    //设置数据域data值
        this.data = data;
    }

    public LinkedNode<T> getNext() {    //获取next值
        return next;
    }

    public void setNext(LinkedNode<T> next) {    //设置next值
        this.next = next;
    }
}
下方datatype就是我们的数据类
public class datatype {
    private int id;    //存放我们的id
    private int password;    //存放我们的密码

    public datatype() {    //构造无参构造函数,构造空结点
    }

    public datatype(int id, int password) { //构造函数,让其与引入的内容对接
        this.id = id;
        this.password = password;
    }

    public int getId() {    //获取我们的id值
        return id;
    }

    public void setId(int id) {    //设置我们的id值
        this.id = id;
    }

    public int getPassword() {    //获取我们的密码
        return password;
    }

    public void setPassword(int password) {    //设置我们的密码
        this.password = password;
    }
}
3.2 理解插入过程

我们有两个步骤来帮助理解

我们利用伪代码2来制作图像,如下图所示

擅自制作

接下来我们利用图像写出代码,如下所示

public void insert(T element){    //用于表达插入元素进约瑟夫表的方法
   LinkedNode<T> cr = new LinkedNode<T>(element);    //设置一个新节点cr,其数据域为element
   if (rear == null){    //如果rear值为null,即只有一个元素
       rear = cr;    //rear此时就等于刚刚插入的新节点cr
       rear.setNext(rear);    //加入一个元素之后,rear的下一个元素还是rear,构成了循环
   }
   else {    //如果不是一个元素
       cr.setNext(rear.getNext());    //插入的元素的引用域就是此时尾指针指向元素的引用域中的地址,即与当时的尾结点相接
       rear.setNext(cr);    //此时尾指针指向元素的引用域为cr元素
       rear = cr;    //再把尾指针向后移一位
   }
}
3.3 理解运行过程

首先,我们要知道判断循环链表为空的方法,如下所示

public boolean isEmpty() {    //用于判断循环链表为空的方法
      if (rear == null)    //根据rear是否=null来判断返回的值是true还是false
          return true;
      else
          return false;
}

之后同样的我们还用两个步骤来继续帮助理解

我们再利用伪代码来制作图像,如下图所示

擅自制作

接下来我们利用图像写出代码,如下所示

 private LinkedNode<T> rear ;    //生成一个节点,定义尾指针

 public CList() {
     rear = null;
 }

 public LinkedNode<T> getRear() {    //获取尾指针
     return rear;
 }

 public void setRear(LinkedNode<T> rear) {    //设置尾指针
     this.rear = rear;
 }
 
 public T yunxingCircular(int m) {
         if (isEmpty()){    //判断是否为空
             throw new RuntimeException("空表");
         }
         else {    //如果不是空表,判断当前是否是一个元素
             if (rear.getNext() == rear) {    //如果只有一个元素
                 LinkedNode<T> cz = rear;    //设置一个新节点,承载rear节点
                 rear = null;    //让此时rear的值为null,即删除此处元素
                 return cz.getData();    //返回此时用于承载节点的数据域
             }
             else {    //如果不是只有一个元素
                 int a = 1;    //定义第一个个人报数为1
                 while (a < m) {    //当报数上限值<该次密码值时
                     rear = rear.getNext();    //尾指针向后移一位
                     a++;    //报数值加一
                 }
                 LinkedNode<T> cz = rear.getNext();    //设置新节点承载rear的后一个节点
                 rear.setNext(rear.getNext().getNext());    //让rear的引用域为之前rear的下下一个节点的地址
                 return cz.getData();    //返回承载节点cz的数据域
             }
         }
     }
3.4 理解更新密码值

我们用文字来理解:先把运行和更新密码分开来,设立一个单独的while循环3,每执行一次yunxingCircular,就获取一次getpassword,并且让password等于获取到getpassword ,把新的password放入循环中。yunxingCircular和更新密码值在一个循环内,所以能够实现每次的密码值更新,如下所示

    int b = 0;
    while (b<peoples){    //当人数小于people数时
        datatype  c = (datatype) zx.yunxingCircular(password);    //将初始密码值加进去去运行约瑟夫环
        System.out.println(c.getId());    //输出c对象的id值
        password = c.getPassword();    //让密码值更新,去寻找
        b++;    //再次循环执行
        }
3.5 将更新密码值放入我们的调用类中去

如下所示

public class Ysf {
    public static void main(String[] args) {
        CList zx = new CList();    //建立一个Clist的对象
        Scanner sr =  new Scanner(System.in);
        System.out.println("请输入环内人数");
        int peoples = sr.nextInt();    //确定环内总人数
        System.out.println("请输入初始密码值");
        int password  = sr.nextInt();
        int jl = 1;    //用于跟随记录第几几人的密码值
        do {
            System.out.println("请输入第"+jl+"人的密码值");
            int password0 =sr.nextInt();    //挨个输入每一个人的密码值
            datatype jd = new datatype(jl,password0);    //创建datatype的节点,节点内存储着每一个人和其对应的密码值
            zx.insert(jd);    //将节点依次加入到约瑟夫环内
            jl++;    //记录数就加一
        }while (jl <= peoples);    //只要记录数不超出人数
        int b = 0;
        while (b<peoples){    //当人数小于people数时
            datatype  c = (datatype) zx.yunxingCircular(password);    //将初始密码值加进去去运行约瑟夫环
            System.out.println(c.getId());    //输出c对象的id值
            password = c.getPassword();    //让密码值更新,去寻找
            b++;    //再次循环执行
        }
    }
}

以上就是本文全部内容,如果对你有帮助,可以随手点个赞,这对我真的很重要。


来自搜狗百科:https://baike.sogou.com/v7958... ↩伪代码(Pseudocode)是一种非正式的,类似于英语结构的,用于描述模块结构图的语言。人们在用不同的编程语言实现同一个算法时意识到,他们的实现(注意:这里是实现,不是功能)很不同。尤其是对于那些熟练于不同编程语言的程序员要理解一个(用其他编程语言编写的程序的)功能时可能很难,因为程序语言的形式限制了程序员对程序关键部分的理解。这样伪代码就应运而生了。伪代码提供了更多的设计信息,每一个模块的描述都必须与设计结构图一起出现。(来自搜狗百科:https://baike.sogou.com/v7860...) ↩ 某个出名的循环(while,循环语句,是计算机的一种基本循环模式。当满足条件时进入循环,不满足跳出。) ↩
上一篇: java-基于SpringBoot+VUE实现博客系统_个人文章 下一篇: 手机怎么远程登录云服务器?