补充:头节点的地址和链表的创建是以成员对象的方式存在于另一个对象之中,也就是环形队列的对象,first 和helper移动到开始位置是数开始位置减1次比如1到3实际只跳转了2次,
由于题目要求从第一个人开始报数所以数也是跳转count-1次,
节点的创建有三个步骤,
1.最后一个.next = 当前
2.当前.next = first
3.最后一个 = 当前
这里的first和最后一个都是用来方便操作的临时地址型索引,first始终指向第一个节点,last(helper)指向最后一个节点
环形链接表和单链表唯一区别就在于最后指的不是null而是开头,构建一个环形链接表需要两个temp对象,分别叫helper,first,helper开始时等于first,first永远指向第一个,helper的作用是用循环创建节点时滞后于当前次数的循环一个节点好把前一个节点的next挂上当前的地址,在完成增加节点的地址链接后再跳转到下一个,而first是用于每加一个节点把他的next连上first,包括只有一个节点的时候,也就是first和help是指向同一个时也要保证first.next指向自己,
遍历就不停跳转打印直到节点.next ==first停止
创建和遍历完成就到了约瑟夫问题,
约瑟夫问题的实现也是需要两个temp对象一个在前一个在后
这时helper在后first在前
约瑟夫问题有几个参数,
1.从几开始
2.一次循环数几下
3.操作的链表有几个节点
排除开始小于1,空链表,开始节点的节点数大于总的节点数量
挨个完成,首先要让help和first一个在前一个在后,通常是help在first后一个,因为要让元素出圈需要让n-1和n+1交换链接达到删除的效果,在删除前得先打印要删除的节点,循环处理打印几次就得到出圈顺序了,
总之初始化helper遍历到help.next == first位置,
其次是把first和helper同时移动到开始位置,如果移动的for循环i=0,就i<开始数-1,是1就i<开始数
上面是准备工作,
下面开始写while循环开始数数然后打印删除,直到链表只剩first一个,也就是first.next=first或者first=helper
每次循环的数几下操作和把first和helper同时移动到开始位置时的代码是一样的,区别在于数完后first等于当前循环要打印(删除)的节点,就先打印,然后把first往前移,把helper.next=first;进行删除
不停打印删除直到剩最后一个节点,就引用first单独打印一次,
package cyrclelink;
public class cyrclelink {
public static void main(String[] args) {
// TODO Auto-generated method stub
dian zuo = new dian();
zuo.add(5);
zuo.list();
zuo.count(1,2,5);//2,4,1,5,3
}
}
//创建环形链表显示链接表
class dian {
public jiedian first = new jiedian(-1);
public void add (int nums) {
if (nums <1) {
System.out.println("num值不正确");
return;
}
jiedian curspot = null;
for(int i = 1; i<=nums;i++) {
jiedian spot = new jiedian(i);
if(i== 1) {
first = spot;
first.next = first;
curspot = first;
}else {
curspot.next = spot;
//cur会滞后一个用来把前一个的next链接到当前的
spot.next= first;
curspot = spot;
}
}
}
public void list() {
if(first == null) {
System.out.println("链表是空的");
return;
}
jiedian curspot = first;
while(true) {
System.out.printf("节点的编号%d \n",curspot.no);
//说明他的下一个就是开头了
if(curspot.next == first) {
break;
}
curspot = curspot.next;
}
}
/**
*
* @param start,从几开始数
* @param count数几下
* @param nums最初有几个节点
*/
public void count (int start,int count,int nums) {
if(first == null|| start < 1|| start >nums) {
System.out.println("参数输入有误,请重新输入");
return;
}
jiedian helper = first;
while(true) {
if(helper.next == first){//指向最后一个节点
break;
}
helper = helper.next;
}
for(int i = 0;i<start-1;i++) {
first = first.next;
helper = helper.next;
}
System.out.println("约瑟夫公式等于------------------------------");
while(true) {
if(helper == first) {
break;
}
for(int j = 0;j<count-1;j++) {
first = first.next;
helper = helper.next;
}
System.out.printf("节点%d出圈\n",first.no);
first=first.next;
helper.next = first;
}
System.out.printf("最后节点编号%d \n",first.no);
}
}
class jiedian{
int no;
jiedian next;
public jiedian(int no) {
this.no = no;
}
@Override
public String toString() {
return "jiedian [no=" + no + "]";
}
}