1. 问题描述:
设编号为1,2,…,n的n个人围坐一圈,约定编号为k(1 <=k <=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
2. 分析: 该问题可以使用多种数据结构, 但是比较简单和自然的做法是利用一个具有n个链接点且不带头接点的循环链表.
3. 实现:
1) 建立循环链表:
代码
public class CirculaLinkedNode<T>
{
public T Data { set; get; }
public CirculaLinkedNode<T> Next { set; get; }
}
public class CirculaLinkedList<T>
{
public CirculaLinkedNode<T> Head { set; get; }
public CirculaLinkedList(CirculaLinkedNode<T> head)
{
this.Head = head;
}
public CirculaLinkedList(T[] data)
{
if (data == null || data.Length < 1)
{
throw new ArgumentNullException("data");
}
CirculaLinkedNode<T> head = new CirculaLinkedNode<T>
{
Data = data[0],
Next = null
};
CirculaLinkedNode<T> currentNode = head, node = null;
for (int i = 1; i < data.Length; i++)
{
node = new CirculaLinkedNode<T>
{
Data = data[i],
Next = null
};
currentNode.Next = node;
currentNode = node;
}
currentNode.Next = head;
this.Head = head;
}
public void Remove(CirculaLinkedNode<T> node)
{
if (this.Head == null)
{
return;
}
if (this.Head.Equals(node))
{
if (Head.Next.Equals(Head))
{
Head = null;
}
else
{
var n = Head.Next;
while (!n.Next.Equals(Head))
{
n = n.Next;
}
n.Next = Head.Next;
Head = Head.Next;
}
}
else
{
var n = Head;
while (!n.Next.Equals(Head))
{
if (n.Next.Equals(node))
{
n.Next = n.Next.Next;
break;
}
n = n.Next;
}
}
}
public CirculaLinkedNode<T> GetNodeByValue(T value)
{
var node = this.Head;
while (!node.Next.Equals(Head))
{
if (node.Data.Equals(value))
{
return node;
}
node = node.Next;
}
return null;
}
}
{
public T Data { set; get; }
public CirculaLinkedNode<T> Next { set; get; }
}
public class CirculaLinkedList<T>
{
public CirculaLinkedNode<T> Head { set; get; }
public CirculaLinkedList(CirculaLinkedNode<T> head)
{
this.Head = head;
}
public CirculaLinkedList(T[] data)
{
if (data == null || data.Length < 1)
{
throw new ArgumentNullException("data");
}
CirculaLinkedNode<T> head = new CirculaLinkedNode<T>
{
Data = data[0],
Next = null
};
CirculaLinkedNode<T> currentNode = head, node = null;
for (int i = 1; i < data.Length; i++)
{
node = new CirculaLinkedNode<T>
{
Data = data[i],
Next = null
};
currentNode.Next = node;
currentNode = node;
}
currentNode.Next = head;
this.Head = head;
}
public void Remove(CirculaLinkedNode<T> node)
{
if (this.Head == null)
{
return;
}
if (this.Head.Equals(node))
{
if (Head.Next.Equals(Head))
{
Head = null;
}
else
{
var n = Head.Next;
while (!n.Next.Equals(Head))
{
n = n.Next;
}
n.Next = Head.Next;
Head = Head.Next;
}
}
else
{
var n = Head;
while (!n.Next.Equals(Head))
{
if (n.Next.Equals(node))
{
n.Next = n.Next.Next;
break;
}
n = n.Next;
}
}
}
public CirculaLinkedNode<T> GetNodeByValue(T value)
{
var node = this.Head;
while (!node.Next.Equals(Head))
{
if (node.Data.Equals(value))
{
return node;
}
node = node.Next;
}
return null;
}
}
2) 实现Josephu解决方案:
代码
/// <summary>
/// Josephy Problem
/// </summary>
/// <param name="n">N people</param>
/// <param name="m"></param>
/// <param name="k"></param>
public static void Josephu(int n, int m, int k)
{
if (n < 1)
{
throw new ArgumentOutOfRangeException("n");
}
if (m < 1)
{
throw new ArgumentOutOfRangeException("m");
}
if (k < 1 || k > n)
{
throw new ArgumentOutOfRangeException("k");
}
int[] personArray = new int[n];
for (int i = 0; i < n; i++)
{
personArray[i] = i + 1;
}
CirculaLinkedList<int> cList = new CirculaLinkedList<int>(personArray);
var firstNode = cList.GetNodeByValue(k);
var node = firstNode;
while (cList != null && cList.Head != null)
{
for (int i = 1; i < m; i++)
{
node = node.Next;
}
Console.Write("---> {0}", node.Data);
firstNode = node.Next;
cList.Remove(node);
node = firstNode;
}
Console.WriteLine("");
}
/// Josephy Problem
/// </summary>
/// <param name="n">N people</param>
/// <param name="m"></param>
/// <param name="k"></param>
public static void Josephu(int n, int m, int k)
{
if (n < 1)
{
throw new ArgumentOutOfRangeException("n");
}
if (m < 1)
{
throw new ArgumentOutOfRangeException("m");
}
if (k < 1 || k > n)
{
throw new ArgumentOutOfRangeException("k");
}
int[] personArray = new int[n];
for (int i = 0; i < n; i++)
{
personArray[i] = i + 1;
}
CirculaLinkedList<int> cList = new CirculaLinkedList<int>(personArray);
var firstNode = cList.GetNodeByValue(k);
var node = firstNode;
while (cList != null && cList.Head != null)
{
for (int i = 1; i < m; i++)
{
node = node.Next;
}
Console.Write("---> {0}", node.Data);
firstNode = node.Next;
cList.Remove(node);
node = firstNode;
}
Console.WriteLine("");
}
3) 测试:
CirculaLinkedListAction.Josephu(8, 4, 3);