约瑟夫环问题:
* 背景:约瑟夫叙述了他和40个士兵在罗马战争期间被罗马军队包围之后签订的一人自杀协定。
* 约瑟夫建议每个人杀掉他旁边的人,约瑟夫利用制定的规则使自己成为这些人中唯一的幸存者。
* 编程:
1.考虑存储结构:顺序存储结构和链式存储结构(杀人模拟删除节点,链表更适合)
2.场景:程序需要处理8个士兵组成的线性表,因为每个人要杀掉他的邻居,则要保证
每个人都有邻居,因此采用循环单链表操作,指针指向的位置表示邻居。
3.核心思想:从循环单链表中某个节点开始依次去除其相邻节点,直到链表中剩下一个节点为止
##思考使用循环双链表及奇数的情况
1.循环单链表数据结构
1 package com.neusoft.link; 2 import com.neusoft.List.IList; 3 /** 4 * @author zhao-chj 5 * 循环单链表 6 */ 7 public class CircleLinkList implements IList{ 8 public Node head; 9 public CircleLinkList() { 10 // TODO 初始化 11 head=new Node();//初始化头结点 12 head.next=head; 13 } 14 @Override 15 public void clear() { 16 // TODO 清空 17 head.next=head; 18 } 19 @Override 20 public boolean isEmpty() { 21 // TODO 判空 22 return head.next.equals(head); 23 } 24 @Override 25 public int length() { 26 // TODO 长度 27 Node p =head.next; 28 int length=0; 29 while (!p.equals(head)) { 30 p=p.next; 31 length++; 32 } 33 return length; 34 } 35 @Override 36 public Object get(int i) { 37 // TODO 读取带头结点的循环链表中第i个数据元素 38 Node p=head.next; 39 int j=0; 40 while (!p.equals(head)&&j<i) { 41 p=p.next; 42 j++; 43 } 44 if (j>i||p.equals(head)) { 45 System.out.println("第"+i+"个元素不存在!"); 46 } 47 return p.data; 48 } 49 50 @Override 51 public void insert(int i, Object x) { 52 // TODO 带头结点的循环链表中第i个节点之前插入一个值为x的元素 53 Node p = head; 54 int j=-1;//第i个节点前驱位置 55 while ((!p.equals(head)||j==-1)&&j<i-1) { 56 p=p.next; 57 j++; 58 } 59 if (j>i-1||(p.equals(head)&&j!=-1)) { 60 System.out.println("插入位置不合法!"); 61 } 62 Node s =new Node(x); 63 s.next=p.next; 64 p.next=s; 65 } 66 67 @Override 68 public void remove(int i) { 69 // TODO 移除循环单链表中第i个元素的节点,注意i的范围 70 Node p=head;//p指向要删除节点的前驱节点 71 int j=-1; 72 while ((!p.next.equals(head)||j==-1)&&j<i-1) {//找前驱元素 73 p=p.next; 74 j++; 75 } 76 if (j>i-1||(p.next.equals(head)&&j!=-1)) { 77 System.out.println("删除位置不合法!"); 78 } 79 p.next=p.next.next; 80 } 81 82 @Override 83 public int indexOf(Object x) { 84 // TODO 查找值为x的元素,返回位置 85 Node p =head.next;//p指向首节点 86 int j=0; 87 while ((!p.equals(head))&&(!p.data.equals(x))) { 88 p=p.next; 89 j++; 90 } 91 if (!p.equals(head)) { 92 return j; 93 }else { 94 return -1; 95 } 96 } 97 @Override 98 public void display() { 99 // TODO 输出元素 100 Node p =head.next; 101 while (!p.equals(head)) { 102 System.out.print(p.data+" "); 103 p=p.next; 104 } 105 System.out.println(); 106 } 107 108 @Override 109 public int remove(Object i) { 110 // TODO Auto-generated method stub 111 return 0; 112 } 113 114 }
2.约瑟夫环循环单链表求解
1 package com.neusoft.exercise; 2 3 import java.util.Scanner; 4 5 import com.neusoft.link.CircleLinkList; 6 7 /** 8 * @author zhao-chj 9 * 约瑟夫环问题: 10 * 来源:约瑟夫叙述了他和40个士兵在罗马战争期间被罗马军队包围之后签订的一人自杀协定。 11 * 约瑟夫建议每个人杀掉他旁边的人,约瑟夫利用制定的规则使自己成为这些人中唯一的幸存者。 12 * 编程:1.考虑存储结构:顺序存储结构和链式存储结构(杀人模拟删除节点,链表更适合) 13 * 2.场景:程序需要处理8个士兵组成的线性表,因为每个人要杀掉他的邻居,则要保证 14 * 每个人都有邻居,因此采用循环单链表操作,指针指向的位置表示邻居。 15 * ##可以考虑使用循环双链表 16 * 3.核心思想:从循环单链表中某个节点开始依次去除其相邻节点,直到链表中剩下一个节点为止 17 * 18 */ 19 public class TestLinearTable06 { 20 public static void main(String[] args) { 21 CircleLinkList circleLinkList = new CircleLinkList(); 22 Scanner sc = new Scanner(System.in); 23 System.out.println("请您输入士兵的个数~"); 24 int num = sc.nextInt(); 25 System.out.println(num+"士兵分别为:"); 26 for (int i = 0; i < num; i++) { 27 //输入num个士兵 28 circleLinkList.insert(i, sc.next()); 29 } 30 for (int i = 0; circleLinkList.length()>1; ) { 31 i = i%circleLinkList.length(); 32 System.out.println("长度:"+circleLinkList.length());//测试用可注释 33 //读取到链表中位序号为i的士兵 34 String str1= circleLinkList.get(i).toString(); 35 System.out.println("STR1:"+str1);//测试用可注释 36 //求出相邻士兵在链表中的位序号 37 i=++i%circleLinkList.length(); 38 //相邻的士兵 39 String str2 =circleLinkList.get(i).toString(); 40 System.out.println("STR2:"+str2);//测试用可注释 41 //杀死相邻的士兵 42 circleLinkList.remove(i); 43 //输出谁杀死谁的信息 44 System.out.println(str1+"杀死"+str2); 45 } 46 System.out.println("活着的是(约瑟夫)是:"+circleLinkList.get(0)); 47 } 48 }
3.结果测试
- 1.加入一些输出语句的测试
- 2.不带输出语句的测试