之前看过马老师的java视频,里面的数三退一的例子我认为非常经典,不仅非常锻炼逻辑思维能力,而且最后巧妙的使用了面向对象的思想构建双向链表另辟蹊径也很好的解决了这个问题,特此记录下来。
- 代码一:(普通版)
public class TestCount3 {
public static void main(String[] args) {
boolean[] f = new boolean[500]; //使用一个500长的布尔类型数组来表示哪些还在圈内,哪些不在
for(int i=0; i<f.length; i++)
f[i] = true; //一开始都置为true
int count = f.length; //初始化圈内还有多少人
int index = 0; //用来遍历数组下标的索引
int number = 0; //用来计数
while(count != 1) { //只要不还有一个以上的小朋友就继续计数
if(f[index] == true) { //查看其是否还在圈内
number ++; //计数加1
if(number == 3) { //当数到3时
number = 0; //计数归0
f[index] = false; //退出圈,置为false
count --; //圈内人数减一
}
}
index ++; //遍历下标加一
if(index == f.length) { //一旦数到第500个小朋友则重头继续数
index = 0;
}
}
//最后打印出仅剩的那个还存在圈内的小朋友编号(即其认仍为true)
for(int i=0; i<f.length; i++) {
if(f[i] == true) {
System.out.println(i);
}
}
}
}
- 代码二(面向对象版)
public class TestCount3Object {
public static void main(String[] args) {
KidCircle c = new KidCircle(500); //新建一个500个小孩的圆圈
int countNum = 0; //要数数的数字
KidNode k = c.first; //拿出圈内第一个小孩
while(c.count > 1) { //只要圈内还有一个小孩以上就继续执行
countNum ++; //数数加1
if(countNum == 3) { //每数到3
countNum = 0; //数字归零
c.delete(k); //删除小孩
}
k = k.right; //接着下一个小孩数数
}
System.out.println(c.first.id); //打印最后剩下的小孩id号码
}
}
//小孩围成的圆圈类
class KidCircle {
int count; //圈内总共有多少个小孩
KidNode first, last; //圈内第一个和最后一个小孩
KidCircle(int num) { //构建一个多大的圈
count = 0;
for(int i=0; i<num; i++)
add();
}
void add() { //每在尾部添加一个小孩方法
KidNode k = new KidNode(count);
if(count <= 0) {
last = k;
first = k;
k.left = k;
k.right = k;
} else {
k.left = last;
k.right = first;
last.right = k;
first.left = k;
last = k;
}
count ++;
}
void delete(KidNode k) { //每删除某一个小孩的方法
if(count <= 0) {
return;
} else if(count == 1) {
first = last = null;
} else {
k.left.right = k.right;
k.right.left = k.left;
if(k == first) {
first = k.right;
} else if(k == last) {
last = k.left;
}
}
count --;
}
}
//每个孩子节点类
class KidNode {
int id; //序号
KidNode left, right; //左右孩子
KidNode(int num) { //按序号构造函数
id = num;
left = null;
right = null;
}
}
结果:都得到435。