数据结构——>单向环形链表

2023-11-11

一、单向环形链表应用场景

提起单向环形链表,就不得不说约瑟夫问题,约瑟夫环。什么事约瑟夫问题呢?

1、约瑟夫问题(有时也称为约瑟夫斯置换,是一个计算机科学和数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环。又称“丢手绢问题”.)

2、约瑟夫问题起源
据说,著名犹太历史学家Josephus,有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人,与Josephus,及他的朋友,躲到一个洞中,39个犹太人,决定宁愿死,也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人,该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友,并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方,才能避免被处决。Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏

3、约瑟夫问题图例
在这里插入图片描述

二、单向环形链表介绍

1、入队过程:
在这里插入图片描述2、出队过程:
在这里插入图片描述

三、单向环形链表代码实现

1、代码实现思路

1、添加节点,构成环装链表

 public void addKid(int nums){
        //nums数据校验
        if(nums<1){
            System.out.println("数据错误");
            return;
        }
        //辅助指针,帮助构成环
        Kid curKid=null;
        //使用for循环来创建环形链表
        for (int i = 1; i <=nums ; i++) {
            //根据编号创建小孩节点
            Kid kid=new Kid(i);
            //如果是第一个小孩
            if(i==1){
                first=kid;
                first.setNext(first);
                curKid=first;//让curKid指向第一个小孩
            }else{
                curKid.setNext(kid);//curkid指针指向下一个孩子
                kid.setNext(first);//再指回first
                curKid=kid;
            }
        }
    }

2、遍历当前链表

  public void showKid(){
        //判断链表是否为空
        if(first==null){
            System.out.println("链表为空");
            return;
        }
        //因为first不能动,需要创建一个帮助指针来帮助遍历
        Kid curKid=first;
        while (true){
            System.out.printf("小孩的编号%d\n",curKid.getNo());
            if(curKid.getNext()==first){//说明已经遍历完毕
                break;
            }
            curKid=curKid.getNext();//curKid向后移
        }
    }

3、计算节点出圈顺序

/**
     *
     * @param startNo   表示从第几个小孩开始数数
     * @param countNum  表示数几下
     * @param nums      表示最初有几个小孩在圈中
     */
    public void countKid(int startNo,int countNum,int nums) {
        if (first == null || startNo < 1 || startNo > nums) {
            System.out.println("输入的数据错误");
            return;
        }
        //创建一个辅助指针帮助小孩出圈
        Kid helper = first;
        while (true) {
            if (helper.getNext() == first) {//说明已经遍历完毕
                break;
            }
            helper = helper.getNext();
        }
        //让小孩报数前先让frist和helper指针移动k-1次(比如报2次数,实际指针只移动了一下)
        for (int j = 0; j < startNo - 1; j++) {
            first = first.getNext();
            helper = helper.getNext();
        }
        //当小孩报数前,让first和helper指针同时移动m-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();
            }
            //first指向的节点就是要出圈的节点
            System.out.printf("出圈的小孩\n", first.getNo());
            //first指向的节点出圈
            first = first.getNext();
            helper.setNext(first);
        }
        System.out.printf("最后留在圈里的节点%d\n", first.getNo());
    }

2、代码实现

完整代码

package sparsearray;

/**
 * @author shkstart
 * @create 2021-08-08 16:22
 */
public class Josepfu {
    public static void main(String[] args) {
        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
        circleSingleLinkedList.addKid(5);

        circleSingleLinkedList.showKid();
        circleSingleLinkedList.countKid(1,2,5);
    }
}
//创建一个环形的单向链表
class CircleSingleLinkedList{
    //创建一个first节点,当前没有编号
    private Kid first=null;
    //添加小孩节点,构成环装链表
    public void addKid(int nums){
        //nums数据校验
        if(nums<1){
            System.out.println("数据错误");
            return;
        }
        //辅助指针,帮助构成环
        Kid curKid=null;
        //使用for循环来创建环形链表
        for (int i = 1; i <=nums ; i++) {
            //根据编号创建小孩节点
            Kid kid=new Kid(i);
            //如果是第一个小孩
            if(i==1){
                first=kid;
                first.setNext(first);
                curKid=first;//让curKid指向第一个小孩
            }else{
                curKid.setNext(kid);//curkid指针指向下一个孩子
                kid.setNext(first);//再指回first
                curKid=kid;
            }
        }
    }


