环形链表
构造图
经典应用
约瑟夫问题
设编号为1,2,… n的n个同学围坐在一起形成一个圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,下一个人又从1开始报数,以此类推,直到所有人出列为止,产生一个出队编号。
思路
- 利用环形链表这种结构模拟n个同学围成一圈
- 通过链表的删除算法,模拟数到m的那个人出列
- 剩下最后一个节点则循环结束,无需在移除
class Stu{ //链表节点
private int data;
private Stu next;
public Stu(){}
public Stu(int data){
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public void setNext(Stu next) {
this.next = next;
}
public Stu getNext() {
return next;
}
}
class StudentLinked{ //链表
//根据n构造环形队列,返回入口节点
public Stu createLinked(int n){
Stu head = new Stu(1);
Stu op = head;
for(int i =2;i<=n;i++){
Stu stu = new Stu();
stu.setData(i); //编号
op.setNext(stu);
op = stu;
}
op.setNext(head);
return head;
}
//移除op对应节点
public void removeLinked(Stu op,Stu op_pre){
if(op == null || op_pre == null) throw new RuntimeException("空指针");
if(op == op_pre) throw new RuntimeException("链表仅剩最后一个节点");
op_pre.setNext(op.getNext());
op.setNext(null);
}
}
public class Test {
//函数调用
public static void main(String[] args) {
StudentLinked lined = new StudentLinked();
YSF_issue(lined,5,1,3);
}
//具体解决函数
public static void YSF_issue(StudentLinked entrance,int n,int k,int m){
Stu op = entrance.createLinked(n);
Stu op_pre = op;
//确定op指针位置(op:需要删除的那个节点)
while(op.getNext() != null){
if(op.getData() == k)break;
op = op.getNext();
}
//确定op_pre指针位置(op_pre:需要删除的那个节点的前一个节点)
while(op_pre.getNext() != null){
if(op_pre.getNext() == op) break;
op_pre = op_pre.getNext();
}
//op = op_pre时 则只剩下一个节点
int pos = 0;
while(op!=op_pre){
if(++pos == m){
System.out.print(op.getData()+" ");//打印模拟出队
entrance.removeLinked(op,op_pre);
op = op_pre.getNext();
pos = 0;
}else {
op_pre = op_pre.getNext();
op = op.getNext();
}
}
System.out.print(op.getData());//最后一个人出队
}
}
假设5个同学围成一圈,从k=1这个编号的人开始从1报数,报数等于(m=3)的时候出队,继续下一个从1开始报数。
最终得出一个队列为 3 1 5 2 4