约瑟夫问题——循环链表C++

  • 什么是约瑟夫问题?

约瑟夫问题是一个有名的问题,编号为1-N的N个人安顺时针围坐一圈,选取M为报数的上限,从第一个人按顺时针开始报数,将第M个人出列,,下一个人继续从1开始报数,报到M的人再出列,直至所有的人全部出列为止。

  • 循环链表:

循环链表与单链表一样,是一种链式的存储结构。区别在于循环链表的最后一个节点的指针指向该循环链表的第一个节点或头结点,从而形成一个环。在建立一个循环链表的时候,要注意以下几点:

1、建立循环链表的时候,必须要让其最后一个节点指向链表的第一个节点或头结点,而不像单链表将租后节点的下一个指向NULL;

2、判断循环链表是否到表尾的方法是采用判断该节点的链域值(下一个节点的地址)是否是表头节点的方法,即当链域值等于表头指针时,说明已到链尾,而不像单链表中判断链域值是否为NULL。

  • 用循环链表来解答约瑟夫问题:
当有人出列之后,报数要从下一个继续开始,剩余的人仍然围成一个圈,所以可以使用循环链表。出列的工作对应表中的节点被删除;为了使链表中的每个节点对应一个具体的人的节点,因此链表不带头结点。因此,对于所有人围成的圆圈所对应的数据结构可采用一个不带头结点的循环链表来实现。

为记录退出的人的先后顺序,采用一个顺序表进行存储。程序结束后在输出依次出列的人的编号。

程序代码如下:

//约瑟夫问题

#include <iostream>
using namespace std;

struct Node 
{
	int data;
	Node *next;

};

//构造节点数量为n的单项循环链表
Node *node_create(int n)
{
	Node *pRet=NULL;
	if(n!=0)
	{
		int n_idx=1;
		Node *p_node=NULL;

		//构造n个节点
		p_node=new Node[n];
		if(p_node==NULL)
			return NULL;
		else
			memset(p_node,0,n*sizeof(Node));//初始化内存
		
		pRet=p_node;
		while(n_idx<n)//构造循环链表
		{
			//初始化链表的每个节点从1到n
			p_node->data=n_idx;
			p_node->next=p_node+1;
			p_node=p_node->next;
			n_idx++;
		}

		p_node->data=n;
		p_node->next=pRet;	
	}
	return pRet;
}


int main()
{
	Node *pList=NULL;
	Node *pIter=NULL;
	int n=20;//设置总人数有20人
	int m=6;//初始报数的上限值

	pList=node_create(n);//构造节点数量为n的循环链表

	//约瑟夫循环取数
	pIter=pList;
	
	m%=n;
	while(pIter!=pIter->next)//该链表不是空表
	{
		int i;

		//取第m-1个节点
		for(i=1;i<m-1;i++)
		{
			pIter=pIter->next;
		}

		//取第m个绩点的值
		cout<<pIter->next->data<<" ";

		//删除第m个节点
		pIter->next=pIter->next->next;
		pIter=pIter->next;
	}

	cout<<pIter->data<<endl;

	delete []pList;

	return 0;
}

运行结果如下:

  • 9
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C-Jonn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值