思想和单向循环一样,只需要将双向链表尾的next和头的prior双向链接即可。
#include <stdio.h>
#include <stdlib.h>
typedef int datatype;
typedef struct node_t
{
datatype data;
struct node_t *prior;
struct node_t *next;
} node_t, *node_p;
typedef struct doublelinklist
{
node_p head;
node_p tail;
} double_link_t, *double_link_p;
// 无头 双向 循环链表 解决 约瑟夫问题
int main(int argc, const char *argv[])
{
int i;
int all_num = 6; //猴子总数
int start_num = 1; //从1号猴子开始数
int kill_num = 5; //数到几杀死猴子
node_p h = NULL;
node_p pdel = NULL; //用来指向被杀死猴子的节点
//1.创建一个操作 无头双向的循环链表 的结构体
double_link_p p = (double_link_p)malloc(sizeof(double_link_t));
if (NULL == p)
{
perror("malloc failed");
return -1;
}
// 申请第一个结点,用 头指针和尾指针 指向其
p->head = p->tail = (node_p)malloc(sizeof(node_t));
if (NULL == p->tail)
{
perror("p->tail malloc failed");
return -1;
}
// 给第一个结点 初始化
p->head->data = 1; //初值为1
p->head->prior = NULL;
p->head->next = NULL;
//将创建n个新的节点,链接到链表的尾
for (i = 2; i <= all_num; i++)
{
node_p pnew = (node_p)malloc(sizeof(node_t));
if (NULL == pnew)
{
perror("pnew malloc failed");
return -1;
}
// 初始化赋值
pnew->data = i;
pnew->prior = NULL;
pnew->next = NULL;
//(1)将新的节点链接到链表的尾
p->tail->next = pnew;
pnew->prior = p->tail;
//(2)尾指针向后移动,指向当前链表的尾
p->tail = pnew;
}
// 1 2 3 4 5 6 创建完成
//(3)形成双向循环链表
p->tail->next = p->head;
p->head->prior = p->tail;
#if 1
//调试程序,看看有几个猴子
node_p ptemp_debug = p->head;
printf("now has: ");
while (ptemp_debug != p->tail)
{
printf("%d ", ptemp_debug->data);
ptemp_debug = ptemp_debug->next;
}
putchar(10);
#endif
//2.循环进行杀死猴子
h = p->head;
//(1)先将h移动到start_num处,也就是开始数数的猴子号码处
// -1 因为 从1开始编号
for (i = 0; i < start_num - 1; i++)
h = h->next;
while (h->next != h) //当h->next == h 就剩一个节点了,循环结束
{
//(2)将h移动到即将杀死猴子号码的位置
// -1 因为 从1开始编号
// 双向结点,可以直接移动到目标位置操作
for (i = 0; i < kill_num - 1; i++)
h = h->next;
//(3)进行杀死猴子,经过上面的循环后,此时的h指向即将杀死的猴子
h->prior->next = h->next;
h->next->prior = h->prior;
printf("kill is -------%d\n", h->data);
//pdel指向被杀死猴子的位置
pdel = h;
h = h->next; //需要移动,从杀死猴子后的下一个位置开始数
free(pdel);
}
printf("猴王是%d\n", h->data);
return 0;
}