问题描述:
刚学数据结构的时候,我们可能用链表的方法去模拟这个过程,N个人看作是N个链表节点,节点1指向节点2,节点2指向节点3,……,节点N - 1指向节点N,节点N指向节点1,这样就形成了一个环。然后从节点1开始1、2、3……往下报数,每报到M,就把那个节点从环上删除。下一个节点接着从1开始报数。最终链表仅剩一个节点。它就是最终的胜利者。
举例:某天你去原始森林玩,碰到了一群土著邀请你去玩一个杀人游戏8个人围坐一圈,报数,报到3的人拿根绳吊死,问如何保命,笑到最后
思路分析:
该问题可以抽象为一个无头节点单向循环链表,链表中有8个节点,各节点中依次填入数据1,2,3,4,5,6,7,8
- 初始时刻,头指针指向1所在的节点
- 每隔2个节点,删除一个节点,需要注意的是删除节点前,要记录下一个节点的位置,所以要定义两个指针变量,一个指向当前节点,另一个指向当前节点的前一个节点,
- 删除节点节点前,记录要删除节点的下一个节点的位置
- 删除节点后当前节点指向删除节点的下一个节点
prenode->next = curnode->next;
printf("%d\t", curnode->data);
free(curnode);
curnode = prenode->next;
完整代码
main.c(用于测试)
#include<stdio.h>
#include<stdlib.h>
#include "list.h"
int main()
{
struct node_st *list = NULL,*lastnode =NULL;
list=list_create(SIZE);
list_show(list);
list_kill(&list, STEP);
list_show(list);
return 0;
}
list.c(用于函数定义)
#include<stdio.h>
#include<stdlib.h>
#include "list.h"
//约瑟夫环可以使用无头节点,单向循环链表来表示
struct node_st* list_create(int n)
{
int i = 1;
struct node_st* p = NULL;
struct node_st* ps = NULL;
struct node_st* q = NULL;
p = (struct node_st*)malloc(sizeof(struct node_st));
if (p == NULL)
{
return NULL;
}
p->data = i;
p->next = p;
i++;
//定义一个结构体变量,记录约瑟夫环起始位置
ps = p;
while (i <= n)
{
q = (struct node_st*)malloc(sizeof(struct node_st));
if (q == NULL)
{
return NULL;
}
q->data = i;
q->next = ps;
p->next = q;
p = q;
i++;
}
return ps;
}
void list_show(struct node_st* ps)
{
//一般来讲,我们不移动头指针ps,而是移动ps的拷贝,原因:
//出错时方便调试以及头指针位置不丢失
struct node_st* p = NULL;
for (p = ps; p->next != ps; p = p->next)
{
printf("%d\t", p->data);
}
printf("%d\n", p->data);
}
void list_kill(struct node_st** ps,int n)
{
struct node_st *prenode = NULL;
struct node_st *curnode = *ps;
int i = 0;
while (curnode != curnode->next)
{
//每轮删除,隔n-1个节点,删除一个节点
while (i < n - 1)
{
prenode = curnode;
curnode = curnode->next;
i++;
}
prenode->next = curnode->next;
printf("%d\t", curnode->data);
free(curnode);
curnode = prenode->next;
i = 0;
}
*ps = curnode;
printf("\n");
}
list.h(负责函数声明)
#ifndef LIST_H__
#define LIST_H__
#define SIZE 8
#define STEP 3
struct node_st
{
int data;
struct node_st *next;
};
//约瑟夫环的创建
struct node_st* list_create(int n);
//约瑟夫环的展示
void list_show(struct node_st*ps);
//约瑟夫环删除节点
void list_kill(struct node_st** ps,int n);
#endif