约瑟夫约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围,从编号为1的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。通常解决这类问题时我们把编号从1~n,最后结果即为原问题的解。
在下面的例子中,我就先以5人的约瑟夫环进行测试:
约瑟夫环问题,你可以用顺序表解决,你也可以用双链表来解决,在时间复杂度上,毋庸置疑,肯定是双莲表复杂度底,那就以双链表为例吧!
假设你拿到一个已经初始化的双链表,那么肯定对这个双链表加工成为环:只需标记尾部tmp,然后tmp->next = phead->next; phead->next->pre = tmp;这一步主要让双联表成环。下来就是杀人了。
假设是第一个人,报数从1开始,每次报到 m 的人就被杀死,对应到链表里就是每走 m-1 步后指向的结点被删除,(用简单的5个人,报到3的人退出,p刚开始指向头节点的下个结点--首元结点,p往后走2步,到达的结点就该被删除,)
最后你这个循环的终止条件为4自己指向自己或者phead的id变成计数,
phead->id == 1终止,那么就剩代码了!
代码:
D_JOSEPH.h
#ifndef _D_JOSEPH_H_
#define _D_JOSEPH_H_
typedef int elem_type;
typedef struct _NODE
{
elem_type id;
struct _NODE *next;
struct _NODE *pre;
}NODE;
NODE * init_double_list();
bool insert_head(NODE *phead,elem_type id);
NODE *CreateLoopList(int num);
int Kill(NODE *phead, int gap);
#endif
D_JOSEPH.cpp
#include"D_JOSEPH.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#define ERROR -1
static int getlength(NODE *phead)
{
NODE *p = phead;
int i = 0;
if(phead == NULL)
{
return ERROR;
}
while(p->next)
{
i++;
p = p->next;
}
return i;
}
static NODE *alloc(elem_type e)
{
NODE *tmp = (NODE *)malloc(sizeof(NODE));
assert(tmp != NULL);
tmp->id = e;
tmp->next = NULL;
tmp->pre = NULL;
return tmp;
}
NODE * init_double_list()
{
NODE *phead = (NODE *)malloc(sizeof(NODE));
assert(phead != NULL);
phead->id = 0;
phead->next = NULL;
phead->pre = NULL;
return phead;
}
bool insert_head(NODE *phead,elem_type id)
{
NODE *tmp = alloc(id);
if(phead == NULL)
{
return false;
}
tmp->next = phead->next;
if(phead->next != NULL)//是空表
{
phead->next->pre = tmp;
}
phead->next = tmp;
tmp->pre = phead;
phead->id ++;
return true;
}
NODE *CreateLoopList(int num)
{
NODE *phead = init_double_list();
NODE *tmp = alloc(num);
phead->next = tmp;
tmp->pre = phead;
phead->id ++;
for(int i = num-1;i>= 1;i --)
{
insert_head(phead,i);
}
tmp->next = phead->next;//双链表成环
phead->next->pre = tmp;
return phead;
}
int Kill(NODE *phead, int gap)
{
NODE *p = phead->next;
NODE *s = phead->next;
if(phead == NULL)
{
return ERROR;
}
while(p->next != p)
{
for(int i = 0;i < gap-1;i ++)
{
p = p->next;
}
s = p;
p->pre->next = p->next;
p->next->pre = p->pre;
p = p->next;
printf("id-%d被杀\n",s->id);
phead->id--;
free(s);
}
int rs = p->id;
free(p);
free(phead);
return rs;
}
main.cpp
#include<stdio.h>
#include"D_JOSEPH.h"
int main()
{
int m = 13;//总数
int ag = 3;//按照多少来报数
NODE *phead = CreateLoopList(m);//成环函数
int i = Kill(phead,3);
printf("最后活着的人id-%d\n",i);
return 0;
}
结果: