循环单向链表与约瑟夫问题

循环链表介绍

先不急着看约瑟夫问题是什么,先了解循环链表的结构,那什么是循环链表?

循环,顾名思义,从链表中第一个节点出发,还会遇到第一个节点,形成循环的一环。也就是说链表中最后一个节点的下一个节点是第一个节点,但是头节点也是一个节点,所以最后一个节点的下一个节点应该是头节点才对。

如下图,有两种情况:

其中更大的长方形是节点的数据域,更小的长方形是节点的指针域,指向链表中的下一个节点。

循环链表的代码实现

因为解决约瑟夫问题,只需要初始化、插入、打印功能,所以别的功能就没实现。

节点定义

首先,循环链表和普通链表节点的结构体定义一模一样,那就写出来吧。

typedef struct _LoopLinkList //循环链表
{
	int date;
	struct _LoopLinkList* next;
}LinkNode,LinkList;

 循环链表的初始化

初始化循环链表,其中函数的参数是一个指向头节点的指针,如图所示:

两个箭头有些重叠了,不过无伤大雅。

函数参数中的取地址符 & 是引用的意思,为C++特有的,相当于就在使用这个一级指针 L ,无需使用二级指针来接收这个一级指针 L 的地址,如果去掉这个 & ,会发生什么事呢?那就是 L 这个指针所指向的地址无法改变,但是可以改变所指向的变量的值。

bool initLinkList(LinkList *&L)
{
	L = new LinkNode;     //为头结点申请空间
	if (!L) return false; // L为空指针,生成头结点失败

	L->next = L; //头结点指向自己
	L->date = -1;
	return true;
}

如果上面那段话不太明白,可以先跳过,等写完所有代码,然后把初始化函数参数中的 & 去掉,在 IDE 中调试一下即可得出答案。

循环链表的插入(尾插法)

其中函数的参数节点指针 node 指向新加节点。

bool InsertBack(LinkList* &L, LinkNode* node)
{
	if (!L || !node) return false; //如果链表头结点未创建或者传入的结点指针指向空

    //分两种情况,一是链表为空,只有头结点存在
	if (L->next == L)
	{
		node->next = L;
		L->next = node;
	}
	else
	{
		LinkNode* p = L;
		while (p->next != L)
		{
			p = p->next;
		} //找到最后一个节点

		p->next = node;
		node->next = L;
	}
	return true;
}

循环链表的打印

从头节点开始打印,直到又为头节点。

bool LinkPrint(LinkList* L)
{
	if (!L) return false;

	LinkNode* p = L;
	p = L ->next;
	while (p != L)
	{
		printf("%d ", p->date);
		p = p->next;
	}
	return true;
}

约瑟夫问题

解决了循环链表,就开始约瑟夫问题了,哈哈,这故事有很多的分支,我之前听过的不是下面这种。

据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决。Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

——摘自约瑟夫问题_百度百科

 不过看完这个故事应该大概了解了约瑟夫问题,这个问题可以用循环链表解决,每一个人都是链表中一个节点,只要某个节点报数报到出圈的那个号码,就把这个节点从链表中删除。

由于原问题的人数实在太多,我这里就简化一下,一共 10 人,报数报到 9 的人出圈,并且要求求出第五轮出圈的号码,还有最后一个出圈的人的号码,所以添加了两个整型变量 loops、num来记录。

首先在进入这个函数之前已经把 10 个节点插入了链表,第 n 个节点的值为 n ,例如:第一个节点的数据域为 1 。

代码实现

其中函数参数 interval 为间隔,也就是出圈的号码 9 。

bool Joseph(LinkList* &L,int interval)
{
	if ( !L || L->next == L) return false; // 头节点未初始化或者是空链表
	if (interval < 1) return false; //报数的间隔也不能小于 1 , 1 的话还能玩,也就是一报数就死

	LinkNode* p = L , *q = NULL ; // q 指向要删除的节点, p 指向要删除的节点的前一个节点
	int loops = 0 , num = 0 ;     //loops表示进行到第几轮,num保存着出圈的人的号码

	int j = 1;

	while (L->next != L) //不为空链表
	{

		while ( j < interval ) //一直报数,除非j等于出圈的数-1,这时候指针p就指向了要删除的节点的前一个节点
		{
			if (p->next != L)
			{
				j++;
			}	
			p = p->next;
		}
		if (p->next == L) //如果p指向最后一个节点,那肯定不能删除头节点,应该删除第一个节点,所以p赋值为头节点
		{
			p = L;
		}

        //删除
		q = p->next;
		num = q->date;
		p->next = q->next;
        delete q;

		j = 1;
        loops++;

		cout <<endl<< "这是第"<<loops<<"轮:" ;
		LinkPrint(L);
		
		if (loops == 5)
		{
			printf("\n第5轮出圈的是:%d", num);
		}
	}

	printf("最后一个出圈的是:%d\n", num);
	return true;
}

 可能有人会想为什么其中循环的条件不是 i <= j 呢?因为在单向链表中,你删除一个节点前,必须要让删除节点的上一个节点的next 指针指向删除节点的下一个节点。

所以指向要删除的节点的上一个节点就方便很多了

如下图:

完整代码以及运行结果

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>

using namespace std;
//结点结构体
typedef struct _LoopLinkList
{
	int date;
	struct _LoopLinkList* next;
}LinkNode,LinkList;

//初始化
bool initLinkList(LinkList* &L)
{ 
	L = new LinkNode;
	if (!L) return false; 

	
	L->next = L; //指向自己
	L->date = -1;
	return true;
}


//尾插法
bool InsertBack(LinkList* L, LinkNode* node)
{
	if (!L || !node) return false; 


	if (L->next == L) //链表为空,只有头结点
	{
		node->next = L;
		L->next = node;
	}
	else
	{
		LinkNode* p = L;
		while (p->next != L)
		{
			p = p->next;
		}
		p->next = node;
		node->next = L;
	}
	return true;
}

//打印
bool LinkPrint(LinkList* L)
{
	if (!L) return false;

	LinkNode* p = L;
	p = L ->next;
	while (p != L)
	{
		printf("%d ", p->date);
		p = p->next;
	}
	return true;
}



//解决joseph问题
bool Joseph(LinkList*& L, int interval)
{
	if (!L || L->next == L) return false; // 头节点未初始化或者为空链表
	if (interval < 1) return false;  //报数的间隔

	LinkNode* p = L, * q = NULL; 
	int loops = 0, num = 0;     //loops表示进行到第几轮,num保存着最后一个出圈的人的号码

	int j = 1;

	while (L->next != L) 
	{

		while (j < interval) 
		{
			if (p->next != L)
			{
				j++;
			}
			p = p->next;
		}
		if (p->next == L) 
		{
			p = L;
		}

		//此时 p 指向要删除节点的前一个节点(不为最后一个节点)
		q = p->next;
		num = q->date;
		p->next = q->next;
		delete q;

		j = 1;
		loops++;

		cout << endl << "这是第" << loops << "轮:";
		LinkPrint(L);

		if (loops == 5)
		{
			printf("\n第5轮出圈的是:%d", num);
		}
	}

	printf("最后一个出圈的是:%d\n", num);
	return true;
}
int main(void)
{
	LinkList* L = NULL ;
	LinkNode* e = NULL;

	//1.初始化循环链表
	initLinkList(L);
	
	//2.尾插循环链表
	for (int i = 1; i <= 10; i++)
	{
		e = new LinkNode;
		e->date = i;
		e->next = NULL;
		InsertBack(L, e);
	}


	//3.打印链表
	LinkPrint(L);

	Joseph(L, 9);
	return 0;
}

---------------------------------------------------------------------------------------------------------------------------------

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

春晚回应吉祥物“龙辰辰”被质疑 AI 合成;周星驰 Web3 团队下月上线独立 App 丨 RTE 开发者日报 Vol.102

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

Python基础知识-变量、数据类型(整型、浮点型、字符类型、布尔类型)详解

1、基本的输出和计算表达式&#xff1a; prinit(12-3) printf(12*3) printf(12/3) prinit(12-3) printf(12*3) printf(12/3) 形如12-3称为表达式 这个表达式的运算结果称为 表达式的返回值 1 2 3 这样的数字&#xff0c;叫做 字面值常量 - * /称为 运算符或者操作符 在C和j…

【S32DS报错】-2-提示Error while launching command:arm-none-eabi-gdb –version错误

目录 1 Error错误提示 2 Error错误原因 3 如何消除Error错误 结尾 【S32K3_MCAL从入门到精通】合集&#xff1a; S32K3_MCAL从入门到精通https://blog.csdn.net/qfmzhu/category_12519033.html 1 Error错误提示 使用S32DSJ-LinK下载程序&#xff0c;在Dedug Configurati…

TA-Lib学习研究笔记(九)——Pattern Recognition (2)

TA-Lib学习研究笔记&#xff08;九&#xff09;——Pattern Recognition &#xff08;2&#xff09; 形态识别的函数的应用&#xff0c;通过使用A股实际的数据&#xff0c;验证形态识别函数&#xff0c;用K线显示出现标志的形态走势&#xff0c;由于入口参数基本上是open, hig…

H5ke14--1--拖放

介绍drag,drop 一.被拖动元素,目标(释放区) 元素要设置dragable属性:true,false,auto 被拖动元素上面有三个事件,drag,dragend,按下左键,移动种,鼠标松,这三个事件一般只用获取我们的被拖动元素 冒泡:event是可以继承的,mouseevent鼠标事件,dragevent拖放事件,前面都是一个…

大数据技术1:大数据发展简史

前言&#xff1a;学习大数据技术&#xff0c;知道会用已经够了&#xff0c;但是要想走得更远&#xff0c;应该了解它发展的来龙去脉&#xff0c;为何会有新的技术/工具的出现&#xff0c;相比老的技术有什么样的进步。 1、传统数据处理系统存在的问题 随着信息时代互联网技术爆…

Efficient physics-informed neural networks using hash encoding

