C++数据结构X篇_07_C++单向循环链表解决约瑟夫问题

news2024/12/24 9:15:08

本篇参考单向循环链表解决约瑟夫问题(C++)整理,先搞懂结构框架,后期根据视频利用c对内容实现,也可以对c有更高的提升。

文章目录

  • 1. 链表创建与初始化
  • 2. 添加插入、删除和打印函数
  • 3. 插入数据并核验
  • 4. 解决约瑟夫问题,
  • 5. 整体代码及运行结果
    • 5.1 代码
    • 5.2 运行结果

在大厂面试时,经常会被提出实现约瑟夫问题。那么什么是约瑟夫问题呢?

约瑟夫问题:
n个人围成一个圆圈,分别编号1~n,从第一个人开始顺时针报数为1,报到第m的时候。令其出列,然后再从下一个人重新开始报数,当从1报到m时,报m的人继续出列,以此重复下去,直到所有人都出列为止,获得所有人出列的序号。

当n=8,m=3时,出列的序号如下所示:
在这里插入图片描述
最终删除的序列为:3、6、1、5、2、8、4、7。
C++中有一种数据存储结构与这种首尾相连的环形结构极为相似——单向循环链表。对于单向循环链表的详细介绍可见C++数据结构X篇_06_C++单向循环链表实现。

下面我们将通过单向循环链表去实现约瑟夫问题。

1. 链表创建与初始化

这已经是老生常谈的问题了,在这里就不再赘述了,详情可见笔者之前写的有关链表的博客文章。

//节点定义
class node
{
public:
	int data;
	node* next;
};
//链表定义
class list
{
public:
	int size;
	node* head;
};
//链表初始化
list* list_init()
{
	list* L=new list;
	L->size=0;
	L->head=new node;
	L->head->data=NULL;
	L->head->next=L->head;
	return L;
}

2. 添加插入、删除和打印函数

我们创建的链表里面并不含有任何数据,因此我们还需要通过数据插入函数,将数据插入到链表中。由于约瑟夫问题还涉及到数据删除的问题,因此我们还要提供数据删除函数。为了知道我们的数据是否成功插入或删除,我们需要提供打印链表中数据的函数。

//链表插入数据
void list_insert(list *L,int pos,int num)
{
	node* new_node=new node;
	new_node->data=num;
	new_node->next=NULL;
 
	node* pcurrent=L->head;
	for (int i = 0; i < pos; i++)
	{
		pcurrent=pcurrent->next;
	}
	new_node->next=pcurrent->next;
	pcurrent->next=new_node;
	L->size++;
}
//删除链表(按值)
void list_delete(list* L,int num)
{
	node* pcurrent=L->head->next;
	int pos=0;
	for (int i = 0; i < L->size; i++)
	{
		if (pcurrent->data==num)
		{
			break;
		}
		pcurrent=pcurrent->next;
		pos++;
	}	
	pcurrent=L->head;
	for (int i = 0; i < pos; i++)
	{
		pcurrent=pcurrent->next;
	}
	pcurrent->next=pcurrent->next->next;
	L->size--;
}
//打印链表
void list_print(list *L,int num)
{
	node* pcurrent=L->head;
	for (int i = 0; i < num; i++)
	{
		if (pcurrent==L->head)
		{
			pcurrent=pcurrent->next;
		}
		cout<<pcurrent->data<<"\t";	
		pcurrent=pcurrent->next;
	}
	cout<<endl;
}

这些准备工作都完成之后我们就可以开始正式实现约瑟夫问题了,这里我同样将约瑟夫问题的n设为8、m设为3。

const int n=8;
const int m=3;

3. 插入数据并核验

首先是数据1~8插入链表,同时还可以打印检核一下

	//在链表中插入1~8
	list* L=list_init();
	for (int i = 0; i < n; i++)
	{
		list_insert(L,i,i+1);
	}
	cout<<"单向循环链表为:"<<endl;
	list_print(L,n);

4. 解决约瑟夫问题,

