Java数三退一算法(代码注释)
一、以数组方式(设定一个500个元素的数组,并附初值为true,然后循环数数,每当数到第三个时给这个元素改变值为false,值到只剩最后一个元素为true为止)
- class Count3Quit
- {
- public static void main(String[] args)
- {
- Boolean arr[] = new Boolean[500];
- /*这里定一个下标为500的数组
- *这里要注意的一个地方在马仕兵老师的视频是以小的boolean
- *你是不是有想到Java不是大小敏感的吗?
- *所以这个也是一个知识点为什么用大写或小写都可以呢?先百度一下吧。
- */
- for(int i=0; i<arr.length; i++){
- arr[i]=true;
- }
- //这个地方是给500个数组元素都附初值true;
- //这个算法有关,是把每数到三时给那个元素附false;
- //剩到最后一个为true值为止,那就可以循环数组找到唯一一个值为true那个元素。
- int maxMan=arr.length; //现在数组中元素为true个数
- int count=0; //要数数吗,所以要有一个计数器,就设初值为0
- int index=0; //我们要定义从数组的哪个下标开始数起。我们设为第1个开始。
- while(maxMan>1){ //只要是数组元素中的true个数大于1个时我们都要继续数。
- if(arr[index]==true){ //只要碰到元素值是true的就开始数,如果值为false那么跳到index++
- count ++; //那就计数器加1,刚好是从一开始数
- if(count==3){ //当数到三时,我们要做以下的事
- count=0; //计数器清零
- arr[index]=false;//把当前的数组元数值改为false
- maxMan --; //这时数组中为true的元素个数也将减少一个。
- }
- }
- index ++; //下一个元素的下标
- if(index==500){ //如果己到了下标第500了。那个要进行下轮的数数直到maxMan为1为止。所以置index为0
- index=0;
- }
- }
- /*程序到这里为止,那个数组中只有一个元素为true的了。所以用下面的循环把那个元素给
- *找出来。并打印出它的下标值。也就是我们所需要的结果。
- */
- for(int i=0; i<arr.length;i++){
- if(arr[i]==true){
- System.out.println(i);
- }
- }
- }
- }
二、面像对像的方式
- class ob
- {
- public static void main(String[] args)
- {
- KidCircle kc = new KidCircle(500);//构建一个500个小孩围成的圈
- int count =0; //数三退一的计数器
- Kid k=kc.first; //圈里的第一个小孩
- while(kc.count>1){ //如果圈里的小孩数大于一个时循环数数
- count++; //计数器加1
- if(count==3){ //如果数到3了,那么计数器清零。并删除当前的小孩。
- count=0;
- kc.delete(k);
- }
- k=k.right; //删除后,从小孩左边的小孩开始继续数。直到人数只剩一个。
- }
- System.out.println(k.id);//完成后打印出最后一个小孩子的ID号。
- }
- }
- class Kid //创建一个小孩的类。
- {
- int id=0; //属性 小孩的id
- Kid left,right;//属性 定义小孩左边与右边的小孩
- }
- class KidCircle //创建一个圈的类
- {
- int count = 0; //属性 圈的小孩个数
- Kid first; //属性 圈起始的小孩
- Kid last; // 属性 圈结束的小孩
- KidCircle(int n){ //构造函数 构造一个以n个小孩围成的圈
- for(int i=0; i<n; i++){
- add();
- }
- }
- public void add(){ //圈添加小孩的方法
- Kid k = new Kid(); //new 一个小孩
- k.id=count; //定义当前的小孩的id为当前圈的小孩个数
- if(count<=0){ //如果当前圈没有小孩子时执行下面的两条语句
- first=last=k; //所添加的这个小孩是圈中的第一个,所以这个圈的开始和结束的小孩都是这个小孩
- k.left = k.right =k;//当然了这个孩的左边与右边的小孩也同样是当前的这个小孩
- }else{ //如果圈里己有小孩的情况执行下面的语句
- last.right =k; //当前小孩就成为原来最后一个小孩右边的小孩
- k.right=first;//当前小孩右边的是原来第一个小孩
- k.left =last; //当前小孩左边的是原来最后一个小孩
- first.left=k;//原来第一个的小孩左边就是当前的小孩了。
- last =k;//当添加完成后,当前小孩成为了这个圈的最后一个小孩。
- }//这里要注意了,last =k 一定要放到最后。
- count++;//圈里的人数加1
- }
- public void delete(Kid k){ //圈里删除一个小孩的方法
- if(count<=0){ //如果当前这个圈里没有小孩就直接反回没有得删了
- return;
- }else if(count==1){ //如果圈里只有一个小孩,那么他的左边和右边的小孩也是不存在的。
- k.left = k.right =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--;//圈里的人数减1
- }
- }