高效实现Josephus算法
副标题#e#
Josephus界说:假设N小我私家编号1-N,围成圈。从1号开始报数,报到M时,此人退出,然 后继承从1开始报数,直到所有人退出为止。简朴的实现是利用轮回单链表,配置一个计数器 count,当count == M ,删除当前节点,并将count重置。
假设M = 9,N = 5;
这里有两处处所可以优化:
1.当M>N时,取M`= M mod N,即M` = 9 % 5 = 4;报数到9与报数到4结果一致,但少遍历一次链表;
2.当M` > N / 2时,可逆 向走N – M’ + 1步,此时反向走比正向走间隔更近,但需要将数据布局配置为轮回双链 表。
对付M = 9,N = 5,实现优化后流程如下:
—
链表:1 2 3 4 5
N = 5
M` = 9 mod 5 = 4
M` = 4 > N / 2 = 2
反走(5 – 4 + 1) = 2 步,删除节点4,此时起点在节点3;
—
链表:1 2 3 5
N = 4
M` = 9 mod 4 = 1
M' = 1 < N / 2 = 2
正走1步,删除节点5,此时起点在节点3;
—
链 表:1 2 3
N = 3
M` = 9 mod 3 = 0
M` = 0 < N / 2 = 1
正走0步,删除节点3,此时起点在节点2;
—
链表:1 2
N = 2
M` = 9 mod 2 = 1
M` = 1 = N / 2 = 1
#p#副标题#e#
正 走1步,删除节点1,此时起点在节点2;
—
链表:2
N = 1
M` = 9 mod 1 = 0
M` = 0 = N / 2 = 0
正走0步,删除节点2,此时 链表空;
算法C实现:
#include <stdio.h>
#include "dlinkedlist.h"
#define SIZE 5
#define N SIZE
#define M 9
static List init();
void print(List l);
void process(List l);
int main()
{
List josephus = init();
print (josephus);
process(josephus);
return 0;
}
/* 初始化链表 */
static List init()
{
int i;
List josephus = CreateList(1);
Position p = josephus;
for (i = 2; i <= SIZE; i++)
{
Insert(i, josephus, p);
p = NextPosition(p);
}
return josephus;
}
/* 打印链表 */
void print(List l)
{
if (l == NULL)
return;
printf ("%d ",Retrieve(l));
Position p = NextPosition(l);
while (p != l)
{
printf("%d ",Retrieve(p));
p = NextPosition(p);
}
printf("\n");
}
/* Josephus处理惩罚 */
void process(List l)
{
int n = N;
int m = M % n;
int i;
Position p = l;
while (n > 1)
{
if (m > n / 2)
{
for (i = 0; i < n - m + 1; i++)
p = PreviousPosition(p);
}
else
{
for (i = 0; i < m; i++)
p = NextPosition(p);
}
p = PreviousPosition(p);
printf ("%d out\n",Retrieve(NextPosition(p)));
Remove (NextPosition(p), &l);
n--;
m = M % n;
printf("current: ");
print(l);
}
}
测试功效:
1 2 3 4 5
4 out
current: 1 2 3 5
5 out
current: 1 2 3
3 out
current: 1 2
1 out
current: 2
这里给出轮回双链表数据布局 ADT和实现
假定链表不带哨兵节点。
dlinkedlist.h
typedef int ElementType;
#ifndef DLINKEDLIST_H_INCLUDED
#define DLINKEDLIST_H_INCLUDED
struct Node;
typedef struct Node *PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;
List CreateList (ElementType X);
void DisposeList(List L);
int IsEmpty(List L);
int IsLast(Position P, List L);
Position Find(ElementType X, List L);
void Delete(ElementType X, List L);
void Remove(Position P, List * L);
void Insert(ElementType X, List L, Position P);
void DeleteList(List L);
Position NextPosition(Position P);
Position PreviousPosition (Position P);
ElementType Retrieve(Position P);
#endif // DLINKEDLIST_H_INCLUDED
fatal.h
#ifndef FATAL_H_INCLUDED
#define FATAL_H_INCLUDED
#include <stdio.h>
#include <stdlib.h>
#define Error(Str) FatalError(Str)
#define FatalError(Str) fprintf(stderr, "%s\n", Str), exit(1)
#endif // FATAL_H_INCLUDED
dlist.c
#include "dlinkedlist.h"
#include "fatal.h"
struct Node
{
ElementType Element;
Position Next;
Position Prev;
};
List CreateList(ElementType X)
{
List L;
L = malloc(sizeof(struct Node));
if(L == NULL)
FatalError("Out of space!!!");
L- >Next = L->Prev = L;
L->Element = X;
return L;
}
void DisposeList(List L)
{
if(L->Next != L)
DeleteList(L);
free(L);
}
/* Return true if L is empty */
int IsEmpty(List L)
{
return L == NULL;
}
/* Return true if P is the last position in list L */
/* Parameter L is unused in this implementation */
int IsLast(Position P, List L)
{
return P == L;
}
/* Return Position of X in L; NULL if not found */
Position Find(ElementType X, List L)
{
if (L->Element == X)
return L;
Position P;
P = L->Next;
while(P != L && P- >Element != X)
P = P->Next;
if (P == L) //not found
P = NULL;
return P;
}
/* Delete from a list */
/* Cell pointed to by P->Next is wiped out */
/* Assume that the position is legal */
void Delete(ElementType X, List L)
{
Position P;
P = Find(X, L);
if (P != NULL)
Remove(P, &L);
}
void Remove (Position P, List * L)
{
if(P == *L)
{
if ((*L)->Next == *L)
{
free(*L);
*L = NULL;
return;
}
*L = (*L)->Next;
}
P->Prev->Next = P->Next;
P->Next ->Prev = P->Prev;
free(P);
}
/* Insert (after legal position P) */
/* Tailer implementation assumed */
/* Parameter L is unused in this implementation */
void Insert(ElementType X, List L, Position P)
{
Position TmpCell;
TmpCell = malloc(sizeof (struct Node));
if(TmpCell == NULL)
FatalError ("Out of space!!!");
TmpCell->Element = X;
TmpCell->Next = P->Next;
P->Next->Prev = TmpCell;
TmpCell->Prev = P;
P->Next = TmpCell;
}
void DeleteList(List L)
{
Position P, Tmp;
P = L->Next; /* Tailer assumed */
L->Next = L;
L- >Prev = L;
while(P != L)
{
Tmp = P->Next;
free( P );
P = Tmp;
}
}
Position NextPosition(Position P)
{
return P->Next;
}
Position PreviousPosition(Position P)
{
return P->Prev;
}
ElementType Retrieve(Position P)
{
return P->Element;
}
这里要留意的是函数Remove()
#p#分页标题#e#
void Remove(Position P, List * L)
{
if(P == *L)
{
if ((*L)->Next == *L)
{
free(*L);
*L = NULL;
return;
}
*L = (*L)->Next;
}
P->Prev->Next = P- >Next;
P->Next->Prev = P->Prev;
free(P);
}
List自己是一个指针,而这里选择List的指针,即指针的指针作为行参, 目标是当删除的节点是首元节点时,需要修改指针的值,即地点,所以通报指针的指针。就 好好比果需要修改int的值,则行参通报int *;同样假如需要修改int *的值,则行参通报 int **。