链队列约瑟夫环c++代码_区区“约瑟夫环问题”也能成为加薪路上的绊脚石?

先赞后看,养成习惯!

5835b6fdd6457883346b1722f55f1284.png

最近闲来无事,翻看了一下之前面试后做的记录,发现当时的自己真是“菜的一批”啊(虽说现在也挺菜,但是多少还是有那么一点点进步的)。追忆一下当年有点跑题了哈哈哈,今天是想跟大家分享一下当年遇到的一道面试题:“约瑟夫环问题”。

多得不说,少得不唠,下面开始今天的分享。

fb711580a0041ae79ad6dd0614a18ab2.png

什么是约瑟夫环问题

大家知道什么是约瑟夫环吗?

各位读者是不是心里想着:“知道谁还看你在这废话。”然后悄悄地攥紧了拳头?别,各位大哥大姐千万别激动,给小弟点时间,让小弟为你排忧解难。

约瑟夫问题为:设编号为1,2,……n得n个人围坐一圈,约定编号为k(k大于等于1并且小于等于n)的人从1开始报数,数到m的那个人出列。它的下一位继续从1开始报数,数到m的人出列,依次类推,直到所有人都出列为止。

这就是著名的“约瑟夫环”问题,是不是还挺有趣的感觉(有趣个鬼不为了面试、加薪谁搞这东西)。

b2342a3176063a797926339a87246602.png

动手实现

我们可以通过单向环形链表来完成约瑟夫环问题。

第一步:构建单向环形链表

实现思路:让单向链表首尾相连从而实现环形链表(对单向链表不太了解的可以翻看一下之前的文章不再赘述)。

单向环形链表节点类:

public class Node {  /**   * 编号   */  public int no;  /**   * 指针域(指向下一个节点)   */  public Node next;  /**   * 构造方法   *    * @param no   */  public Node(int no) {    this.no = no;  }}

初始化单向环形链表类:

public class CircleSingleLinkedList {  // 创建一个first节点  private Node first;}

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

/** *  * @param nums 环形链表中有几个节点 */public void initCircleSingleLinkedList(int nums) {    if (nums < 1) {      throw new RuntimeException("入参有误!");    }    // 定义辅助变量    Node cur = null;    // 创建环形链表    for (int i = 1; i <= nums; i++) {      // 创建节点      Node node = new Node(i);      if (i == 1) {        // 初始化第一个节点。        first = node;        // 将该节点的指针域指向自己,构成环形。        first.next = first;        // 初始化辅助变量。        cur = first;      } else {        // 将辅助变量的指针域指向新节点。        cur.next = node;        // 链表首尾相连        node.next = first;        // 后移辅助变量        cur = node;      }    }}

以上代码就可以轻松地构建出一个单向环形链表,还是挺简单的吧!

第二步:编写出列方法

实现思路:

问题回顾:从k开始,移动m次。

1、准备两个变量,分别指向环形链表的首尾。

2、因为不一定是从编号1开始报数,所以需要先将第一步准备的两个变量移动到指定的位置(移动k次)。

3、循环m次,找到出列的编号,并将该节点删除。

4、重复第三步一直到环形链表中只剩下一个节点时结束。

代码:

/** * 计算出圈的顺序 * * @param startNo 表示从第几个节点开始数 * @param countNum 表示数几下 * @param nums 表示圈内最初有几个节点 */public void calculateOutNode(int startNo, int countNum, int nums) {    // 参数校验    if (first == null || startNo < 1 || countNum > nums) {      throw new RuntimeException("参数有误,请重新输入!");    }    // 创建辅助变量,并将helper指向链表尾部。    Node helper = first;    while (true) {      if (helper.next == first) {        break;      }      // 后移辅助变量      helper = helper.next;    }    // 报数前让first和helper移动到指定位置    for (int i = 0; i < startNo - 1; i++) {      first = first.next;      helper = helper.next;    }    // 开始出圈    while (true) {      if (helper == first) {        // 环形链表中只剩下一个节点了,结束循环。        break;      }      // 让first和helpe移动countNum次      for (int i = 1; i < countNum; i++) {        first = first.next;        helper = helper.next;      }      // first指向的节点就是需要出列的节点      System.out.println("编号为【" + first.no + "】的节点出列!");      // 将first后移,并且将helper(指向环形链表尾部的节点)指向改变后的first节点,从而实现删除出列的节点。      first = first.next;      helper.next = first;    }    System.out.println("最后留在环形链表中的节点编号是【" + first.no + "】!");}

通过以上代码可以轻松解决约瑟夫环问题。分分钟完成升职加薪,走向人生巅峰。

41a994f04b470f10d817a1240a24fe1c.gif

该吹的牛也吹了,今天的分享也该结束了。如果感觉文章写得还不错的,记得点赞、关注,多多鼓励鼓励哟!文章哪里写得有问题的话大家可以在评论区指出来,我会积极改正!

本文由编程小菜鸟原创,欢迎关注,带你一起长知识!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值