数三退一问题:有500个小孩手拉手围成一圈,从1开始数,数3小孩退出圈外,直到最后一位小孩,求最后一位小孩的序号是?
下面给出两个方法,第一种面向过程:
public class Test1
{
//数3退1;每数到3就退出一个人
public static void main(String[] args)
{
boolean[] child = new boolean[500];
Arrays.fill(child , true);//初始化
//数3退1
int leftNum = child.length;//数组中剩余的小孩数目
int countNum = 0;//用于记录当前小孩123编号
int index = 0;//记录小孩原始编号
while(leftNum > 1)//只要数组中的小孩数目多于一个继续数3退1
{
if(child[index])
{
countNum ++;
if(countNum == 3)
{
countNum = 0;
child[index] = false;
leftNum --;
}
}
index ++;
if(index == child.length)
index = 0;
}
for (int i = 0; i < child.length; i++)
{
if(child[i])
System.out.println("剩余的小孩的编号为:" + i);
}
/*for (int i = 0; i < child.length; i++)
{
System.out.print(child[i] + " ");
if( (i + 1) % 10 == 0 )
System.out.println();
}*/
}
}
第二张方式:面向对象:
public class Test2
{
public static void main(String[] args)
{
//数3退1;每数到3就退出一个,面向对象的方法
//面向对象,考虑问题中出现的名词:小孩类,圈类
KidCircle kc = new KidCircle(500);
Kid k = kc.first;//先取出kc的第一个孩子
int countNum = 0;//用来数数,数到3退出
while(kc.count > 1)
{
countNum ++;
if(countNum == 3)
{
countNum = 0;
kc.delete(k);
}
k = k.right;//因为是圆环,所以,每次取k孩子的右孩子
}
System.out.println("剩余的小孩的编号为:" + kc.first.id);
}
}
//小孩类
class Kid
{
int id;//小孩原始编号
/*
* 每个小孩都有左小孩和右相邻小孩
*/
Kid left;
Kid right;
}
//圈类
class KidCircle
{
int count = 0;//小孩编号
Kid first;//圈中第一个小孩
Kid last;//圈中最后一个小孩
/*
* 写完成员变量以后首先完成其构造方法
*/
public KidCircle(int n)//构造方法一般用来初始化
{
//构造n个小孩的圈
for (int i = 0; i < n; i++)
{
add();
}
}
//向圈中添加小孩
void add()
{
Kid k = new Kid();
k.id = count;
if(count <= 0)//当前圈中没有小孩
{
first = k;
last = k;
k.left = k;
k.right = k;
}
else //当前圈中有小孩情况
{
last.right = k;
k.left = last;
k.right = first;
first.left = k;
last = k;
}
count ++;
}
//向圈中删除小孩
void delete(Kid 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 --;
}
}