一、单向循环链表
单向循环链表也称约瑟夫链表。据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
二、用C语言实现单向循环链表
1、构造存储结构
typedef int datatype;
typedef struct josephus
{
datatype data; /* 数据域 */
struct josephus *next; /* 指针域 */
}josephus_list, *josephus_plist;
2、初始化
初始化主要工作:①申请头结点空间;②
head->next=head
/* 初始化 */
void init_josephus_list(josephus_plist *list)
{
*list = (josephus_plist)malloc(sizeof(josephus_list));
if(NULL == *list)
{
printf("内存申请失败\n");
perror("malloc"); /* 打印内存申请失败原因 */
exit(1);
}
(*list)->next = *list; /* 将next设为NULL,建立空链表 */
}
3、插入
void insert_josephus_list(josephus_plist head, josephus_plist new)
{
new->next = head->next;
head->next = new;
}
4、删除
删除结点和单向链表的删除思想一样。
void delete_josephus_list(josephus_plist pnode)
{
josephus_plist dnode;
dnode = pnode->next;
pnode->next = dnode->next;
free(dnode);
}
5、判断链表是否为空
即判断
head
是否等于head->next
/* 判断是否为空 */
bool isempty(josephus_plist head)
{
if(head == head->next)
{
return true;
}
else
{
return false;
}
}
5、打印链表
void show_josephus_list(josephus_plist head)
{
josephus_plist p = NULL;
for(p = head; p->next != head; p = p->next)
{
printf("%d\t", p->data);
}
printf("%d\n", p->data);
}
三、练习题:实现约瑟夫环
1、创建链表
/* 创建单向循环链表 */
void create_josephus_list(josephus_plist head)
{
josephus_plist new = NULL;
josephus_plist p = head;
int len = 0;
int i = 0;
printf("输入要插入数据的个数:");
scanf("%d", &len);
for(i = 0; i < len; i++)
{
if (0 == i)
{
scanf("%d", &(head->data));
}
else
{
new = (josephus_plist)malloc(sizeof(josephus_list));
if(NULL == new)
{
printf("内存申请失败\n");
perror("malloc");
exit(1);
}
printf("输入要插入的第%d个数据:", (i+1));
scanf("%d", &(new->data));
insert_josephus_list(p, new);
p = p->next;
}
show_josephus_list(head); /* 打印 */
}
}
2、实现约瑟夫
/* n是第n个要删除的结点 */
void josephus(josephus_plist head, int n)
{
int i = 0;
josephus_plist p = head;
while(p != p->next)
{
for(i = 0; i < n-2; i++)
{
p = p->next;
}
printf("-->%d", p->next->data);
delete_josephus_list(p);
p = p->next;
}
printf("-->%d\n", p->data);
}
3、main函数
int main(void)
{
josephus_plist head = NULL; /* 定义一个头指针 */
init_josephus_list(&head); /* 初始化 */
create_josephus_list(head); /* 创建单向链表 */
josephus(head, 3);
return 0;
}
4、实验结果