数据结构(六)——循环链表

article/2025/11/9 13:13:55

一、循序链表简介

1、循环链表的定义

循环链表的任意元素都有一个前驱和一个后继,所有数据元素在关系上构成逻辑上的环。

循环链表是一种特殊的单链表,尾结点的指针指向首结点的地址。

循环链表的逻辑关系图如下:

 2、循环链表的设计实现

循环链表的设计实现要点:

A、通过模板定义CircleList,继承自LinkedList

B、定义连接链表首尾的内部函数

C、实现首元素的插入和删除操作

D、重写清空操作和遍历操作

3、循环链表的实现关键

A、插入位置为0时,头结点和尾结点均指向新结点,新结点作为首结点插入链表。

B、删除位置为0时,头结点和尾结点指向位置为1的结点,删除销毁首结点

二、循环链表的操作

1、尾结点获取

Node* last()
{return this->position(this->m_length - 1)->next;
}

2、首尾结点连接

void lastToFirst()
{last()->next = this->m_header.next;
}

3、循环链表的实现

  template <typename T>class CircleList:public LinkedList<T>{protected:typedef typename LinkedList<T>::Node Node;//尾结点Node* last(){return this->position(this->m_length - 1)->next;}//链接最后一个结点和首结点void lastToFirst(){last()->next = this->m_header.next;}int mod(int index)const{return (this->m_length == 0)?0:(index % this->m_length);}public:bool insert(int index, const T& value){bool ret = true;//计算插入结点的位置index = index % (this->m_length + 1);ret = LinkedList<T>::insert(index, value);//如果插入位置为0if(ret && (index == 0)){lastToFirst();//连接首尾结点}return ret;}bool insert(const T& value){return insert(this->m_length, value);}bool remove(int index){bool ret = true;index = mod(index);//删除结点为首结点if(index == 0){//首结点Node* toDel = this->m_header.next;if(toDel){//将头结点的下一个结点指向首结点的下一个结点this->m_header.next = toDel->next;this->m_length--;//链表长度减1//链表不为空if(this->m_length > 0){lastToFirst();//连接新的首结点与尾结点if(this->m_current == toDel){this->m_current = toDel->next;}}else{//链表为空,置空this->m_header.next = NULL;this->m_current = NULL;}//销毁要删除的结点this->destroy(toDel);}else{ret = false;}}else{//删除的结点不是首结点,按单链表处理ret = LinkedList<T>::remove(index);}return ret;}bool set(int index, const T& value){index = mod(index);return LinkedList<T>::set(index, value);}T get(int index)const{index = mod(index);return LinkedList<T>::get(index);}bool get(int index, T& value){index = mod(index);return LinkedList<T>::get(index, value);}int find(const T& value){int ret = -1;//首结点Node* current = this->m_header.next;//遍历链表查找数据元素for(int i = 0; i < this->length(); i++){if(current->value == value){ret = i;break;}//移动游标current = current->next;}return ret;}void clear(){//删除链表中结点至头结点while(this->m_length > 1){remove(1);}//删除首结点if(this->m_length == 1){Node* toDel = this->m_header.next;this->m_header.next = NULL;this->m_current = NULL;this->m_length = 0;this->destroy(toDel);}}bool move(int pos, int step){pos = mod(pos);return LinkedList<T>::move(pos, step);}bool end(){return (this->m_length == 0) || (this->m_current == NULL);}~CircleList(){clear();}};

四、约瑟夫环(Josephus)

1、约瑟夫环简介

Josephu约瑟夫环问题为:设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。

2、循环链表解决约瑟夫环问题

//约瑟夫环
void jusephus(int n, int k, int m)
{//构建循环链表CircleList<int> cl;for(int i = 1; i <= n; i++){cl.insert(i);}//移动当前结点到位置k-1,设置步长为m-1cl.move(k-1, m-1);while(cl.length() > 0){cl.next();//移动到目标位置cout << cl.current() << endl;//删除目标位置结点cl.remove(cl.find(cl.current()));}
}

3、递归方法解决约瑟夫环问题

当编号为1开始时可以使用递归

假设n=10,m=3

1 2 3 4 5 6 7 8 9 10 m=3

第一次有人出列后:1 2 4 5 6 7 8 9 10

出环的序列:4 5 6 7 8 9 10 1 2

转换为:1 2 3 4 5 6 7 8 9

              +3: 4 5 6 7 8 9 10 11 12

             %10: 4 5 6 7 8 9 10 1 2

设f(n,m,i)为n个人的环,报数为m,第i个人出环的编号,则f(10,3,10)是我们要的结果

当i=1时,  f(n,m,i) = (n-1+m)%n

当i>1时,  f(n,m,i)= ( f(n-1,m,i-1)+m )%n

当编号为0开始时可以使用递归

假设n=10,m=3

0 1 2 3 4 5 6 7 8 9 m=3

第一次有人出列后:0 1 3 4 5 6 7 8 9

3 4 5 6 7 8 9 0 1

1 2 3 4 5 6 7 8 9

              +3: 4 5 6 7 8 9 10 11 12

             %10: 3 4 5 6 7 8 9 1 2

设f(n,m,i)为n个人的环,报数为m,第i个人出环的编号,则f(10,3,10)是我们要的结果

当i=1时,  f(n,m,i) = (n-1+m)%n

当i>1时,  f(n,m,i)= ( f(n-1,m,i-1)+m )%n

#include <stdio.h>
#include <stdlib.h>int Josephu_recursion(int n, int m, int i)
{if(1 == i)return (n-1 + m) % n;elsereturn (Josephu_recursion(n-1, m, i-1) + m) % n;
}int main(void)
{int i;for(i = 1; i <= 10; i ++)printf("第%2d次出环:%2d\n", i, Josephu_recursion(10, 3, i));
}

4、数组方法解决约瑟夫环问题

/************************************************ 约瑟夫环问题的数组解决* n:约瑟夫环的长度* k:起点* m:步长* *********************************************/
int JosephuArray(int n, int k, int m)
{//分配n+1个int空间int *a = (int *)malloc((n+1) * sizeof(int));int i, j;//下标从1开始赋值for(i = 1; i <= n; i++)a[i] = i;//从a[1]开始//依次出环for(i = n; i >= 1; i--){//计算每次出环的k值k = (k + m -1) % i;if(k == 0)k = i;printf("%2d\n", a[k]);//打印出出环的序号//将出环的位置后的元素前移for(j = k; j < i; j++)a[j] = a[j+1];}free(a);
}


http://chatgpt.dhexx.cn/article/PgmghmGY.shtml

相关文章

数据结构-使用链表实现栈

目录结构 Stack接口 package LinkedListStack;public interface Stack<E> {int getSize();boolean isEmpty();void push(E e); //向栈中添加元素E pop();//向栈中取出元素E peek();//查看栈顶的元素 }LinkedList类 package LinkedListStack;public class LinkedList<…

数据结构 | 链表的实现

目录 单链表双链表数组结构和链式结构的对比 线性表中&#xff0c;除了顺序表这一重要的结构&#xff0c;还有链式结构&#xff0c;而这也是我们常说的链表。 一般是通过定义结构体(类)的方式来表示链表的每一个结点。一般而言&#xff0c;链表的结点都会有数据域和地址域。数据…

Java数据结构之链表

目录 一.单链表 1.单链表的介绍和内存布局 2.单链表的添加和遍历 3.单链表的插入 4.单链表的删除 二.双向链表 1.添加节点 2.遍历节点 3.插入节点 4.删除结点 5.测试 三.单向环形链表 1.问题的引出 ​编辑 2.构建环形链表 1.创建结点 3.测试 3.约瑟夫问题代码的…

c++数据结构:链表

链表是一种物理存储单元上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点&#xff08;链表中每一个元素称为结点&#xff09;组成&#xff0c;结点可以在运行时动态生成。每个结点包括两个部分&#xff1a;一个是…

java数据结构-链表详解

文章目录 1.数据结构-链表详解1.1单链表1.1.1单链表节点的尾部添加1.1.2单链表节点的自动排序添加1.1.3单链表节点的修改1.1.4单链表节点的删除 1.2单链表面试题1.2.1单链表的有效节点个数1.2.2单链表倒数第k个结点1.2.3单链表反转1.2.4单链表逆序打印 1.3双向链表1.3.1双向链表…

C语言数据结构链表(图文)

目录 一、链表的简单理解与引入 1.1 链表的引入 1.2 节点的理解 1.3 链表的分类 二、常用链表功能的实现 2.1 首先是节点的定义&#xff0c; 2.2 节点的创建 2.3 单链表的尾插 2.4 单链表的尾删 2.5 单链表的头插 2.6 链表的头删 2.7 单…

【数据结构】链表的学习总结

目录 1.链表的概念2.链表的结构1️⃣链表中单个结点的结构2️⃣链表的整体结构 3.链表的分类4.链表的实现1️⃣单向无头非循环2️⃣双向带头循环 1.链表的概念 链表&#xff0c;是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表 中的指针…

C++数据结构之链表(详解)

主要参考文章地址 01.链表基础知识 | 算法通关手册 (itcharge.cn)&#xff09; 本次内容是对链表的总结&#xff0c;可以看了上面的文章之后。 在看我下面的内容&#xff0c;做一个简短的复习&#xff0c;且本内容的代码均用C实现&#xff0c;而参考资料的代码则为python。 …

[数据结构]链表之单链表(详解)

文章目录 [数据结构]链表之单链表前言1.链表1.1链表的概念及结构1.2单链表与顺序表的区别与优缺点1.3八种链表类型、单向带头循环链表单向带头非循环链表单向不带头循环链表单向不带头非循环链表双向带头循环链表双向带头非循环链表双向不带头循环链表双向不带头非循环链表 2.单…

【数据结构与算法】详解什么是链表,并用代码手动实现一个链表结构

本系列文章【数据结构与算法】所有完整代码已上传 github&#xff0c;想要完整代码的小伙伴可以直接去那获取&#xff0c;可以的话欢迎点个Star哦~下面放上跳转链接 https://github.com/Lpyexplore/structureAndAlgorithm-JS 本文将来讲解一下一种常见的线性数据结构—链表&a…

数据结构-链表篇

数据结构中数组和链表是是使用频率最高的基础数据结构。数组作为数据存储结构有一定的缺陷。在无序数组中&#xff0c;搜索性能差&#xff0c;在有序数组中&#xff0c;插入效率又很低&#xff0c;而且这两种数组的删除效率都很低&#xff0c;并且数组在创建后&#xff0c;其大…

数据结构之——链表

目录 一、链表的概念及结构 二、单链表的实现&#xff08;无头单向非循环链表&#xff09; 1.单链表节点定义 2.单链表的接口实现 &#xff08;1&#xff09;动态申请一个节点 &#xff08;2&#xff09;单链表打印 &#xff08;3&#xff09;单链表的销毁 &#xff0…

【数据结构】链表

单链表 这张图是我们待会要实现的功能&#xff0c;我会尽可能的将每一步都说的很详细&#xff0c;方便理解。 链表的概念及结构 概念&#xff1a;链表是一种 物理存储结构上非连续 、非顺序的存储结构&#xff0c;数据元素的 逻辑顺序 是通过链表中的 指针链 接 次序实现的 。…

数据结构之链表

目录 一、链表的特点 二、虚拟头结点 三、链表的实现 1、定义LinkedList 2、 构造方法 3、基本方法 4、添加元素 5、查找元素 6、修改元素 7、删除元素 链表是一种物理存储单元上非连续、非顺序的数据结构。前几篇我们讲到的数组也好&#xff0c;基于数组实现的栈…

[数据结构] 链表(图文超详解讲解)

文章目录 一、链表是什么&#xff1f;二、链表 1.链表的结构2.链表方法的代码实现总结 一、链表是什么&#xff1f; 链表是一种物理存储结构上非连续存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。 二、链表 1.链表的结构 链表的结构如图: 链…

数据结构---单向链表,双向链表,单向环形链表

链表介绍 链表是以节点的方式来存储,是链式存储每个节点包含 data 域&#xff0c; next 域:指向下一个节点.如图:发现链表的各个节点不一定是连续存储.链表分带头节点的链表和没有头节点的链表&#xff0c;根据实际的需求来确定 修改节点功能 思路(1) 先找到该节点&#xff0c…

数据结构与算法——线性表(链表篇)

&#x1f60a;数据结构与算法——线性表&#xff08;链表篇&#xff09; &#x1f680;前言&#x1f680;线性链表&#xff08;单链表&#xff09;&#x1f6a2;概念&#x1f6a2;基本操作&#x1f47b;插入操作⛅按位序插入⛅指定结点的后插操作⛅指定节点的前插操作 &#x1…

什么是接口测试?为什么要做接口测试?

1. 什么是接口测试&#xff1f;为什么要做接口测试&#xff1f; 接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及系统间的相互…

接口测试怎么测?

通过性验证&#xff1a;首先肯定要保证这个接口功能是好使的&#xff0c;也就是正常的通过性测试&#xff0c;按照接口文档上的参数&#xff0c;正常传入&#xff0c;是否可以返回正确的结果。 参数组合&#xff1a;现在有一个操作商品的接口&#xff0c;有个字段type&#xf…

接口测试—详细

目录 1.为什么要做接口测试 2.最简单的接口长什么样 3.入门级接口测试工具:postman的安装 4.Json简介 5.3A原则 6.unittest框架 7.requests库 8.第一个用例 9.什么是mock server 10.使用flask实现mock server 总结 1.为什么要做接口测试 很多同学反馈现在面试的时候…