循环链表解决Josephus问题

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

#define CL_SUCCESS    0
#define CL_NO_MEM     1
#define CL_EMPTY      2
#define CL_ZERO_SIZE  3

typedef struct CL_ITEM{
int Tag;
struct CL_ITEM *Prev, *Next;
void *Object;
size_t Size;
}CL_ITEM;

typedef struct CLIST{
CL_ITEM *CurrentItem;
size_t   NumItems;
}CLIST;
//创建结点
CL_ITEM *CLCreate(int Tag, void *Object, size_t Size){
CL_ITEM *NewItem;
if(Size > 0){
  NewItem = (CL_ITEM *)malloc(sizeof *NewItem);
  if(NewItem != NULL){
   NewItem->Prev = NewItem->Next = NULL;
   NewItem->Tag = Tag;
   NewItem->Size = Size;
   NewItem->Object = (void*)malloc(Size);
   if(NewItem->Object == NULL){
    free(NewItem);
    NewItem = NULL;
   }else{
    memcpy(NewItem->Object, Object, Size);
   }
  }
}
return NewItem;
}
//向循环链表List中添加新元素
int CLAddItem(CLIST *List, int Tag, void *Object, size_t Size){
CL_ITEM *NewItem;
int Result = CL_SUCCESS;
assert(List != NULL);
//为新结点分配需要的内存空间
NewItem = CLCreate(Tag, Object, Size);
if(NewItem == NULL){
  Result = CL_NO_MEM;
}else{
  ++List->NumItems;
  //List empty
  if(List->CurrentItem == NULL){
   List->CurrentItem = NewItem;
   List->CurrentItem->Next = NewItem;
   List->CurrentItem->Prev = NewItem;
  }else{
   NewItem->Prev                 = List->CurrentItem->Prev;
   NewItem->Next                 = List->CurrentItem;
   List->CurrentItem->Prev->Next = NewItem;
   List->CurrentItem->Prev       = NewItem;
  }
}
return Result;
}
//更新循环链表指定结点的值
int CLUpdate(CLIST *List,int NewTag,void *NewObject,size_t NewSize){
int Result = CL_SUCCESS;
void *p;

assert(List != NULL);
if(NewSize > 0){
  //is empty?
  if(List->NumItems > 0){
   //重新分配空间
   p = realloc(List->CurrentItem->Object, NewSize);
   if(NULL != p){
    List->CurrentItem->Object = p;
    memmove(List->CurrentItem->Object, NewObject, NewSize);
    List->CurrentItem->Tag    = NewTag;
    List->CurrentItem->Size   = NewSize;
   }else{
    Result = CL_NO_MEM;
   }
  }else{
   Result = CL_EMPTY;
  }
}else{
  Result = CL_ZERO_SIZE;
}
return Result;
}
//得到链表中指定元素的值
void *CLGetData(CLIST *List,int *Tag,size_t *Size){
void *p = NULL;
assert(List != NULL);

if(List->CurrentItem != NULL){
  if(Tag != NULL){
   *Tag = List->CurrentItem->Tag;
  }
  if(Size != NULL){
   *Size = List->CurrentItem->Size;
  }
  p = List->CurrentItem->Object;
}
return p;
}
//旋转表
void CLRotate(CLIST *List, int Places){
int Multiple;
int i;
assert(List != NULL);
//判断表是否为空表
if(List->NumItems > 0){
  if(Places < 0){
   Multiple = (List->NumItems - 1 - Places) / List->NumItems;
   Places += Multiple * List->NumItems;
  }
  Places %= List->NumItems;
  //倒序转
  if(Places > (int)List->NumItems / 2){
   Places = List->NumItems - Places;
   for(i = 0; i < Places; i++){
    List->CurrentItem = List->CurrentItem->Prev;
   }
  }else{
   //顺序转
   for(i = 0; i < Places; i++){
    List->CurrentItem = List->CurrentItem->Next;
   }
  }
}
}
//删除循环链表中的结点
int CLDelete(CLIST *List){
int Deleted = 0;
CL_ITEM *PrevItem, *NextItem, *ThisItem;
assert(List != NULL);

if(List->NumItems > 0){
  Deleted = 1;

  ThisItem = List->CurrentItem;
  free(ThisItem->Object);
  NextItem = ThisItem->Next;
  PrevItem = ThisItem->Prev;
  //如果循环链表中只存在一个元素,将表置为空表
  if(1 == List->NumItems){
   List->CurrentItem = NULL;
  }else{
   //把结点从循环链表中摘掉
   List->CurrentItem = NextItem;
   NextItem->Prev = PrevItem;
   PrevItem->Next = NextItem;
  }
  //释放
  free(ThisItem);
  //结点个数-1;
  --List->NumItems;
}
return Deleted;
}
//清空循环链表
void CLDestroy(CLIST *List){
assert(List != NULL);
while(CLDelete(List)){
  continue;
}
}
//访问循环链表
int CLWalk(CLIST *List,int(*Func)(int, void *, void *),void *Args){
CL_ITEM *ThisItem;
int i, Result = 0;
assert(List != NULL);

for(ThisItem = List->CurrentItem, i = 0;!Result && i < (int)List->NumItems;ThisItem = ThisItem->Next, i++){
  Result = (*Func)(ThisItem->Tag,ThisItem->Object,Args);
}
return Result;
}
//以下测试程序来自C语言教科书,用于解决Josephus问题.
int _tmain(int argc, _TCHAR* argv[])
{
char *Intro[] = {
  "This Josephus Problem",
  "---------------------",
  " ",
  "Consider a ring of N items. If the Kth item",
  "is eliminated, there will now be N-1 items.",
  "If this procedure is performed iteratively",
  "eventually there will be just one item",
  "remaining. Which is it?",
  " ",
  "This program provides the answer.",
  " ",
  NULL
};
char **Text;
char buffer[32];
char *endp;
CLIST Circle = {0};
int Result = EXIT_SUCCESS;
unsigned long N, K, i;
for(Text = Intro; *Text != NULL; ++Text){
  puts(*Text);
}

puts(" \nHow many items in the ring?");
if(fgets(buffer, sizeof buffer, stdin) == NULL){
  puts("Program aborted .");
  exit(EXIT_SUCCESS);
}
N = strtoul(buffer, &endp, 10);
if(buffer == endp || N == 0){
  puts("Program aborted.");
  Result = EXIT_FAILURE;
}else{
  puts("Count how many items before removing one?");
  if(fgets(buffer, sizeof buffer, stdin) == NULL){
   puts("Program aborted.");
   exit(EXIT_FAILURE);
  }
  K = strtoul(buffer, &endp, 10);
  if(buffer == endp || K == 0){
   puts("Program aborted.");
   exit(EXIT_FAILURE);
  }
}

for(i = 0; Result == EXIT_SUCCESS && i < N; i++){
  if(CLAddItem(&Circle, 0, &i, sizeof i) != CL_SUCCESS){
   printf("Insufficient memory. Sorry. \n");
   Result = EXIT_FAILURE;
  }
}

if(Result == EXIT_SUCCESS){
  while(Circle.NumItems > 1){
   CLRotate(&Circle, K);
   printf("Removing item %lu. \n", *(unsigned long *)CLGetData(&Circle, NULL, NULL));

   CLDelete(&Circle);

   CLRotate(&Circle, -1);
  }
  printf("The last item is %lu .\n", *(unsigned long*)CLGetData(&Circle, NULL, NULL));
}


CLDestroy(&Circle);

return Result;
}

你可能感兴趣的:(OS)