-
问题描述
有n个人,编号为1~n,从第一个人开始报数,从1开始报,报到m的人会死掉,然后从第m+1个人开始,重复以上过程。在死了n-1个人后,问最后一个人的编号是?
不找规律,直接举例子,假设如下
- 开始位置是第1个人
- 每次查2个人
- 总共有9个人
指针的定义
定义两个指针(变量)
- first:用于记录要被干死的人
- prev:用于记录要被干死的前一个人,目的就是连接后续的链表
//要先建立一个单向环形链表,这里省略
Node first = head; (head就代表开始的位置)
Node prev = first;
while(true){
if(prev.next==first){//此时prev就指向first前一个位置
break;
}
prev=prev.next;
}
指针的移动
如图,此时first就是要干死的人。那么接下来要做的就是单向循环链表的踢出工作。
很显然,要删除first,就要将first前移,用prev直接连first。这样就将这个人干死了
first=first.next; //first前移
prev.next=first; //prev指向新的first
此时,first指向3号位置,由于3还没被查,所以下一次就是从3开始!查两个!注意了,第一次是从1开始查的,1同样也没被查,很显然这里是一个循环。
那么下一个被干死的就是4号,然后first移动到5号位置,那么被干死的就是6号,以此类推、、、
代码!代码!代码!来了,嘿嘿
/**该方法我是直接从我项目中粘的,有些内容不全,我会做出解释
*
* @param start 起始位置
* @param step 步长
* @param nums 队伍总人数
*/
void outOfRanks(int start, int step, int nums) {
//确保数据有效性,first==null时,就说明循环链表为空
if (first == null || start > nums || nums <= 0 || start <= 0) {
System.out.println("输入数据有误");
return;
}
//定义prev变量。
//first用于指向结点1
Child prev = first;
while (true) {
if (prev.next == first) {
break;
}
prev = prev.next;
}
//循环结束后,此时的prev就是first前一个结点
//根据输入的参数,确定起始位置
for (int i = 0; i < start - 1; i++) {
prev = prev.next;
first = first.next;
}
//每次循环都干死一个人,那么循环nums-1次,那就干死nums-1个人,剩下的那个就是活着的人
for (int i = 1; i < nums; i++) {
//当prev==first时,就剩一个结点了,自身结点next指向自己。退出循环
if (prev == first) {
break;
}
//开始查人,由于first自身也要查,那么prev和first都向前移动step-1个
for (int j = 0; j < step - 1; j++) {
first = first.next;
prev = prev.next;
}
System.out.println("第" + i + "个淘汰的是" + first);
//再将first前移一个位置,用于删除该节点,也就是把这人干死
first = first.next;
prev.next = first;
}
System.out.println("活着的是" + first);//这里类中要记得重写toString
}
完事!!!