标题：约瑟夫环
例子
n = 9,k = 1,m = 5
【解答】
出局人的顺序为5,1,7,4,3,6,9,2,8。
链表方法
这个就是约瑟夫环问题的实际场景，有一种是要通过输入n,m,k三个正整数，来求出列的序列。这个问题采用的是典型的循环链表的数据结构，就是将一个链表的尾元素指针指向队首元素。p->link=head
解决问题的核心步骤：（程序的基本算法）
⒈建立一个具有n个链结点，无头结点的循环链表；
⒉确定第1个报数人的位置；
⒊不断地从链表中删除链结点，直到链表为空。
void JOSEPHUS(int n,int k,int m) //n为总人数，k为第一个开始报数的人，m为出列者喊到的数
{
/* p为当前结点 r为辅助结点，指向p的前驱结点 list为头节点*/
LinkList p,r,list; 　/*建立循环链表*/
for(int i=0；i<n；i++)
{
p=(LinkList)malloc(sizeof(LNode));
p->data=i;
if(list==NULL){
list=p;
r=p;
}
else{
r->link=p;
r=p;
}
}
p->link=list; 　/*使链表循环起来*/
p=list；　 /*使p指向头节点*/
/*把当前指针移动到第一个报数的人*/
for(i=0;i<k;i++)
{
r=p；
p=p->link;
}
/*循环地删除队列结点*/
while(p->link!=p)
{
for(i=0;i<m-1;i++)
{
r=p;
p=p->link;
}
r->link=p->link;
printf("被删除的元素：%4d ",p->data);
free(p);
p=r->link;
}
printf("\n最后被删除的元素是：%4d",P->data);
}
Josephus（约瑟夫）问题的非递归方法
首先我们列出一些有关约瑟夫环的结果：
1 1 2 2 3 2 4 1 5 4 6 1 7 4 8 7 9 1 10 4
11 7 12 10 13 13 14 2 15 5 16 8 17 11 18 14 19 17 20 20
21 2 22 5 23 8 24 11 25 14 26 17 27 20 28 23 29 26 30 29
31 1 32 4 33 7 34 10 35 13 36 16 37 19 38 22 39 25 40 28
41 31 42 34 43 37 44 40 45 43 46 46 47 2 48 5 49 8 50 11
51 14 52 17 53 20 54 23 55 26 56 29 57 32 58 35 59 38 60 41
61 44 62 47 63 50 64 53 65 56 66 59 67 62 68 65 69 68 70 1
71 4 72 7 73 10 74 13 75 16 76 19 77 22 78 25 79 28 80 31
81 34 82 37 83 40 84 43 85 46 86 49 87 52 88 55 89 58 90 61
91 64 92 67 93 70 94 73 95 76 96 79 97 82 98 85 99 88 100 91
意思是，前一个数为约瑟夫环的人数，后一个数为最后出去的人的号码。
从上面的表中我们可以归纳出以下两个规则：
规则1:若上一组数字中最后保留号比人数少一，则下一数从1开始记。
例如第三组（3,2）为上一组，最后保留号为2，比3少1，下一组的数字（4,1），最后保留号为1
规则2：若上一组数字为最后保留号与人数相等，则下一数从2开始记。
以下是C语言编写的程序。
#include <stdio.h>
#define M 200
int main()
{
int temp=0;
int b=1,k=0;
for(int i=1;i<=M;i++)
{
temp=b+3*k;
if(i==temp)//规则2：若上一组数字为最后保留号与人数相等，则下一数从2开始记。
{
b=2;
k=0;
continue;
}
else if(i-temp==1）//规则1：若上一组数字为最后保留号比人数少一，则下一数从1开始记。
{
b=1;
k=0;
continue;
}
k++;
}
printf("%d %d ",M,temp);
return 0;
}
Josephus（约瑟夫）问题的数学方法
无论是用链表实现还是用数组实现都有一个共同点：要模拟整个游戏过程，不仅程序写起来比较烦，而且时间复杂度高达O(nm），当n，m非常大（例如上百万，上千万）的时候，几乎是没有办法在短时间内出结果的。我们注意到原问题仅仅是要求出最后的胜利者的序号，而不是要读者模拟整个过程。因此如果要追求效率，就要打破常规，实施一点数学策略。
为了讨论方便，先把问题稍微改变一下，并不影响原意：
问题描述：n个人（编号0~(n-1）），从0开始报数，报到m-1的退出
，剩下的人继续从0开始报数。求胜利者的编号。
我们知道第一个人（编号一定是（m-1）%n) 出列之后，剩下的n-1个人组成了一个新的约瑟夫环（以编号为k=m%n的人开始）：
k k+1 k+2 ... n-2,n-1,0,1,2,... k-2
并且从k开始报0。
现在我们把他们的编号做一下转换：
k --> 0
k+1 --> 1
k+2 --> 2
...
...
k-3 --> n-3
k-2 --> n-2
序列1：0,1,2,3 … n-2,n-1
序列2：0,1,2,3 … k-2,k，…，n-2,n-1
序列3：k,k+1,k+2,k+3，…，n-2,n-1,1,2,3，…，k-2,
序列4：0,1,2,3 …，5,6,7,8，…，n-3,n-2
变换后就完完全全成为了（n-1）个人报数的子问题，假如我们知道这个子问题的解：例如x是最终的胜利者，那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗？！！变回去的公式很简单，相信大家都可以推出来：
∵ k=m%n;
∴ x' = x+k = x+ m%n ; 而 x+ m%n 可能大于n
∴x'= (x+ m%n)%n = (x+m)%n
得到 x‘=(x+m)%n
如何知道（n-1）个人报数的问题的解？对，只要知道（n-2）个人的解就行了。（n-2）个人的解呢？当然是先求（n-3）的情况 ---- 这显然就是一个倒推问题！好了，思路出来了，下面写递推公式：
令f表示i个人玩游戏报m退出最后胜利者的编号，最后的结果自然是f[n].
递推公式：
f[1]=0;
f[i]=(f[i-1]+m)%i; (i>1）
有了这个公式，我们要做的就是从1-n顺序算出f的数值，最后结果是f[n]。因为实际生活中编号总是从1开始，我们输出f[n]+1。
我们输出f[n]由于是逐级递推，不需要保存每个，程序也是异常简单：（注意编号是0 -- n-1）
#include <stdio.h>
int main(void)
{
int n,m,i,s=0;
printf ("N M = ");
scanf("%d%d",&n,&m);
for (i=2; i<=n; i++)
s=(s+m)%i;
printf ("The winner is %d\n",s); 
return 0 ;
} 
时间复杂度为O(n），相对于模拟算法已经有了很大的提高。算n，m等于一百万，一千万的情况不是问题了。可见，适当地运用数学策略，不仅可以让编程变得简单，而且往往会成倍地提高算法执行效率。
参照上面提供的思路，我认为可以类似的得到一个更易于明白的方法，设有（1,2,3，……，k-1，k，k+1，……，n）n个数，当k出列时，那么有
k+1 -->1
k+2 -->2
...
...
n -->n-k
1 -->n-k+1
...
...
k-1 -->n-1
由上面一组式子可以推出，若知道新产生的n-1个数中某个数x，那么很显然可以推出x在原数列里的位置，即x‘=（x+k）%n，由此，我们可以得到一个递推公式
f[1]=1
f[n]=(f[n-1]+k)%n （n>1）
如果你认为上式可以推出约瑟夫环问题的解，很不幸，你错了，上面的递推公式中，在某种情况下，f[n-1]+k会整除n，如n=2，k=3，这时我们修要对上式进行修正，
f[n]=(f[n-1]+k)%n;if(f[n]==0)f[n]=n;
问题得解。程序代码如下：
#include<stdio.h>
int main()
{
int n,k,s=1;
scanf("%d%d",&n,&k);
for(int i=2;i<=n;i+=1）
{
s=(s+k)%i;
if(s==0)s=i;
}
printf("ans=%d\n",s);
return 0;
}
当然，我们还可以用递归方法解决此问题：
#include<stdio.h>
int main()
{
int jos(int n,int k);
int n,k,s;
scanf("%d%d",&n,&k);
s=jos(n,k);
printf("ans=%d\n",s);
return 0;
}
int jos(int n,int k)
{
int x;
if(n==1）x=1;
else {x=(jos(n-1,k)+k)%n;if(x==0)x=n;}
return x;
}
解决Josephus(约瑟夫）问题的pascal代码
program Josephus(input,output);
type pointer=^nodetype;
nodetype=record
data:integer;
link:pointer
end;
var head,next,last:pointer;
i,n,s,j,m,k:integer;
begin
writeln('请输入组成约瑟夫环的人数：');
read(n);
new(head);
head^.data :=1;
last:=head;
for i:=2 to n do
begin
new(next);
next^.data :=i;
last^.link :=next;
last:=next
end;
last^.link :=head;
next:=head;
repeat
begin
writeln(next^.data);
next:=next^.link
end;
until next=head;
readln;
next:=head;
writeln('请输入第一个报数人的位置：');
read(s);
j:=1;
if s<=n
then
while j<s do
begin
next:=next^.link ;
j:=j+1
end
else writeln('你的输入有误');
writeln('请输入出列人的位置：');
read(m);
while next^.link <>next do
begin
k:=1;
while k<m do
begin
last:=next;
next:=next^.link ;
k:=k+1
end;
writeln(next^.data);
last^.link :=next.link ;
next:=next^.link 
end;
writeln(next^.data);
readln;
readln
end.
C语言模拟 约瑟夫环#include <stdio.h>
#define M 10/*总人数*/
#define N 5
#define START 0/*第一个报数的人*/
void main(void)
{
int a[M],i=0,k,count=0;
while(i++<M)/*给每个人编号*/
a[i-1]=i;
for(i=START;count<=M-1;count++)
{
for(k=1;k<=N;a[i++]&&++k)/*根据&&；运算的路短原理，若a[i]为0的话，++k的运算会被省略而++i的运算总会进行*/
if(i>M-1）
i=0;
printf("%d ",i?a[i-1]:a[M-1]);
a[(i?(i-1）：（M-1））]=0;
}
getch();
}
C#描述///<summary>；约瑟夫环</summary>
/// <remarks>Program by nickelzhang</remarks>
static void Main(string[] args)
{
/*
*已知n个人（以编号1，2，3...n分别表示）围坐在一张圆桌周围。
*从编号为k的人开始报数，数到m的那个人出列；
*他的下一个人又从1开始报数，数到m的那个人又出列；
*依此规律重复下去，直到圆桌周围的人全部出列。
*/
int n = 7;
int k = 2;
int m = 3;
Link head = new Link() { Value = "1" };
Link node = head;
for (int i = 2; i <= n; i++)
{
node.Next = new Link();
node = node.Next;
node.Value = i.ToString();
}
node.Next = head;
//循环链表建立完毕
Link cur = head;
//指针移动到第K个人
for (int i = 1; i < k; i++)
{
cur = cur.Next;
}
//开始报数
do
{ 
for (int i = 1; i < m - 1; i++)
{
cur = cur.Next;
}
Console.WriteLine(cur.Next.Value);
cur.Next = cur.Next.Next;//删除第m个人
cur = cur.Next;//指针指向m+1
} while (cur != cur.Next);//仅剩下一个人，报数结束
Console.WriteLine(cur.Value);
}
/// <summary>
/// 循环链表节点
/// </summary>
public class Link
{
public string Value;
public Link Next;
}
Java递归实现
import java.util.LinkedList;
/**
* 
* @author Love yali_deng forever
*
*/
public class Yuesefu {
/**
* 约瑟夫环是一个数学的应用问题：
* 
* 已知n个人（以编号1，2，3...n分别表示）围坐在一张圆桌周围。从编号为k的人开始报数，数到m的那个
*人出 列；
* 他的下一个人又从1开始报数，数到m的那个人又出列；依此规律重复下去，直到圆桌周围的人全部出列。
* 
* @param args
*/
private static StringBuffer removedStr = new StringBuffer("");// 记录出列的数字
public static void main(String[] args) {
long startTime = System.currentTimeMillis(); // 获取开始时间
process（5000,10,1）；
System.out.println(removedStr.substring(0,removedStr.length() - 1））；
long endTime = System.currentTimeMillis(); // 获取结束时间
System.out.println("程序运行时间：" + (endTime - startTime) + "ms");
}
public static void process(int n,int k,int m) {
// 构建一个list，存放人数
LinkedList<Integer> list = new LinkedList<Integer>();
for (int i = 0; i < n; i++) {
if (i + k > n) {
list.add(i + k - n);
} else {
list.add(i + k);
}
}
int count = 1;// 记录数的人数
cycleCal(list,count,m);
}
public static void cycleCal(LinkedList<Integer> list,int count,int m) {
int len = list.size();
if (len > 1） {
for (int i = 0; i < len; i++) {
if (count == m) {// 第m个时，remove
removedStr.append(list.get(i)).append(",");
list.remove(i);
len = list.size();
i--;
count = 0;
}
count++;
}
cycleCal(list,count,m);
} else {
if (len != 0) {
removedStr.append(list.get(0)).append(",");
}
}
}
}
Common Lisp递归实现
（defun josephus-main ()
（let ((lt (make-array 20 :fill-pointer 0)))
（dotimes (var 20）
（vector-push var lt))
（josephus-loop lt)))
（defun josephus-loop(lt)
（if (= (length lt) 1）
（progn
（format t "~a~%" lt)
（return-from josephus-loop)))
（if (>= (length lt) 5）
（progn
（let ((setv (remove (elt lt 4） lt)))
（josephus-loop setv)))
（progn
（let ((setv (remove (elt lt (if (= (length lt) (- 4 (length lt))) (- 4 (length lt) 1） (- 4 (length lt)))) lt)))
（josephus-loop setv)))))