约瑟夫环问题(Josephus)
原题:
用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。写出C程序。(约瑟夫环问题 Josephus)
提示:
data:18467
data:6334
data:26500
data:19169
data:15724
data:11478
data:29358
data:26962
data:24464
data:5705
data:28145
data:23281
data:16827
data:9961
data:491
data:2995
data:11942
data:4827
data:5436
input m and n:
3 4
data:26500
data:29358
data:28145
data:491
data:5436
data:19169
data:24464
data:9961
data:41
data:11478
data:16827
data:18467
data:5705
data:4827
data:23281
data:15724
data:6334
data:26962
data:11942
data:2995
原题:
用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。写出C程序。(约瑟夫环问题 Josephus)
提示:
由于当某个人退出圆圈后,报数的工作要从下一个人开始继续,剩下的人仍然是围成一个圆圈的,可以使用循环表,由于退出圆圈的工作对应着表中结点的删除操作,对于这种删除操作频繁的情况,选用效率较高的链表结构,为了程序指针每一次都指向一个具体的代表一个人的结点而不需要判断,链表不带头结点。所以,对于所有人围成的圆圈所对应的数据结构采用一个不带头结点的循环链表来描述。设头指针为p,并根据具体情况移动。
下面是我写的一种答案,对内存有两种申请方式,一种是懒汉方式,一种是饱汉方式,大家可以自行确定,只是要注意其释放内存的差别。
#include <process.h>
#include <stdio.h>
#include <stdlib.h>
#define DATALEN 20
typedef enum eret
{
SUCCESS,
ERROR_MEMORY
}eret;
typedef struct list_node
{
int data;
list_node* next;
}list_node;
/*
*懒汉方式,需要时才申请内存
*/
eret init_list_node_one(list_node* &pListIn,int len)
{
int tmp = 0;
list_node* iterator = NULL;
pListIn = (list_node*)malloc(sizeof(list_node));
iterator = pListIn;
tmp = rand();
iterator->data = tmp;
iterator->next = iterator;
for (int i = 0;i < len -1;i++)
{
tmp = rand();
list_node* p = (list_node*)malloc(sizeof(list_node));
if (!p)
{
printf("error memory\n");
return ERROR_MEMORY;
}
p->data = tmp;
iterator->next = p;
p->next = pListIn;
iterator = p;
}
return SUCCESS;
}
/*
*饱汉方式,一次申请足够的内存
*/
eret init_list_node_two(list_node* &pListIn,int len)
{
int tmp = 0;
list_node* iterator = NULL;
pListIn = (list_node*)malloc(len * sizeof(list_node));
iterator = pListIn;
for (int i = 0; i < len; i++)
{
tmp = rand();
iterator->data = tmp;
if (i < len - 1)
{
iterator->next = iterator + 1;
iterator = iterator->next;
}
iterator->next = pListIn;
}
return SUCCESS;
}
/*
*懒汉方式时的约瑟夫循环查找,找到一个就释放其内存,
*注意还有最后一个在循环结束后打印
*/
eret josephos_one(list_node* node,int m,int n)
{
m %= n;
list_node* m_pList = node;
while (m_pList != m_pList->next)
{
for (int i = 0; i < m-1;i++)
{
m_pList = m_pList->next;
}
printf("data:%d\n",m_pList->next->data);
list_node* tmp = m_pList->next;
m_pList->next = tmp->next;
m_pList = m_pList->next;
free(tmp);
}
printf("data:%d\n",m_pList->data);
free(m_pList);
return SUCCESS;
}
/*
*饱汉方式时的约瑟夫循环查找,先不释放其内存,
*注意还有最后一个在循环结束后打印
*/
eret josephos_two(list_node* node,int m,int n)
{
m %= n;
list_node* m_pList = node;
while (m_pList != m_pList->next)
{
for (int i = 0; i < m-1;i++)
{
m_pList = m_pList->next;
}
printf("data:%d\n",m_pList->next->data);
list_node* tmp = m_pList->next;
m_pList->next = tmp->next;
m_pList = m_pList->next;
//free(tmp);
}
printf("data:%d\n",m_pList->data);
//free(m_pList);
return SUCCESS;
}
eret display(list_node* node)
{
list_node* m_pList = node;
printf("data:%d\n",m_pList->data);
m_pList = m_pList->next;
while (m_pList != node)
{
printf("data:%d\n",m_pList->data);
m_pList = m_pList->next;
}
return SUCCESS;
}
int main(int argc, char* argv[])
{
list_node *node;
int m = 0,n = 0;
eret ret = init_list_node_two(node,DATALEN);
if (ret != SUCCESS)
{
printf("init_list_node error,%d\n",__LINE__);
return -1;
}
display(node);
printf("input m and n:\n");
scanf("%d%d",&m,&n);
ret = josephos_two(node,m,n);
if (ret != SUCCESS)
{
printf("josephos error,%d\n",__LINE__);
return -2;
}
//这里的free是针对第二种内存申请的释放,貌似对于内存的申请是整取就需要整放
free(node);
system("pause");
return 0;
}
data:41
data:18467
data:6334
data:26500
data:19169
data:15724
data:11478
data:29358
data:26962
data:24464
data:5705
data:28145
data:23281
data:16827
data:9961
data:491
data:2995
data:11942
data:4827
data:5436
input m and n:
3 4
data:26500
data:29358
data:28145
data:491
data:5436
data:19169
data:24464
data:9961
data:41
data:11478
data:16827
data:18467
data:5705
data:4827
data:23281
data:15724
data:6334
data:26962
data:11942
data:2995