    //遍历当前链表
    public void showKid(){
        //判断链表是否为空
        if(first==null){
            System.out.println("链表为空");
            return;
        }
        //因为first不能动,需要创建一个帮助指针来帮助遍历
        Kid curKid=first;
        while (true){
            System.out.printf("小孩的编号%d\n",curKid.getNo());
            if(curKid.getNext()==first){//说明已经遍历完毕
                break;
            }
            curKid=curKid.getNext();//curKid向后移
        }
    }

    //计算小孩出圈顺序
    /**
     *
     * @param startNo   表示从第几个小孩开始数数
     * @param countNum  表示数几下
     * @param nums      表示最初有几个小孩在圈中
     */
    public void countKid(int startNo,int countNum,int nums) {
        if (first == null || startNo < 1 || startNo > nums) {
            System.out.println("输入的数据错误");
            return;
        }
        //创建一个辅助指针帮助小孩出圈
        Kid helper = first;
        while (true) {
            if (helper.getNext() == first) {//说明已经遍历完毕
                break;
            }
            helper = helper.getNext();
        }
        //让小孩报数前先让frist和helper指针移动k-1次(比如报2次数,实际指针只移动了一下)
        for (int j = 0; j < startNo - 1; j++) {
            first = first.getNext();
            helper = helper.getNext();
        }
        //当小孩报数前,让first和helper指针同时移动m-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();
            }
            //first指向的节点就是要出圈的节点
            System.out.printf("出圈的小孩\n", first.getNo());
            //first指向的节点出圈
            first = first.getNext();
            helper.setNext(first);
        }
        System.out.printf("最后留在圈里的节点%d\n", first.getNo());
    }
}
//创建Kid类,表示节点
class Kid{
    private int no;//小孩编号
    private Kid next;//表示下一个节点

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

    public int getNo() {
        return no;
    }

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

    public Kid getNext() {
        return next;
    }

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据结构——>单向环形链表 的相关文章

随机推荐

  • lowbit

    lowbit用来计算二进制数 从右往左数第一个1与其后面的0组成的数 int lowbit int x return x x x 12 1100 lowbit 12 100 4 7 111 lowbit 7 1 1
  • Flutter优秀第三方常用框架

    名称 GitHub地址 下拉刷新上拉加载 EasyRefresh 下拉刷新上拉加载 PullToRefresh SharedPreferences shared preferences 中国城市选择器 city picker 设备信息 de
  • 硬盘存储知识

    存储知识 内存和外存 硬盘 1 物理磁盘类型 硬盘分为 机械硬盘 HDD 和固态硬盘 SSD 注意 买硬盘的时候要注意转速 机械硬盘是以下三种 物理磁盘类型 SATA盘 物理磁盘类型 SAS盘 物理磁盘类型 NL SAS盘 固态硬盘 物理磁
  • 微信小程序期末大作业 中草药小程序 药海拾遗

    微信小程序期末大作业 中草药小程序 药海拾遗 小程序详情如下 下载链接在文末 学习社区可以自己添加内容 点我下载资源 https download csdn net download weixin 43474701 59675965
  • 【Struts2六】ui标签之form标签及数据回显

    ui标签 用在jsp页面用于回显数据的标签 这些标签是由框架定义的 用来替代原生的标签 ui标签有
  • WPF编程,Live Charts使用说明(11)——基本折线图

    后台 using System using System Windows Controls using System Windows Media using LiveCharts using LiveCharts Wpf namespace
  • Spring整合Druid

