约瑟夫环问题-单向循环链表实现
前言
代码可能存在不足,欢迎大家修改指正
一、约瑟夫环-题目描述
约瑟夫(joseph):
编号为1,2,。。。,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他在顺时针方向的下一个人开始重新从1报数,如此下去,直到所有人全部出列为止。试设计一个程序显示出列顺序。
〖基本要求〗:利用单向循环链表存储结构模拟此过程,按照出列的顺序打印出各人的编号。
〖测试数据〗:m的初值为20,密码:3,1,7,2,4,8,6
〖结果为〗:出列编号:6,1,4,7,5,3,2
二、解题思路
首先建立一个链表,进行链表初始化
其中需要对每个人的位置下标及所带密码值进行初始化
LinkList inti_list(int* key, int n) //循环链表初始化
{
LinkList palist = (LinkList)malloc(sizeof(struct node));
PNode p;
int i, j = 1;
p = create_node();
if (p) //初始化每个人所带的密码值 ,即这个人出队后下一轮的循环次数
{
p->key = key[0];
p->link = NULL;
palist = p;
}
for (i = 1; i < n; i++)
{
PNode q = create_node();
if (q) {
q->key = key[i];
p->link = q;
q->link = NULL;
p = q;
}
}
if (i == 7) {
p->link = palist;
}
PNode t = palist;
while (t->link != palist) //初始化每个人的位置值
{
t->info = j;
j++;
t = t->link;
}
t->info = 7;
return palist;
}
递归思想,写一个出队函数循环调用直到最后一个人出队
以队伍中的人数作为函数需调用的次数,每找到一个需要出队的人,就把他的密码值保留下来作为函数参数,进行下一轮循环
void jose_out(LinkList palist, int m, int n)
{
if (n > 0)
{
PNode p = palist;
for (int i = 0; i < m - 2; i++) p = p->link; //找即将出队元素的前驱结点p
printf("\nout element is %d\n", p->link->info);
res[count++] = p->link->info;
int next_m = p->link->key; //将出队元素的密钥值保留作出队函数的参数,以便下一轮循环
printf("下一轮循环次数%d,", next_m);
p->link = p->link->link;
palist = p->link;
printf("下一个开始位置:%d\n", palist->info);
--n;
jose_out(palist, next_m, n); //以新密码值做参数,再次调用出队函数
}
}
三、完整代码与运行结果
#include<stdio.h>
#include<stdlib.h>
int count = 0;
int res[7];
typedef struct node* PNode;
struct node {
int info;
int key;
PNode link;
};
typedef struct node* LinkList;
PNode create_node() //新建结点函数
{
PNode q = (PNode)malloc(sizeof(struct node));
if (q == NULL) return NULL;
else return q;
}
LinkList inti_list(int* key, int n) //循环链表初始化
{
LinkList palist = (LinkList)malloc(sizeof(struct node));
PNode p;
int i, j = 1;
p = create_node();
if (p) //初始化每个人所带的密钥值 ,即这个人出队后下一轮的循环次数
{
p->key = key[0];
p->link = NULL;
palist = p;
}
for (i = 1; i < n; i++)
{
PNode q = create_node();
if (q) {
q->key = key[i];
p->link = q;
q->link = NULL;
p = q;
}
}
if (i == 7) {
p->link = palist;
}
PNode t = palist;
while (t->link != palist) //初始化每个人的位置值
{
t->info = j;
j++;
t = t->link;
}
t->info = 7;
return palist;
}
void jose_out(LinkList palist, int m, int n)
{
if (n > 0)
{
PNode p = palist;
for (int i = 0; i < m - 2; i++) p = p->link; //找即将出队元素的前驱结点p
printf("\nout element is %d\n", p->link->info);
res[count++] = p->link->info;
int next_m = p->link->key; //将出队元素的密钥值保留作出队函数的参数,以便下一轮循环
printf("下一轮循环次数%d,", next_m);
p->link = p->link->link;
palist = p->link;
printf("下一个开始位置:%d\n", palist->info);
--n;
jose_out(palist, next_m, n);
}
}
int main()
{
int m = 20;
int key[7] = { 3,1,7,2,4,8,6 };
LinkList list = inti_list(key, 7);
printf("出队过程如下:\n");
jose_out(list, m, 7);
printf("\n所以出队顺序为:\n");
for (int i = 0; i < 7; i++)
{
printf("%d\t", res[i]);
}
}
运行结果如下