数据结构与算法: 约瑟夫问题(丢手绢)
Posted android超级兵
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法: 约瑟夫问题(丢手绢)相关的知识,希望对你有一定的参考价值。
数据结构与算法: 约瑟夫(丢手绢)问题(单向链表,双向链表解决)
Tips: 采用java语言, 关注博主,底部附有完整代码
采用到的知识点:
- 单向环形链表
- 双向环形链表
- 单向 / 双向 环形链表出圈
流程效果图:
单向环形链表 | 双向环形链表 |
---|---|
什么是约瑟夫问题
约瑟夫问题好像小时候玩的丢手绢一样
先来说一下规则, 默认从第一个小朋友开始数,在第n个小朋友过后开始寻手绢, 第n个小朋友每k个人就丢下手绢,然后这个小朋友出圈
直到圈中只剩一人才结束
假设5个小朋友围坐一圈来丢手绢
例如这样:
在第2个小朋友开始丢手绢
那么就是元素三出圈
接着每2个元素依次出圈
tips: 这里单向环形链表和双向环形链表思路有所不同
, 所以结果也有所不同!
- 单向环形链表 先创建好5个元素 然后从第n个孩子开始,每k次出圈 , (第一次从第n个孩子数也
会出圈
) - 双向环形链表 直接调用一个方法,并且传入需要“丢手绢”的元素,在开始出圈 (第一次从第n个孩子数也
不会出圈
)
单向环形链表
自定义链表 AnnularLinkedList.java:
public class AnnularLinkedList
//头节点
private HeroNode3 head;
/**
* get头节点
* @return 头节点
*/
public HeroNode3 getHead()
return head;
/**
* 创建元素
* @param sum 需要创建的个数
*/
public void createHeroNode(int sum)
if (sum < 1)
System.out.println("请正确输入创建个数");
return;
HeroNode3 temp = null;
for (int i = 1; i <= sum; i++)
HeroNode3 node3 = new HeroNode3(i, "张三" + i);
if (i == 1)
//记录第一个位置
head = node3;
//辅助变量,记录第一个位置
temp = node3;
//第一个元素指向自己,构建成环形
head.next = head;
//指向新的元素
temp.next = node3;
//新的元素指向第一个节点
node3.next = head;
//temp后移
temp = temp.next;
/**
* @param start 从元素几开始数
* @param number 每数几下出圈
*/
public void count(int start, int number)
//获取链表长度
int sum = size();
System.out.println("sum为:" + start + "\\t" + number + "\\t" + sum);
//start < 1 不能从 < 1 开始的数 数
//sum < start 链表总数不能 < 开始的位置
if (start < 1 || sum < start)
System.out.println("请正确输入");
return;
HeroNode3 help = head;
//将 help 移动到 head 后面
while (help.next != head)
help = help.next;
//从第start位置开始循环
for (int i = 0; i < start - 1; i++)
head = head.next;
help = help.next;
//如果heap != head 那么就继续循环
//当help == head 时,则退出循环
while (help != head)
//每number下出圈
for (int i = 0; i < number - 1; i++)
head = head.next;
help = help.next;
//此时head则为要出圈的元素
System.out.println("要出圈的勇士id为:" + head.id);
//出圈操作
head = head.next;
help.next = head;
//最终help = head 那么help/head就是最后一个在圈中的元素
System.out.println("留在圈中的勇士id为:" + help.id);
/**
* 计算链表长度
*/
public int size()
int length = 1;
HeroNode3 temp = head;
while (temp.next != head)
length++;
temp = temp.next;
return length;
/**
* 输出链表所有数据
*/
public void show()
if (head == null)
System.out.println("链表为null,不能打印");
HeroNode3 temp = head;
while (temp.next != null)
System.out.println("show:" + temp);
//当最后一个元素 = 第一个元素时,表示链表当前在最后一个元素,停止循环
if (temp.next == head)
break;
//temp后移
temp = temp.next;
HeroNode3.java:
public class HeroNode3
int id;
String name;
HeroNode3 next;
public HeroNode3(int id, String name)
this.id = id;
this.name = name;
@Override
public String toString()
return "HeroNode3" +
"id=" + id +
", name='" + name + '\\'' +
'';
调用:
AnnularLinkedList linkedList = new AnnularLinkedList();
linkedList.createHeroNode(5);
System.out.println("测试的值为:"+linkedList.getHead().next.next.next.next.next.next);
linkedList.show();
linkedList.count(2, 2);
来看看运行结果:
如果对单向链表或者约瑟夫问题陌生的,项目中还有我画的2张详细流程图 那就下载看看吧
双向环形链表
AnnularDoubleLinkedList.java
/**
* @author: android 超级兵
* @create: 2022-05-05 11:53
* TODO 约瑟夫问题 双向链表
**/
public class AnnularDoubleLinkedList
public AnnularHeroNode headNode = new AnnularHeroNode();
/**
* TODO 约瑟夫问题 双向链表
*
* @param n 从第几个开始 (0 - list.size())
* @param k 每次走几个 (k < list.size())
* @param list 元素
*/
public void josephusProblem(int n, int k, List<AnnularHeroNode> list)
if (list.size() < n)
System.out.printf("当前元素一共%d个,无法从第%d个元素开始", list.size(), n);
return;
headNode = list.get(0);
// TODO 先将每个元素链接起来
for (int i = 0; i < list.size(); i++)
AnnularHeroNode node = list.get(i);
// 下一个元素
AnnularHeroNode nextNode;
if (i != list.size() - 1)
nextNode = list.get(i + 1);
else // 最后一个节点
node.setLastNode(true);
nextNode = list.get(0);
node.next = nextNode;
nextNode.pre = node;
System.out.println("测试是否成功:");
System.out.println(headNode.next.next.next.next);
System.out.println(headNode.pre.pre.pre.pre);
System.out.printf("最后一个节点为:%s\\n", headNode.pre);
System.out.printf("第一个节点为:%s\\n", headNode);
show();
// 从第几个元素开始
AnnularHeroNode tempNode = list.get(n);
System.out.printf("从%s开始\\n", tempNode);
System.out.println();
AnnularHeroNode currentNode = null;
// 当前节点上一个节点
AnnularHeroNode currentPreNode = null;
while (true)
// 每次过n个人
for (int i = 0; i < k; i++)
currentNode = tempNode.next;
tempNode = tempNode.next;
System.out.printf("currentNode:%s\\n", currentNode);
// 移除当前选中的
currentNode.pre.next = currentNode.next;
currentNode.next.pre = currentNode.pre;
// 当前位置的最后一个位置
currentPreNode = currentNode.pre;
// 如果当前位置后一个位置 = 当前位置 说明只有一个,则退出循环
if (currentPreNode == currentNode)
break;
System.out.printf("最终留在圈中的是 %s\\n", currentNode);
private void show()
System.out.println("\\n遍历: ======= start =======");
AnnularHeroNode tempHeadNode = headNode;
while (true)
System.out.println(tempHeadNode);
if (tempHeadNode.isLastNode())
break;
tempHeadNode = tempHeadNode.next;
System.out.println("遍历: ======= end =======\\n");
AnnularHeroNode.java
/**
* @author: android 超级兵
* @create: 2022-05-05 11:54
* TODO
**/
public class AnnularHeroNode
private final int id;
private final String name;
private final String title;
// 是否是最后一个节点
private boolean isLastNode;
// 下一个节点
public AnnularHeroNode next;
// 上一个节点
public AnnularHeroNode pre;
public AnnularHeroNode()
id = 0;
name = "";
title = "";
public int getId()
return id;
public AnnularHeroNode(int id, String name, String title)
this.id = id;
this.name = name;
this.title = title;
public boolean isLastNode()
return isLastNode;
public void setLastNode(boolean lastNode)
isLastNode = lastNode;
@Override
public String toString()
return "AnnularHeroNode" +
"id=" + id +
", name='" + name + '\\'' +
", title='" + title + '\\'' +
", isLastNode='" + isLastNode + '\\'' +
'';
使用:
package a20220505环形双向列表;
import java.util.ArrayList;
/**
* @author: android 超级兵
* @create: 2022-05-05 12:07
* TODO 约瑟夫问题 双向链表解决
**/
public class Client
public static void main(String[] args)
AnnularDoubleLinkedList annularDoubleLinkedList = new AnnularDoubleLinkedList();
AnnularHeroNode node0 = new AnnularHeroNode(0, "史进", "九纹龙");
AnnularHeroNode node1 = new AnnularHeroNode(1, "鲁智深", "花和尚");
AnnularHeroNode node2 = new AnnularHeroNode(2, "林冲", "豹子头");
AnnularHeroNode node3 = new AnnularHeroNode(3, "宋万", "云里金刚");
AnnularHeroNode node4 = new AnnularHeroNode(4, "吴用", "智多星");
ArrayList<AnnularHeroNode> nodeArrayList = new ArrayList<>();
nodeArrayList.add(node0);
nodeArrayList.add(node1);
nodeArrayList.add(node2);
nodeArrayList.add(node3);
nodeArrayList.add(node4);
// 23401
annularDoubleLinkedList.josephusProblem(1, 2, nodeArrayList);
原创不易,您的点赞与关注就是对我最大的支持!
以上是关于数据结构与算法: 约瑟夫问题(丢手绢)的主要内容,如果未能解决你的问题,请参考以下文章