    Druid是Java语言中最好的数据库连接池 Druid能够提供强大的监控和扩展功能 Druid是阿里巴巴开源平台上的一个项目 整个项目由数据库连接池 插件框架和SQL解析器组成 该项目主要是为了扩展JDBC的一些限制 可以让程序员实现一些
  • 厉害了|十分钟掌握python3语言特性

    看了王垠的 如何掌握所有程序语言 感触甚深 如果说程序语言有其通用规律的话 那就是语言特性 也就是这些语言的通用概念 这些概念的具体语法的形式可能都不一样 但是所内涵的功能是一致的 比如英语中的bird和汉语中鸟 其实指的都是同一种事物 关
  • python自动生成电子邮箱'@hotmail.com', '@msn.com', '@yahoo.com', '@gmail.com', '@aim.com', '@aol.com', '@mail

    def getAutoEmail self 自动生成电子邮箱 Fist email join random sample string ascii letters string digits 9 last emailList hotmail
  • 使用Docker及Docker-compose部署SpringBoot项目

    1 环境准备 Windows下安装Docker需要WSL2及Hyper v Windows家庭版没有 Linux下安装Docker 参考官方文档 Install Docker Engine Docker Documentation 根据自己
  • Poi实现Excel导出

    Poi实现Excel导出 Appache Poi提供了HSSFWorkbook操作2003版本的Excel文件 XSSFWorkbook操作2007版Excel文件 简单的具体实现在网上有很多案例可以参考学习 我就不写入门案例了 下面我会将
  • AutoML系列

    本文是对 Neural Architecture Search A Survey 的翻译 这篇Paper 很好的总结分析了 NAS 这一领域的研究进展 摘要 在过去几年中 深度学习在各种任务上 例如图像识别 语音识别和机器翻译 取得了显著进
  • 利用javascript的算术运算符获取一个数字的每位数字

  • element tree 树形控件

    组件 Element 地址 http element eleme io zh CN component tree Tree树形控件
  • 【VAR模型

    向量自回归 VAR 是一种随机过程模型 用于捕获多个时间序列之间的线性相互依赖性 VAR 模型通过允许多个进化变量来概括单变量自回归模型 AR 模型 VAR 中的所有变量都以相同的方式进入模型 每个变量都有一个方程式 根据其自身的滞后值 其
  • IBM MQ 故障诊断(一)

    说明 本文主要是针对运维人员的手册 前面部分主要是应用三板斧的方式 后面的步骤可能会发散和具体深入一些 不过也不是严格的划分 读者就当看一遍杂文的方式来看待此文吧 一 队列管理器的启停 QMGR的启停是故障诊断中遇到最多的需求之一 启动队列
  • 【C语言】可变参数列表

    文章目录 前言 一 可变参数列表是什么 二 怎么用可变参数列表 三 对于宏的深度剖析 隐式类型转换 对两个函数的重新认知 总结 前言 可变参数列表 使用起来像是数组 学习过函数栈帧的话可以发现实际上他也就是在栈区定义的一块空间当中连续访问
  • 无服务器编程语言,腾讯云之无服务器云函数运行golang程序-Go语言中文社区

    使用腾讯的 无服务器云函数启动了一个服务 用golang代码生成以太坊的私钥跟地址 genEthAddr png 无服务器云函数是什么 腾讯云的无服务器云函数 跟 aws lambda类似 把一段代码放到云函数服务器上 设定好访问路径 就可
  • 高等代数 多项式环(第7章)5* 结式与域

    一 结式 1 概念 2 结式与公共复根 1 多项式存在公共复根的判定 定理1 设 f x a
  • 数据结构——>单向环形链表

    单向环形链表 一 单向环形链表应用场景 二 单向环形链表介绍 三 单向环形链表代码实现 1 代码实现思路 2 代码实现 一 单向环形链表应用场景 提起单向环形链表 就不得不说约瑟夫问题 约瑟夫环 什么事约瑟夫问题呢 1 约瑟夫问题 有时也称