这明显是一个条件循环问题,只要链表中还有数据它就会一直循环下去。由于报号的过程是从自身开始的,因此除了自身外,还需要往后数两个数即这三个数分别为:pcurrent、pcurrent->next、pcurrent->next->next。当第三个人报号时,把他剔除。并将下次重新报号的人往后移一位,这样就可以与前面循环起来了。

	//开始解决约瑟夫问题
	cout<<"\n开始循环:"<<endl;
	node* pcurrent=L->head;
	int iter=1;
	while (L->size != 0)
	{
		for (int i = 0; i < 2; i++)
		{
			if (pcurrent == L->head)  //排除头node
			{
				pcurrent=pcurrent->next;
			}
			pcurrent=pcurrent->next;
			if (pcurrent == L->head) //排除头node
			{
				pcurrent=pcurrent->next;
			}
		}
		cout<<"第"<<iter<<"轮删除的数字:"<<pcurrent->data<<endl;
		//node* temp_p=pcurrent;
		list_delete(L,pcurrent->data);
		pcurrent=pcurrent->next;
		iter++;
	}

至此我们就完成了整个约瑟夫问题。

5. 整体代码及运行结果

5.1 代码

#include <iostream>
using namespace std;
const int n=8;
const int m=3;
//创建单向循环链表
class node
{
public:
	int data;
	node* next;
};
class list
{
public:
	int size;
	node* head;
};
list* list_init()
{
	list* L=new list;
	L->size=0;
	L->head=new node;
	L->head->data=NULL;
	L->head->next=L->head;
	return L;
}
//链表插入数据
void list_insert(list *L,int pos,int num)
{
	node* new_node=new node;
	new_node->data=num;
	new_node->next=NULL;
 
	node* pcurrent=L->head;
	for (int i = 0; i < pos; i++)
	{
		pcurrent=pcurrent->next;
	}
	new_node->next=pcurrent->next;
	pcurrent->next=new_node;
	L->size++;
}
//删除链表(按值)
void list_delete(list* L,int num)
{
	node* pcurrent=L->head->next;
	int pos=0;
	for (int i = 0; i < L->size; i++)
	{
		if (pcurrent->data==num)
		{
			break;
		}
		pcurrent=pcurrent->next;
		pos++;
	}	
	pcurrent=L->head;
	for (int i = 0; i < pos; i++)
	{
		pcurrent=pcurrent->next;
	}
	pcurrent->next=pcurrent->next->next;
	L->size--;
}
//打印链表
void list_print(list *L,int num)
{
	node* pcurrent=L->head;
	for (int i = 0; i < num; i++)
	{
		if (pcurrent==L->head)
		{
			pcurrent=pcurrent->next;
		}
		cout<<pcurrent->data<<"\t";	
		pcurrent=pcurrent->next;
	}
	cout<<endl;
}
int main()
{
	//在链表中插入1~8
	list* L=list_init();
	for (int i = 0; i < n; i++)
	{
		list_insert(L,i,i+1);
	}
	cout<<"单向循环链表为:"<<endl;
	list_print(L,n);
	//开始解决约瑟夫问题
	cout<<"\n开始循环:"<<endl;
	node* pcurrent=L->head;
	int iter=1;
	while (L->size != 0)
	{
		for (int i = 0; i < 2; i++)
		{
			if (pcurrent == L->head)  //排除头node
			{
				pcurrent=pcurrent->next;
			}
			pcurrent=pcurrent->next;
			if (pcurrent == L->head) //排除头node
			{
				pcurrent=pcurrent->next;
			}
		}
		cout<<"第"<<iter<<"轮删除的数字:"<<pcurrent->data<<endl;
		//node* temp_p=pcurrent;
		list_delete(L,pcurrent->data);
		pcurrent=pcurrent->next;
		iter++;
	}
	system("pause");
	return 0;
}

5.2 运行结果

在这里插入图片描述
6. 学习视频地址: 单向循环链表解决约瑟夫问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/713605.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DM8:达梦数据库备份还原报错-文件已存在 -4558 file exists