论文阅读&#xff1a;Efficient physics-informed neural networks using hash encoding Efficient physics-informed neural networks using hash encoding简介方法PINN哈希编码具有哈希编码的 PINN 实验Burgers 方程Helmholtz 方程N-S 方程训练效率对比 总结 Efficient physi…

Java来实现二叉树算法,将一个二叉树左右倒置(左右孩子节点互换)

文章目录 二叉树算法二叉树左右变换数据 今天来和大家谈谈常用的二叉树算法 二叉树算法 二叉树左右变换数据 举个例子&#xff1a; Java来实现二叉树算法&#xff0c;将一个二叉树左右倒置&#xff08;左右孩子节点互换&#xff09;如下图所示 实现的代码如下&#xff1a;以…

AntDB数据库助力中国移动结算中心建设

结算中心负责中国移动漫游伙伴进行数据和财务清算支撑。本次结算中心项目涉及结算处理、资料管理、信息管理等模块&#xff0c;用以构建系统的结算能力。 建设需求 结算中心现有传统集中式架构的数据库无法做到根据业务量变化进行弹性扩缩容&#xff0c;目前系统数据量巨大&a…

maven学习笔记总结

目录 一、maven简介 二、GAVP属性 三、基于 IDLE 的 Maven 工程创建 1&#xff09;java标准工程&#xff08;Javase&#xff09;的创建 2&#xff09;java企业工程&#xff08;Javaee&#xff09;的创建 a&#xff09;手动创建 b&#xff09;插件方式创建&#xff08;fil…

开发一款属于自己的校园跑腿小程序 手把手带你写同城跑腿 代取快递 代买东西 代寄快递 含骑手端 管理员端 用户端 校园圈子论坛

今天开始带大家开发一款属于自己的校园跑腿同城跑腿小程序。 第一章讲技术点和效果图&#xff0c;如果你看完效果图觉得不错&#xff0c;可以认真跟着石头哥学习。 第二章教大家如何快速部署项目&#xff0c;如果你只是为了部署源码只需要学习第二章即可。 第三章开始就是带着…

css 输入框动态特效

先上图 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>css 输入框动效</title><style>.inputBox {position: relative;width: 250px;}.inputBox input {width: 100%;padding: 10px…

MySQL Connector/J 数据库连接 URL的语法

详情请参考&#xff1a;https://dev.mysql.com/doc/connector-j/en/connector-j-reference-jdbc-url-format.html jdbc:mysql:是用于普通的、基本的故障转移连接使用&#xff1a; jdbc:mysql://[host][,failoverhost...][:port]/[database][?propertyName1][propertyValue1]…

高德地图画渐变线

高德地图画渐变线&#xff0c;思路是将线和颜色均分为多个小线段和小颜色&#xff0c;实现渐变&#xff0c;类似于下图。 如果需要多段线&#xff0c;自己循环拼一下就可以了&#xff0c;方法返回多个小线段组成的polyline数组。 /** 高德地图画渐变线* author: liyun* params…

PHP基础 - 输入输出

在 PHP 中,有多种方法可以用来输出内容。下面是其中的几种: 1、echo: 这是最常见的输出语句之一,可以输出一个或多个字符串。它是一个语言结构,可以省略括号。使用示例如下: <?php // 使用 echo 语句输出一个字符串 echo "Hello, world!\n";// 可以使用…

3.添加与删除字段

添加字段与删除字段 1.添加字段 因为甲方的业务需求是不停变化的&#xff0c;所以在数据库操作中&#xff0c;添加字段可是常有的事。一个完整的字段包括&#xff1a;字段名、数据类型和完整性约束。 语法规则为&#xff1a; ALTER TABLE 表名 ADD 新字段名 数据类型 [约束条…

解决:During handling of the above exception, another exception occurred

解决&#xff1a;During handling of the above exception, another exception occurred 文章目录 解决&#xff1a;During handling of the above exception, another exception occurred背景报错问题报错翻译报错位置代码报错原因解决方法参考内容&#xff1a;今天的分享就到…

用html+css+js做canvas烟花模拟网页动画代码

圣诞节、元旦就要到了&#xff0c;本案例我们将用htmlcssjs做canvas烟花模拟网页动画代码&#xff0c;程序员的浪漫这不就来了嘛&#xff0c;与家人朋友一起看烟花吧&#xff01; 附源码 烟花模拟器 <!-- App --> <div class"container"><div class&…

区块链创新应用场景不断拓展,实现去中心化

小编介绍&#xff1a;10年专注商业模式设计及软件开发&#xff0c;擅长企业生态商业模式&#xff0c;商业零售会员增长裂变模式策划、商业闭环模式设计及方案落地&#xff1b;扶持10余个电商平台做到营收过千万&#xff0c;数百个平台达到百万会员&#xff0c;欢迎咨询。 区块…

gitee配置

注册配置gitee Gitee官网 进入官网之后&#xff0c;有账号直接登录&#xff0c;没有账号注册一个新的账号 下载安装git客户端 官网地址 下载完成&#xff0c;一路直接点击安装直接安装成功 检查是否安装成功 鼠标留在桌面–>右击–>出现Git GUI Here/Git Bash Her…