约瑟夫环问题-单向循环链表实现

约瑟夫环问题-单向循环链表实现



前言

代码可能存在不足,欢迎大家修改指正


一、约瑟夫环-题目描述

约瑟夫(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]);
	}
}

运行结果如下
在这里插入图片描述

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值