简要:
1 丢手绢问题:这是小时候经常玩的游戏,一群小朋友围到一起,形成一个圈。老师唱歌,小朋友们同时丢手绢,歌曲暂停时,目前拿到手绢的小朋友需要表演一个节目。依次循环下去。
2 而约瑟夫问题与之类似,由一群元素构成的环形链表,首先由某个元素开始报数,报到K时的那个元素需要出圈,然后又由下一个元素开始报数,直到全部的元素出圈时才结束。
下面代码相关的注意点:
相关术语 | 解释 |
---|---|
first | 表示的意思是头结点 |
last | 表示的意思是为节点 |
num | 表示的意识是添加元素的数量 |
startNo | 表示的意思是开始时从哪里数数 |
count | 表示的意思是数几下 |
startNum | 表示的意思是开始的时候有 多少元素 |
m | 表示的意思是报的数是多少 |
另外:
添加元素是首先first自我成环然后添加元素时改变元素指针的指向。
如:
1 开始环中只有一个元素时:
2 添加一个元素时:(这里需要用到一个辅助节点curboy,目的是为了添加元素和遍历时更加方便)
3 出圈的时候:(需要用到两个辅助节点,一个是first,另一个是last,first需要指向需要出圈的元素,last应该在first的后一位。)
- 未出圈之前:如
- 假如boy2准备出圈此时的情况:(first需要移动到boy2处,last也需要向相同的方向移动相同的位数)
- boy2出圈后(一个元素最多指向另一个元素):
- 最终:
first = last
相关代码:
public class Test {
public static void main(String[] args){
CircleLinkedlist c =new CircleLinkedlist();
c.add(10);
System.out.println("遍历后的元素");
c.list();
c.count(2,3,10);
}
}
//创造一个环形链表。
class CircleLinkedlist{
Boy first = null;
Boy last = null;
//在里面有很多进行链表的操作。
//定义一个添加元素的方法。
public void add(int num){
if(num<1){
System.out.println("num的数值不准确");
}
else{
Boy curBoy = null; //定义一个辅助节点。
for(int i=1;i<=num;i++){
//定义一个男生节点。
Boy boy = new Boy(i);
//在这个循环语句内要形成一个环。所以首节点需要形成一个环。
if(i==1){
//自我形成一个环。
first =boy;
first.next=first;
curBoy = first;
}
else{
curBoy.next=boy;
boy.next = first;
curBoy = boy;
}
}//取最后一次环就行了!!
}
}
//根据用户的输入来判断男孩输出的顺序。
//startNo表示的意思是刚开始从哪里开始数数。
//count表示的意思是数几下。
//startNum表示的意思是刚开始有几个男孩在里面。
public void count(int startNo,int count,int startNum){
last = first;
//先对数据进行校验。
if(first == null||startNo == 0||count > startNum||startNo > startNum){
System.out.println("参数输入有误");
}
else{
//首先让last指针指向最后一个节点
while(true){
if(last.next==first){
break;
}
else{
last=last.next;
}
}
//,first和last节点分别移动m-1次。此时的first指向开始报数的男孩处。
for(int i = 1;i<startNo;i++){
first = first.next;
last = last.next;
}
//出圈。
while(true){
//最终两者指向同一个节点。
if(first==last){ //说明圈中只有一个节点。
break;
}
else{
//得出指向报m次处的男孩处。
for(int i=0;i<count-1;i++){
first = first.next;
last = last.next;
}
//输出需要出圈小孩的编号和名字。
System.out.println("出圈小孩的编号:"+first.no);
//实现小孩的出圈操作,需要删除出圈的节点。
last.next=null;
//获得删除节点的后一个节点,并将last与其连接。
Boy temp = first.next;
last.next = temp;
//设置first.next的值为null
first.next = null; //取消了一根head指向下一个元素的指针。
startNum--; //循环一次,人数减少一个。
//移动first指针,移动一位,并指向temp。
first = temp;
}
}
}
}
//遍历当前的环形链表。。
public void list(){
Boy curBoy = null;
if(first.next==null){
System.out.println("环形链表元素为空,无法遍历");
}
else {
curBoy = first; //因为直接用boy不好进行遍历,所以只能寻找一个辅助节点来帮忙。
while(true){
if(curBoy.next==first){
break;
}
else {
System.out.println("no = "+curBoy.no);
curBoy=curBoy.next;
}
}
}
}
}
//创造一个Boy类表示一个节点。
class Boy {
int no;
Boy next;
public Boy(int no ){
this.no = no;
}
}