DM8:达梦数据库备份还原报错-文件已存在 -4558 file exists 1 文件已存在 -4558 file exists2 使用 OVERWRITE 参数对数据库还原3 参数介绍 1 文件已存在 -4558 file exists 在数据库还原操作时&#xff0c;遇到报错文件已存在 -4558 file exists&#xff0c;可以使用OVERWRIT…

IP归属地与IP定位

IP归属地查询是指根据给定的IP地址&#xff0c;确定该IP地址所属的地理位置或网络服务提供商。这种查询可以帮助用户了解到访者的地理位置&#xff0c;有助于网络安全、反垃圾邮件等应用。 在实际应用中&#xff0c;IP归属地查询常用于以下几个方面&#xff1a; 网络安全&…

vcruntime140_1.dll详细修复方法(推荐使用这个方法)

vcruntime140_1.dll丢失要怎么办&#xff1f;其实很多人都在头疼这个问题&#xff0c;关于dll文件的丢失这事情是时常发生的&#xff0c;因为电脑的杀毒软件有时候会误杀&#xff0c;然后就会导致你的游戏程序都打开不了&#xff0c;你必须要修复好了才行&#xff0c;今天小编就…

【UE5 Cesium】09-Cesium for Unreal 子关卡应用实例(下)

效果 通过按钮点击事件实现子关卡的切换 步骤 新建两个Actor蓝图作为GeoMarker&#xff0c;分别命名为“BP_GeoMarker_BeiJing”、“BP_GeoMarker_ShangHai” 分别打开这两个蓝图&#xff0c;添加文本渲染组件 在指定的地理位置上拖入蓝图“BP_GeoMarker_BeiJing” 控制“BP_…

分布式缓存系统热点数据

一、背景 分布式缓存一般被定义为一个数据集合&#xff0c;它将数据分布&#xff08;或分区&#xff09;于任意数目的集群节点上。集群中的一个具体节点负责缓存中的一部分数据&#xff0c;整体对外提供统一的访问接口 Amazon 于 2007 年提出的一种改进的一致性哈希算法 [4]。…

华为OD机试真题 Java 实现【查找单入口空闲区域】【2022 Q4 100分】,附详细解题思路

目录 一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 一、题目描述 给定一个 m x n 的矩阵&#xff0c;由若干字符 ‘X’ 和 ‘O’构成&#xff0c;’X’表示该处已被占据&#xff0c;’O’表示该处空闲&#xff0c;请找…

【JS】将表格数据下载为 .csv 文件

文章目录 代码实现 代码实现 1. 将表格数据转换为字符串格式 2. 字符串格式里面的,逗号表示换列 3. 字符串格式里面的\n符号表示换行实现 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><…

Linux(包括centos) 如何查看服务器内存、CPU

CPU架构 CPU架构主要包括&#xff1a;amd64、arm32v7、arm64v8、mips64el、mips32、ppc64le和ppc32等架构。 CPU信息 CPU信息主要为中央处理器详细信息&#xff0c;包括&#xff1a; 架构核心数量处理速度厂商名称CPU主频标签 … 注&#xff1a;不同的操作系统或者CPU架构提供…

怎么提取视频中的音频?这些提取音频方法很简单

将视频中的音频提取出来&#xff0c;可以单独对音频进行处理&#xff0c;如剪辑、增强声音等&#xff0c;而不影响视频本身的内容。在后期制作中&#xff0c;音频需要经过一系列的处理&#xff0c;如去噪、降噪、混响等&#xff0c;提取出音频可以更方便地进行这些处理&#xf…

MHA高可用

文章目录 MHA高可用1 定义2 组成3 特点4 搭建MySQL MHA4.1 配置主从复制4.2 关闭防火墙&#xff0c;安全机制4.3 修改Master、Slave1、Slave2节点的主机名4.4 添加主机映射关系4.5 修改 Master、Slave1、Slave2 节点的 Mysql主配置文件/etc/my.cnf4.6 在master、slave1、slave2…

2023年--上半年小程序团队工作总结

