文章目录
- 1 单循环链表
- 2 约瑟夫问题
- 3 代码实现
1 单循环链表 单向循环链表就是链表的尾节点的next指向链表的头结点,这样整个链表就形成了一个环形结构.
文章图片
单向循环链表的著名的应用场景就是解决约瑟夫问题(Josephu)
2 约瑟夫问题 osephu(约瑟夫、约瑟夫环) 问题
Josephu 问题为:设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
【数据结构与算法|4 单循环链表解决约瑟夫问题】思路:
用一个不带头结点的循环链表来处理Josephu 问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束
3 代码实现
package LinkList;
/**
* 该程序是用单向循环链表解决约瑟夫问题
* Josephu问题为:设编号为1,2,… n的n个人围坐一圈,
* 约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,
* 它的下一位又从1开始报数,数到m的那个人又出列,依次类推,
* 直到所有人出列为止,由此产生一个出队编号的序列。
*/
public class Josepfu {
public static void main(String[] args) {
jesepfuFunc(5,2,1);
}/**
*
* @param num 链表节点的数量
* @param start 从哪个位置开始
* @param range 隔几个节点抽一个
*/
public static void jesepfuFunc(int num, int start,int range){
CircleSingleLinkedList list = new CircleSingleLinkedList();
list.addNode(num);
list.show();
list.setFirst(start);
Node node = null;
System.out.println("退出的编号为: ");
//开始抽取数据,直到链表为空为止
while (!list.isEmpty()){
node = list.del(range);
System.out.print(node.getNo() + " ");
}
System.out.println();
}
}class CircleSingleLinkedList {private Node first = null;
/**
* 判断数组是否为空
* @return
*/
public boolean isEmpty(){
return first == null;
}/**
* 设置first 的位置
* @param index
*/
public void setFirst(int index){
if(index < 0 || index > getCount() || index == 1){
return ;
}for (int i = 1;
i < index;
i++) {
first = first.getNext();
}
}/**
* 增加num个node
* 编号从1 到 num
*
* @param num
*/
public void addNode(int num) {
if (num < 1) {
System.out.println("num 的值不正确");
return;
}Node temp = null;
for (int i = 1;
i <= num;
i++){
Node node = new Node(i);
if (i == 1){ //处理第一个节点
first = node;
node.setNext(node);
//节点自己指向自己
temp = node;
}else{
/**
* node节点的下一个节点指向first,因为插入之后node节点讲师最后的
* 原来链表的next指向node
* temp指向node
*/
node.setNext(first);
temp.setNext(node);
temp = node;
}
}
}/**
* 求链表节点的数量
* @return
*/
public int getCount(){
if (first == null){
return 0;
}
Node temp = first;
int count= 0;
while (true){
count++;
if (temp.getNext() == first){
break;
}
temp = temp.getNext();
}
return count;
}/**
*
* 返回链表的尾结点
* @return
*/
public Node getTail(){
if (first == null){
System.out.println("没有数据");
return null;
}
Node temp = first;
while (true){
if (temp.getNext() == first){
break;
}
temp = temp.getNext();
}
return temp;
}/**
* 删除指定位置的节点,并返回
* @param index
* @return
*/
public Node del(int index){
if(index < 1 || getCount() == 0){
System.out.println("index 的值不正确");
return null;
}
boolean flat = false;
//只有
if (getCount() == 1)
flat = true;
Node temp = first;
if (index == 1){ //删除第一个节点的情况
Node tail = getTail();
first = temp.getNext();
tail.setNext(first);
}else {//其它情况
for (int i = 1;
i < index;
i++) {
first = temp;
temp = temp.getNext();
}
first.setNext(temp.getNext());
first = first.getNext();
}//当链表只有一个节点的情况,需要把frist指向null
if (flat)
first = null;
return temp;
}/**
* 显示链表
*/
public void show(){
if (first == null){
System.out.println("没有数据");
return;
}
Node temp = first;
System.out.print("[ ");
while (true){
System.out.printf("%d ",temp.getNo());
if (temp.getNext() == first){
break;
}
temp = temp.getNext();
}
System.out.println(" ]");
}} class Node {
private int no;
//人的编号
private Node next;
//指向下一个节点public Node(int no) {
this.no = no;
}public int getNo() {
return no;
}public void setNo(int no) {
this.no = no;
}public Node getNext() {
return next;
}public void setNext(Node next) {
this.next = next;
}
}
推荐阅读
- java|JAVA中方法重写与重载的区别
- 数据结构|数据结构(循环链表解决约瑟夫问题)
- C语言|C语言求水仙花数
- C语言|C语言求输入字符的字母和数字个数
- Java|Nginx多个域名配置ssl证书出错解决方案
- 关于滑动时间窗口算法
- 编程语言|末日来临,你的编程语言能干嘛( | 每日趣闻)
- leetcode|46. 全排列
- 菜鸟刷题|蓝桥杯每日一题——最大字段和问题(动态规划)