java之单链表解决约瑟夫问题

java之单链表解决约瑟夫问题


文章内容选自尚硅谷,jdk8,eclipse环境

所谓约瑟夫问题就是丢手绢游戏,一个带编号环形列表,从某处开始重复报数,假如报到n的人必须退出列表,求最后退出列表的人是原来环形列表的第几号。

解决约瑟夫问题分两步,第一步是环形列表的创建,第二步是报数n的人出列表。

在这里插入图片描述
上图是尚硅谷的图。

  1. 着重说明一下第二步的步骤,首先让first指针指向环形列表第一个元素(环形列表是分首尾的),让helper指针指向first前一个元素。
  2. 然后把first定位到第一个报数的人(编号为k)的位置。要移动到该位置,需要把两个指针分别转移k-1次。
  3. 从编号为k的人开始报数,每数到n的人退出,把first指针定位到k+n的位置,那么helper就到k+n-1的位置,两个指针都要移动n-1次。
  4. 把数到n的人移除,就是把first指针指向k+n+1的位置,把helper的next属性变为k+n+1的位置。
  5. 重复以上报数的操作,报数的操作使用一个循环语句完成,当环形列表只剩下最后一个人的时候,此时first和helper的值相同。

代码如下

package linkedlist;

public class Josepfu {

	public static void main(String[] args) {
		CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
//		circleSingleLinkedList.addBoy(125);
//		circleSingleLinkedList.show();
		circleSingleLinkedList.outOfList(10, 20, 125);
	}	
}

class CircleSingleLinkedList{
	Boy first = null;
	Boy curBoy = null;
	
	public void addBoy(int n){
		for(int i = 1;i<=n;i++){
			Boy boy = new Boy(i);
			if(i<1){
				System.out.println("输入个数不能小于1,请重新输入");
			}else{
				if(i == 1){
					first = boy;
					curBoy = boy;
					boy.setNext(first);
				}
				else{
					curBoy.setNext(boy);
					boy.setNext(first);
					curBoy = boy;
				}
			}
		}
	}
	
	public void show(){
		if(first == null){
			System.out.println("链表为空");
			return;
		}
		curBoy = first;
		while(true){
			System.out.printf("当前的boy编号为%d",curBoy.getNo());
			System.out.println();
			if(curBoy.getNext() == first)
				break;
			curBoy = curBoy.getNext();
		}
	}
	
	public  void outOfList(int startNo,int countNo,int nums){
		addBoy(nums);
		if(first == null || startNo < 1 || startNo > nums){
			System.out.println("输入的数字不合要求,请重新输入");
			return;
		}

		Boy helper = first;
		while(true){
			if(helper.getNext() == first){
				break;
			}
			helper = helper.getNext();
		}
		
		for(int i = 0;i<startNo -1;i++){
			helper = helper.getNext();
			first = first.getNext();
		}
		
		while(true){
			if(first == helper){
				System.out.printf("最后剩下的编号为%d",first.getNo());
				break;
			}
			for(int i = 0;i<countNo-1;i++){
				helper = helper.getNext();
				first = first.getNext();
			}
			System.out.printf("出圈的男孩编号为%d",first.getNo());
			System.out.println();
			first = first.getNext();
			helper.setNext(first);
		}
	}
}

class Boy{
	private int no;
	private Boy next;
	
	public Boy(int no){
		this.no = no;
	}

	public int getNo() {
		return no;
	}

	public void setNo(int no) {
		this.no = no;
	}

	public Boy getNext() {
		return next;
	}

	public void setNext(Boy next) {
		this.next = next;
	}		
}

运行结果为

出圈的男孩编号为29
出圈的男孩编号为49
出圈的男孩编号为69
出圈的男孩编号为89
出圈的男孩编号为109
出圈的男孩编号为4
出圈的男孩编号为24
出圈的男孩编号为45
出圈的男孩编号为66
出圈的男孩编号为87
出圈的男孩编号为108
出圈的男孩编号为5
出圈的男孩编号为26
出圈的男孩编号为48
出圈的男孩编号为71
出圈的男孩编号为93
出圈的男孩编号为115
出圈的男孩编号为12
出圈的男孩编号为35
出圈的男孩编号为58
出圈的男孩编号为81
出圈的男孩编号为104
出圈的男孩编号为2
出圈的男孩编号为27
出圈的男孩编号为52
出圈的男孩编号为76
出圈的男孩编号为100
出圈的男孩编号为124
出圈的男孩编号为23
出圈的男孩编号为51
出圈的男孩编号为77
出圈的男孩编号为102
出圈的男孩编号为3
出圈的男孩编号为31
出圈的男孩编号为57
出圈的男孩编号为84
出圈的男孩编号为112
出圈的男孩编号为14
出圈的男孩编号为41
出圈的男孩编号为70
出圈的男孩编号为98
出圈的男孩编号为1
出圈的男孩编号为33
出圈的男孩编号为62
出圈的男孩编号为92
出圈的男孩编号为121
出圈的男孩编号为28
出圈的男孩编号为60
出圈的男孩编号为91
出圈的男孩编号为122
出圈的男孩编号为32
出圈的男孩编号为64
出圈的男孩编号为97
出圈的男孩编号为8
出圈的男孩编号为40
出圈的男孩编号为75
出圈的男孩编号为111
出圈的男孩编号为19
出圈的男孩编号为56
出圈的男孩编号为95
出圈的男孩编号为9
出圈的男孩编号为44
出圈的男孩编号为83
出圈的男孩编号为120
出圈的男孩编号为38
出圈的男孩编号为79
出圈的男孩编号为118
出圈的男孩编号为37
出圈的男孩编号为80
出圈的男孩编号为123
出圈的男孩编号为43
出圈的男孩编号为88
出圈的男孩编号为11
出圈的男孩编号为55
出圈的男孩编号为105
出圈的男孩编号为22
出圈的男孩编号为74
出圈的男孩编号为6
出圈的男孩编号为54
出圈的男孩编号为107
出圈的男孩编号为36
出圈的男孩编号为94
出圈的男孩编号为20
出圈的男孩编号为82
出圈的男孩编号为16
出圈的男孩编号为73
出圈的男孩编号为15
出圈的男孩编号为78
出圈的男孩编号为18
出圈的男孩编号为90
出圈的男孩编号为34
出圈的男孩编号为106
出圈的男孩编号为53
出圈的男孩编号为125
出圈的男孩编号为85
出圈的男孩编号为42
出圈的男孩编号为117
出圈的男孩编号为86
出圈的男孩编号为50
出圈的男孩编号为17
出圈的男孩编号为114
出圈的男孩编号为99
出圈的男孩编号为67
出圈的男孩编号为61
出圈的男孩编号为47
出圈的男孩编号为46
出圈的男孩编号为59
出圈的男孩编号为65
出圈的男孩编号为96
出圈的男孩编号为113
出圈的男孩编号为13
出圈的男孩编号为68
出圈的男孩编号为7
出圈的男孩编号为101
出圈的男孩编号为39
出圈的男孩编号为30
出圈的男孩编号为72
出圈的男孩编号为119
出圈的男孩编号为110
出圈的男孩编号为10
出圈的男孩编号为116
出圈的男孩编号为103
出圈的男孩编号为25
出圈的男孩编号为21
最后剩下的编号为63

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值