前言 大家好&#xff0c;这是小程序团队第一次跟大家见面。小程序团队从2020年开始&#xff0c;就着手进行着小程序的开发。 在2020年7月上线了第一个现在仍在使用的上古小程序&#xff1a;课程小程序 和 我的内容库小程序。 小伙伴们可能还不知道&#xff0c;你们平时日常在cs…

10分钟看透微信公众号支付

开发痛点 如何配置微信&#xff1f;怎么个流程&#xff1f;怎么入手&#xff1f;如何本地调试&#xff1f;网上教程10个小时不想看怎么办&#xff1f;这里一篇文章带你入手微信支付。看看微信公众号支付到底有什么神奇之处。 开发后结果 微信配置 1、首先打开文档中心&#…

dy系点选验证码协议2023/07/3 一直可用

前言 可以关注我哟,一起学习,主页有更多练习例子 如果哪个练习我没有写清楚,可以留言我会补充 如果有加密的网站可以留言发给我,一起学习共享学习路程 如侵权,联系我删除 此文仅用于学习交流,请勿于商用,否则后果自负 因为需求不得不搞,小白一个,哪有不对,大佬多多…

Linux 学习记录44(C++篇)

Linux 学习记录44(C篇) 本文目录 Linux 学习记录44(C篇)一、静态成员变量/函数1. 静态成员变量2. 静态成员函数 二、继承1. 继承的作用2. 继承的格式3. 子类对父类中成员的继承4. 子类中存在和父类同名成员时5. 继承中特殊的成员函数(1. 构造函数(2. 析构函数(3. 拷贝构造函数(…

OpenAI遭集体诉讼!窃取数百万用户信息?明星大模型变“数据小偷”!

“尽管制定了购买和使用个人信息的协议&#xff0c;但被告采取了不同的方法&#xff1a;窃取。”近日&#xff0c;一家律师事务所用一份长达157页的诉讼将OpenAI告到法庭&#xff0c;指控其在利润的驱使下&#xff0c;窃取大量个人信息来训练人工智能模型。 起诉书称&#xff0…

UE4 TCP通信 (UE作为客户端接收字节)

在上一篇(UE4 TCP通信)基础上,实现UE客户端接收服务端推送的字节数据并解析。 效果 (注意看左上角的打印信息) 步骤 1. 首先新建一个工程,然后创建一个Actor蓝图,这里命名为“BP_TCPConnect” 打开“BP_TCPConnect”,添加如下节点: (1)当服务端与客户端断开连接时…

SpringBoot+Vue+Element-ui实现简单登录注册功能

目录 1.前端 &#xff08;1&#xff09;登录和注册页面 HomeView.vue RegisterView.vue &#xff08;2&#xff09; main.js&#xff0c;作请求和响应拦截 2.后端 &#xff08;1&#xff09;mapper.xml &#xff08;2&#xff09;mapper接口 &#xff08;3&#xff0…

六本入选!首批“十四五”职业教育国家规划教材书目

近日&#xff0c;教育部办公厅公布了首批“十四五”职业教育国家规划教材书目&#xff0c;其中广东泰迪智能科技股份有限公司携手院校联合编写的6本教材入选该名单。 入选首批“十四五” 职业教育国家规划教材介绍 高职“十四五”职业教育国家规划教材 Python编程基础(第2版)…

平时成绩综合评价与总成绩预测模型

已排除非本人创作部分 摘要 针对问题一&#xff0c;我们首先对所有团队的数据做了正态性检验&#xff0c;共x次作业&#xff0c;每次作业成绩分布均可用正态分布描述。其次&#xff0c;我们对团队之间的成绩变化做了格兰杰因果检验&#xff0c;列出了成绩变化相关的一部分团队…

STL补充:STL中遵循的左闭右开原则/STL随机访问

文章目录 左闭右开原则示例&#xff1a;示例中erase的用法不能写成s.erase(s.begin()left)的原因 STL中支持随机访问的迭代器 左闭右开原则 在 C 中&#xff0c;容器&#xff08;如 vector&#xff0c;set&#xff0c;map 等&#xff09;的迭代器都遵循左闭右开的原则。 也就…