Josephu
Josephu 问题为:设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
实现思路:
创建环形链表:
1.添加节点:
第一个节点时,也需要形成一个环形。
遍历到最后一个节点将其添加,并且将其与第一个节点相连
怎么确定最后一个节点和第一节点。
第一个节点:可以一个first节点固定费不移动(跟单链表的头节点一样)
最后一个节点:Node.next == first,若相等则为最后一个节点
2.遍历节点
从第K个节点开始遍历,需要两个辅助指针一开始都指向第K个节点,一个指针不移动的作为遍历结束的标记,另一个则是进行遍历。
3.删除节点(提取节点出来排序)
从第k个节点开始数,每第m个将其提取出来排队,只要最后一个节点,并且将最后一个节点直接排在最后
遍历链表:
1.从第K个节点开始,遍历出第K个节点。
2.然每数m个节点,将其提取出来,而且在链表中删除提取出去的节点。
3.(红色线是,将节点删除之后的)问题来了:我怎么将单向链表,上一个节点的next,连接到下一个节点呢。
(若是双向就可以利用pre 与 next 实行自我删除,单向链表:找到需要删除节点的上一个节点 )
可以利用两个辅助变量来同时进行遍历, temp1: 当数完m个节点,temp1所指的节点是要提取出来排队的, 则
Node newNode = temp2;(先将节点保留下来排队)
此时好保留 newNode .next == temp2.next
temp1.next = temp2.next ;(就可以将节点删除)
temp2 =temp2.next;
temp1 = temp1.next;
取到最两个:
取倒最后一个时,也要将其取出来此次排序;最后环形链表为空
将取出的节点依次排序成一条单链表:
代码
public class Josepfu {
public static void main(String[] args) {
//创建节点
Boy boy1 = new Boy(1, "路飞小同学");
Boy boy2 = new Boy(2, "娜美小同学");
Boy boy3 = new Boy(3, "索隆小同学");
Boy boy4 = new Boy(4, "香吉士小同学");
Boy boy5 = new Boy(5, "罗宾小同学");
//创建环形单向链表
CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
circleSingleLinkedList.add(boy5);
circleSingleLinkedList.add(boy4);
circleSingleLinkedList.add(boy3);
circleSingleLinkedList.add(boy2);
circleSingleLinkedList.add(boy1);
//创建单链表进行排队
SingleLinkedList singleLinkedList = circleSingleLinkedList.singleLinkedList;
//显示链表
circleSingleLinkedList.show(3, "索隆小同学");
circleSingleLinkedList.del(3, "索隆小同学", 2);
circleSingleLinkedList.show(3, "索隆小同学");
singleLinkedList.list();
}
}
//创建环形的单向链表
class CircleSingleLinkedList {
//创建一个first节点,作为链表的标计
Boy firstBoy = null;
//添加节点,构建环形的链表
//遍历需要一个辅助指针temp
Boy temp =null;
//创建单链表进行排队
SingleLinkedList singleLinkedList = new SingleLinkedList();
public void add(Boy boyNode) {
//遍历需要一个辅助指针temp
while(true) {
if(firstBoy == null) {
firstBoy=boyNode;
firstBoy.setNxetBoy(firstBoy); // 说明没有第一个节点 ,第一个节点需要形成环形
temp = firstBoy;
//System.out.println("temp.getNxetBoy()"+temp.getNxetBoy());
break;
}
//若不是第一个节点,则遍历到最后一个节点
else if(temp.getNxetBoy() == firstBoy ) {
temp.setNxetBoy(boyNode);
boyNode.setNxetBoy(firstBoy);
break;
}
temp =temp.getNxetBoy();
}
}
//遍历显示链表 ,送 第K个节点(no nameString 的节点)开始显示链表
public void show(int no , String nameString) {
//遍历需要一个辅助指针temp
Boy temp = firstBoy;
//找出 第K个节点 ,开始显示链表
if(firstBoy == null ) {System.out.println("该链表为空");return;}
while(temp != temp.getNxetBoy()) {
//System.out.println(" "+temp);
if(temp.getNo() == no && temp.getNameString() == nameString) {break;}
temp = temp.getNxetBoy();
}
//已经找到第K个节点,开始显示链表 ,此时重新起个头节点,作为遍历结束的标志
Boy fBoy = temp;
do {
if(temp==null) {break;}
System.out.println(temp);
temp = temp.getNxetBoy();
}while(temp != fBoy );
}
//环形链表的删除
public void del(int no , String nameString,int m) {
//遍历需要一个辅助指针temp
Boy temp = firstBoy;
//System.out.println("firstBoy\t" + firstBoy);
//System.out.println("temp\t" + temp);
//找出 第K个节点 ,开始显示链表
while(true) {
if(temp.getNo() == no && temp.getNameString() == nameString) {break;}
temp = temp.getNxetBoy();
}
Boy temp1 = temp; //temp2 移动m次后 指向的节点是需要删除 和 提取 出来的
Boy temp2 = temp.getNxetBoy();
while(true) {
//找到第K个节点开始,数m个节点
if(temp1 == temp2 ) {break;}
for(int i = 0 ; i <m -1; i++ ) {
temp2 = temp2.getNxetBoy();
temp1 = temp1.getNxetBoy();
}
//节点移动m次
Boy savaBoy = temp2;
temp1.setNxetBoy(temp2.getNxetBoy());
temp2 = temp2.getNxetBoy();
//System.out.println("temp2" + temp2);
//System.out.println("temp1" + temp1);
savaBoy.setNxetBoy(null);
//System.out.println("savaboyNode"+ savaBoy);
singleLinkedList.add(savaBoy);
}
//此时链表只剩下一个节点
firstBoy=null;
temp2 .setNxetBoy(null);
singleLinkedList.add(temp2);
//singleLinkedList.list();
}
}
//创建节点类
public class Boy{
private int no;
private String nameString;
private Boy nxetBoy;
public Boy(int no , String nameString) {
this.nameString = nameString;
this.no = no;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getNameString() {
return nameString;
}
public void setNameString(String nameString) {
this.nameString = nameString;
}
public Boy getNxetBoy() {
return nxetBoy;
}
public void setNxetBoy(Boy nxetBoy) {
this.nxetBoy = nxetBoy;
}
@Override
public String toString() {
return "Boy [no=" + no + ", nameString=" + nameString +"]";
}
}
public class SingleLinkedList {
//先初始化一个头节点, 头节点不要动, 不存放具体的数据
private Boy head = new Boy(0, "");
//返回头节点
public Boy getHead() {
return head;
}
/*
//添加节点到单向链表
//思路,当不考虑编号顺序时
//1. 找到当前链表的最后节点
//2. 将最后这个节点的next 指向 新的节点
*/
public void add (Boy heroNode) {
//因为head节点不能动,因此我们需要一个辅助遍历 temp
Boy temp = head;
boolean flag = false;
//遍历链表,找到最后
while(true) {
//找到链表的最后
if(temp.getNxetBoy() == null) { break; }
//if (temp.getNo() == heroNode.getNo()) { flag=true; break; } //说明该元素 链表 已经存在
//如果没有找到最后, 将将temp后移
temp = temp.getNxetBoy();
}
if(flag) {System.out.printf("该元素%s已经存在,添加失败",temp.getNxetBoy()); System.out.println();}
else {
//当退出while循环时,temp就指向了链表的最后
//将最后这个节点的next 指向 新的节点
temp.setNxetBoy(heroNode);
}
}
//显示单链表
public void list() {
//判断链表是否为空
if(head.getNxetBoy() == null){ System.out.println("该链表为空"); return; }
//由于头节点是不能移动的,需要用到一个遍历变量 来 遍历 显示
Boy temp = head.getNxetBoy(); //显示遍历 ,不需要对头节点进行显示,即temp 被赋值为 头节点的 next (temp是指向 next)
while(true) {
if(temp == null ) {break;} //判断遍历到最后
//如果没有到最后,先显示本节点的消息 , 继续向后移
System.out.println("single"+temp);
temp=temp.getNxetBoy();
}
}
}
运行结果: