循环链表经常与约瑟夫问题涉及在一起,在解决约瑟夫问题之前,如果了解了循环链表(这里当然是指单向的了,不要想复杂了),那么约瑟夫问题就比较好解决了。
1,循环链表的建立,打印。
这里为了简单,只是开辟了5个空间,然后将其打印。
#include <stdio.h>
#include <stdlib.h>
typedef struct Link {
int k;
struct Link *next;
}Link, *LinkPoint;
LinkPoint create() //建立循环链表
{
LinkPoint head,p1,p2;
int i, n=0;
for(i=0; i<5; i++)
{
p1 = (LinkPoint)malloc(sizeof(Link));
if(n == 0)
{
p2 = head = p1;
p1->k = i+1;
p1->next = NULL;
n = 1;
}
else
{
p1->k = i+1;
p1->next = NULL;
p2->next = p1;
p2 = p1;
}
}
p2->next = head;
return head;
}
void print(LinkPoint head) //打印出来
{
LinkPoint p;
p = head;
if(head != NULL)
{
do{
printf("uuu %d\n",p->k);
p = p->next;
}while(p->next != head);
printf("uuu %d\n",p->k);
}
}
int main()
{
LinkPoint list;
list = create();
print(list);
return 0;
}
一个简单的循环链表完成了,下面就一个简单的题目来进入约瑟夫问题吧。
2,13个人围成一圈,从第1个人开始顺序报号1、2、3。凡报导3者退出圈子。找出最后留在圈子中的人原来的序号。
#include <stdio.h>
#include <stdlib.h>
typedef struct Link {
int k;
struct Link *next;
}Link, *LinkPoint;
LinkPoint create(int num) //建立循环链表
{
LinkPoint head,p1,p2;
int i, n=0;
for(i=0; i<num; i++)
{
p1 = (LinkPoint)malloc(sizeof(Link));
if(n == 0)
{
p2 = head = p1;
p1->k = i+1;
p1->next = NULL;
n = 1;
}
else
{
p1->k = i+1;
p1->next = NULL;
p2->next = p1;
p2 = p1;
}
}
p2->next = head;
return head;
}
void print(LinkPoint head) //打印出来
{
LinkPoint p;
p = head;
if(head != NULL)
{
do{
printf("uuu %d\n",p->k);
p = p->next;
}while(p->next != head);
printf("uuu %d\n",p->k);
}
}
int playGame(LinkPoint head)
{
LinkPoint p1,p2;
int i = 1;
int num = 13;
p1 = p2 = head;
while(num != 1)
{
p1 = p1->next;
i++;
if(i == 3)
{
p2 = p2->next;
p2->next = p1->next;
free(p1); //p1指向的内存释放掉,但p1指针还没有消失
p1 = p2->next;
p2 = p1;
i = 1;
num--;
}
}
return p1->k;
}
int main()
{
LinkPoint list;
int last;
list = create(13);
print(list);
last = playGame(list);
printf("last num is %d\n",last);
return 0;
}
假如从第几个人开始是未知的,可以从第2个人开始数,从第3个人开始数,又比如说总共有几个人来参与这个游戏,都是未知,由我们来确定的话,只需要修改函数的参数就够了,整体框架不用再改变。如:
#include <stdio.h>
#include <stdlib.h>
typedef struct Link {
int k;
struct Link *next;
}Link, *LinkPoint;
LinkPoint create(int num) //建立循环链表
{
LinkPoint head,p1,p2;
int i, n=0;
for(i=0; i<num; i++)
{
p1 = (LinkPoint)malloc(sizeof(Link));
if(n == 0)
{
p2 = head = p1;
p1->k = i+1;
p1->next = NULL;
n = 1;
}
else
{
p1->k = i+1;
p1->next = NULL;
p2->next = p1;
p2 = p1;
}
}
p2->next = head;
return head;
}
int playGame(LinkPoint head, int start, int total)
{
LinkPoint p1,p2,r;
int i = 1;
//int num = 13;
start -= 1;
//p1 = p2 = head;
r = head;
while(start--)
r = r->next;
p1 = p2 = r;
while(total != 1)
{
p1 = p1->next;
i++;
if(i == 3)
{
p2 = p2->next;
p2->next = p1->next;
free(p1); //p1指向的内存释放掉,但p1指针还没有消失
p1 = p2->next;
p2 = p1;
i = 1;
total--;
}
}
return p1->k;
}
int main()
{
LinkPoint list;
int last;
list = create(13);
last = playGame(list,2,13);
printf("last num is %d\n",last);
return 0;
}
当然可以根据自己再次修改,可以添加输入,这样就不用每次修改参数还要重新编译。