之前在博客园首页推荐里看到了浅议约瑟夫问题这篇文章,于是正好顺手补完一下。
注意:本文不讨论约瑟夫问题的数学归纳计算法。
原文中介绍了循环链表法和位图数组法两种最基本的约瑟夫问题解法。而两种方法各有优点和不足的地方。链表法在处理大量离散数据的时候效率更高,但是大量的内存碎片开销也是个问题。而位图法虽然代码简洁,也没有内存碎片问题,但是在死亡人数上升后,效率会大幅下降。
于是出现了一种方法,叫做数组链表法,同时结合了以上这两种方法,取其优点,克服其缺点。具体的概念图和比较如下。
一人死亡后:
结构和算法 | 循环链表 | 位图数组 | 数组链表 |
---|---|---|---|
优点 | 效率高 | 代码可读性强 内存分配整齐 | 效率高 内存整齐 代码可读性强 |
缺点 | 代码量多 可读性差 | 效率略低 | 几乎没有 |
以下是示例代码:
1
using System;
2
3 namespace Josephus
4 {
5 class Program
6 {
7 static void Main( string[] args)
8 {
9 JosephusRing jr = new JosephusRing( 7, 20);
10 int dead;
11 while ( 0 <= (dead = jr.KickNext()))
12 Console.WriteLine(dead + 1);
13 Console.ReadKey();
14 }
15 }
16
17 public class JosephusRing
18 {
19 public int Alive { get; private set; }
20 public int DieCount { get; private set; }
21 int[] ring;
22 int ringpos = 0;
23 public JosephusRing( int totalPeople, int dieCount)
24 {
25 // Initialize Ring
26 ring = new int[totalPeople];
27 for ( int i = 0; i < totalPeople - 1; i++)
28 ring[i] = i + 1; // Point to next person
29 Alive = totalPeople;
30 DieCount = dieCount;
31 }
32
33 public int KickNext()
34 {
35 int dead;
36 if (Alive < 1)
37 return - 1;
38 for ( int i = 0; i < (DieCount - 2) % Alive; i++) // Point to person before dead
39 ringpos = ring[ringpos];
40 dead = ring[ringpos]; // You are dead
41 Alive--;
42 ring[ringpos] = ring[ring[ringpos]]; // Kick dead person from ring
43 ringpos = ring[ringpos]; // Move cursor to next person
44 return dead;
45 }
46 }
47 }
2
3 namespace Josephus
4 {
5 class Program
6 {
7 static void Main( string[] args)
8 {
9 JosephusRing jr = new JosephusRing( 7, 20);
10 int dead;
11 while ( 0 <= (dead = jr.KickNext()))
12 Console.WriteLine(dead + 1);
13 Console.ReadKey();
14 }
15 }
16
17 public class JosephusRing
18 {
19 public int Alive { get; private set; }
20 public int DieCount { get; private set; }
21 int[] ring;
22 int ringpos = 0;
23 public JosephusRing( int totalPeople, int dieCount)
24 {
25 // Initialize Ring
26 ring = new int[totalPeople];
27 for ( int i = 0; i < totalPeople - 1; i++)
28 ring[i] = i + 1; // Point to next person
29 Alive = totalPeople;
30 DieCount = dieCount;
31 }
32
33 public int KickNext()
34 {
35 int dead;
36 if (Alive < 1)
37 return - 1;
38 for ( int i = 0; i < (DieCount - 2) % Alive; i++) // Point to person before dead
39 ringpos = ring[ringpos];
40 dead = ring[ringpos]; // You are dead
41 Alive--;
42 ring[ringpos] = ring[ring[ringpos]]; // Kick dead person from ring
43 ringpos = ring[ringpos]; // Move cursor to next person
44 return dead;
45 }
46 }
47 }
仅供参考。