C语言循环单链表实现约瑟夫环(Josephus)问题

许南星
许南星
发布时间:2026-10-13| 5人浏览过
原创

本文介绍如何使用C语言和循环单链表解决经典的约瑟夫环问题。通过构建环形数据结构,模拟n个人围坐一圈并按特定规则淘汰的过程,提供完整的源码逻辑与实现细节。

约瑟夫环问题描述

约瑟夫环(Josephus Problem)是一个著名的数学应用题。假设有 n 个人围坐在一个圆桌周围,从第 s 个人开始报数,数到第 m 的那个人出列;他的下一位又从 1 开始报数,数到第 m 的人又出列,依此规律重复下去,直到圆周围的人全部出列。本方案的目标是设计一个程序,确定这 n 个人的出列次序序列。

算法设计思路

由于参与者是围成一圈运动的,使用具有“回环”特性的结构最为合适,因此选择循环单链表作为核心存储结构。

  1. 节点定义:每个节点包含编号(number)和指向下一个节点的指针(pNext)。
  2. 链表构建:将 n 个节点依次连接,最后将尾节点的 pNext 指向头节点,形成闭环。
  3. 位置定位:链表的起始头指针默认指向第一个节点。要找到从第 s 个人开始的位置,需要遍历链表找到对应节点。
  4. 淘汰逻辑:
  • 进行 n 轮循环,每轮淘汰一人。
  • 在每一轮中,移动指针 m-1 次,此时当前指针指向的就是待淘汰者。
  • 输出淘汰者的编号,并将其标记为已出列(如设为0),防止后续再次被选中。
  • 调整指针至下一个有效节点,准备下一轮报数。

C语言源代码实现

以下代码实现了上述逻辑。程序首先创建循环单链表,然后根据用户输入的 n、s、m 三个变量计算并打印出列顺序。注意,代码中使用了 malloc 动态分配内存。

#include <stdio.h>
#include <malloc.h>

typedef struct Node
{
	int number;
	struct Node * pNext;
}NODE, *PNODE;

// 函数声明
PNODE creat_list(int n);

int main (void)
{
	int n, m, s;
	printf("约瑟夫环问题:\n");
	printf("设有n(编号为 0 1 2 ... n-1)个人围坐一圈,现从第s个人开始报数,数到m的人出列,\n求最后的出列顺序。\n");
	printf("请设置n, s, m :\n");
	printf("n = ");
	scanf("%d", &n);
	printf("s = ");
	scanf("%d", &s);
	printf("m = ");
	scanf("%d", &m);                    // 获取问题参数

	PNODE pHead = NULL;
	pHead = creat_list(n); 
    if (pHead == NULL) return 0;
    pHead->number = 1;                   // 初始化头节点编号,确保闭环正确性

	PNODE p = pHead;                       // 工作指针
	int i, j, k;

	// 第一步:移动指针到起始位置(第s个人)
	for(j = 1; j < s; j++)
	{
		p = p->pNext;
	}

	// 第二步:逐个淘汰,直到所有人都出列
	for(i = 1; i <= n; i++)               
	{
		// 内部循环:寻找第m个待出列的人
		for(k = 1; k < m; )              
		{
			// 检查下一个节点是否已经出列
			if(p -> pNext -> number != 0)
			{
				p = p -> pNext;
				k++;
			}
			else
			{
				// 如果下一个节点已出列,跳过该节点继续找下一个有效的
				p = p -> pNext;
			}
		}
		// 输出当前淘汰者的编号
		printf("%d  ", p -> number);
		// 标记为已出列
		p -> number = 0;
		
		// 寻找下一个还未出列的节点,准备下一轮
		do
		{
		    p = p -> pNext;
		}while(p -> number == 0); 
	}
	printf("\n");
	
	return 0;
}

// 创建循环单链表
PNODE creat_list(int n)                        
{
	PNODE pHead = (PNODE)malloc(sizeof(NODE));
    if (!pHead) return NULL;
    PNODE pTail = pHead;
	int i;
    // 生成其余节点并链接成环
    for(i = 2; i <= n; i++)
	{
		PNODE pNew = (PNODE)malloc(sizeof(NODE));
		if (!pNew) break;
		pNew->number = i;
		pTail->pNext = pNew;
		pNew->pNext = pHead; // 关键:构成循环
		pTail = pNew;
	}
	return pHead;
}

代码逻辑关键点解析

  • 闭环构建:creat_list 函数中,新节点创建后立即将其 pNext 指向头节点 pHead,这是实现循环操作的基础。
  • 跳过出列者:在 for(k = 1; k < m;) 循环中,判断条件 p -> pNext -> number != 0 确保了如果下一个人已经出局,指针会继续向后移,直到找到一个状态正常的节点才算作一次有效的计数。
  • 更新起点:每次淘汰后,代码通过 do-while 循环直接跳过所有已标记为 0 的节点,保证下一轮报数是从最近的活人开始的。

总结

通过循环单链表处理约瑟夫环问题,能够直观地反映物理世界中“围圈”的特性。该方法的时间复杂度取决于具体的实现细节,但通过合理的指针移动逻辑,可以高效地模拟出局过程。以上就是C语言循环单链表实现约瑟夫环问题的详细内容,更多关于C语言数据结构算法的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。