import java.util.ArrayList;
import java.util.List;
/**
* 约瑟夫问题,环形链表,双指针
*/
public class CircularLink {
//表示头节点,头节点值为1时,表示此链表为空
private Node first = new Node(-1);
//helper表示链表结尾的位置
private Node helper;
//表示链表中元素的个数
private int size;
//初始化循环链表
public CircularLink(int num){
this.size = num;
if (num<1 || num>size){
throw new IndexOutOfBoundsException("下标越界");
}
first = new Node(1);
first.next = first;
Node pNode = first;
for (int i = 2; i <= num; i++) {
Node newNode = new Node(i);
pNode.next = newNode;
newNode.next = first;
pNode = newNode;
helper = pNode;
}
}
//重写toString方法
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("[");
Node pNode = first;
for (int i = 0; i < size-1; i++) {
builder.append(pNode.data + ",");
pNode = pNode.next;
}
builder.append(pNode.data + "]");
return builder.toString();
}
/*
按照约瑟夫的规则输出序列三个参数
在一个循环链表中,规定一个起始位置start,开始计数,当计数到count时,将这个节点移除
并从移除的这个节点的下一个节点开始重新进行计数,直到链表中剩下最后一个节点,按照移除顺序输出这个链表
*/
public String show(int start, int count){
List list = new ArrayList(size);
if (start<1 || start>size){
throw new IndexOutOfBoundsException("下标越界");
}
//在初始化的时候,first的位置时1的位置,helper时size的位置,因为,start不一定是1,所以需要对这两个指针做一个移动
for (int i = 1; i < start; i++) {
first = first.next;
helper = helper.next;
}
while (list.size()<size){
//开始计数,在这里,本身也要计数,例如:count=2,则每次只移动一次
for (int i = 1; i < count; i++) {
first = first.next;
helper = helper.next;
}
list.add(first.data);
first = first.next;
helper.next = first;
}
return list.toString();
}
//定义一个内部类来模拟链表中的节点
private class Node{
int data;
Node next;
public Node(int data) {
this.data = data;
}
}
public static void main(String[] args) {
CircularLink link = new CircularLink(5);
System.out.println(link.toString());
String res = link.show(1,2);
System.out.println(res);
}
}
08-02
322