Floyd 判圈算法(Floyd Cycle Detection Algorithm)

Floyd 判圈算法(Floyd Cycle Detection Algorithm)

  1. 前言

Floyd判圈算法属于对指针操作的算法,它一般需要且仅需要两个指针,通过设定不同的指针移动速度,来判定链表或有限状态机中是否存在环。人为规定移动较快的指针称为快速指针(fast pointer),移动较慢的指针称作慢速指针(slow pointer),快速指针比慢速指针移动速度快2倍。

  1. 链表中环判定

在判定链表中是否存在环过程中,快慢指针可能会出现下列两种情形之一:

a) 快速指针指向到达链表的结尾 (fast pointer =NULL),此种情况表明链表中不存在环。这里需要说明的是,快速指针一定先于慢速指针道道链表的尾部。

b) 快速指针在遍历过程中,赶上慢速指针,并且与慢速指针相会和。这种情况下表明链表中存在着环(Loop)。

具体看一个例子,显而易见,链表中存在一个环,环的起点为5,应用快慢指针对此链表进行遍历,并判断其是否存在环。

在这里插入图片描述

第一步,建立快慢指针两个变量,并且令快慢指针均指向头节点,准备开始以不同的速度进行移动指针,观察会出现上述提到的哪类情形。

在这里插入图片描述

令快指针以两倍于慢指针的速度向前移动

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

显而易见,当移动至第七个元素的时候,快指针赶上慢指针,在此处快慢指针相遇。符合第二类情形,所以判定链表中存在着环。

  1. 算法逻辑

如果存在环,那么快慢指针一定在某处相遇,那究竟是为什么呢? 借助相关图示进行数学分析和理解,

在这里插入图片描述

上图中,采用链表两个节点之间的数目来代表距离

X-代表头节点(Head)到 环起点 之间的距离(Loop start point)

Y-代表环起点(Loop start point)和两指针的第一次相遇点(Meet point)之间的距离

C-代表环的周长/距离

当快慢指针在相遇的时候,分别求出快慢指针移动的相应距离,慢指针移动的距离:
D i s t a n c e _ s l o w = X + Y + s ∗ C ; s ∈ n o n − n e g a t i v e   i n t e g e r ( 非负整数 ) Distance\_slow=X+Y+s*C; s∈ non-negative\ integer(非负整数) Distance_slow=X+Y+sC;snonnegative integer(非负整数)

与之对应的是快指针移动的距离:
D i s t a n c e _ f a s t = X + Y + f ∗ C ; f ∈ n o n − n e g a t i v e   i n t e g e r ( 非负整数 ) Distance\_fast=X+Y+f*C; f∈ non-negative\ integer(非负整数) Distance_fast=X+Y+fC;fnonnegative integer(非负整数)
在相同移动次数的前提下,快指针移动的距离为慢指针移动距离的两倍,利用此条件可以对上面的距离建立有效的关系式。
D i s t a n c e _ f a s t = 2 ∗ D i s t a n c e _ s l o w Distance\_fast=2*Distance\_slow Distance_fast=2Distance_slow
通过等式变换和合并同类项后,我们可以得到,
X + Y + f ∗ C = 2 ∗ ( X + Y + s ∗ C ) X+Y+f*C=2*(X+Y+s*C) X+Y+fC=2(X+Y+sC)

X + Y = f ∗ C − 2 ∗ s ∗ C = ( f − 2 ∗ s ) ∗ C = K ∗ C X+Y=f*C-2*s*C=(f-2*s)*C=K*C X+Y=fC2sC=(f2s)C=KC

通过简化上面的关系是,最终我们可以得到两个简单的关系式:

X+Y=K*C----(1)

X=K*C-Y----(2)

上面关系式为寻找环的起点提供了方向和思路,如果两个指针相遇后,把头节点赋给慢指针,快指针的位置保持不变,我们以每次步长为1进行移动,快慢指针最后将相遇在环的起点位置(Loop start point)。此时慢指针走过的距离为X,快指针走过的距离为K*C-Y=X。

  1. 算法实现

a) 头文件声明函数, make_node 函数从整数创建待插入的结点;insert_node 利用头插法,插入结点,头结点一直在第一个位置。is_contain_loop函数判定链表中是否存在环,find_loop_start_point函数找到环的起始结点。

/**
 * @file floyd_cycle_detecion.h
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-06-18
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#ifndef FLOYD_CYCLE_DETECTION_H
#define FLOYD_CYCLE_DETECTION_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

typedef struct node
{
    int data;
    struct node *next;
}node,*node_link;


void make_node(node_link *new_node, int new_value);

void insert_node(node_link *head,int new_value);

bool is_contain_loop(node_link *head);

node_link find_loop_start_point(node_link *head);


#endif

b) 函数定义

值得一提的是,快指针采用 fast_pointer=fast_pointer->next->next方式实现跨越式移动。

/**
 * @file floyd_cycle_detecion.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-06-18
 * 
 * @copyright Copyright (c) 2023
 * 
 */

#ifndef FLOYD_CYCLE_DETECTION_C
#define FLOYD_CYCLE_DETECTION_C
#include "floyd_cycle_detection.h"

void make_node(node_link *new_node, int new_value)
{
    *new_node=(node_link)malloc(sizeof(node));
    (*new_node)->data=new_value;
    (*new_node)->next=NULL;

    return;
}

void insert_node(node_link *head, int new_value)
{
    node_link new_node;

    make_node(&new_node,new_value);

    if((*head)==NULL)
    {
        *head=new_node;
    }
    else //insert before the current node
    {
        new_node->next=*head;
        *head=new_node;
    }

    return;
}

bool is_contain_loop(node_link *head)
{
    node_link slow_pointer;
    node_link fast_pointer;

    slow_pointer=fast_pointer=*head;

    while(slow_pointer && fast_pointer && fast_pointer->next)
    {
        slow_pointer=slow_pointer->next;
        fast_pointer=fast_pointer->next->next;

        if(slow_pointer==fast_pointer)
        {
            return true;
        }
    }

    return false;
}

node_link find_loop_start_point(node_link *head)
{
    node_link slow_pointer;
    node_link fast_pointer;

    slow_pointer = fast_pointer = *head;

    while (slow_pointer && fast_pointer && fast_pointer->next)
    {
        slow_pointer = slow_pointer->next;
        fast_pointer = fast_pointer->next->next;

        if (slow_pointer == fast_pointer)
        {
            break;
        }
    }

    if(slow_pointer!=fast_pointer)
    {
        return NULL;
    }

    slow_pointer=*head;

    while(slow_pointer!=fast_pointer)
    {
        slow_pointer=slow_pointer->next;
        fast_pointer=fast_pointer->next;
    }

    return slow_pointer;
}

#endif

c) 测试函数

通过临时结点temp_node_1和temp_node_2在链表内创建一个环,方便后面的相关测试。

/**
 * @file floyd_cycle_detetcion_main.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-06-18
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#ifndef FLOYD_CYCLE_DETECTION_MAIN_C
#define FLOYD_CYCLE_DETECTION_MAIN_C
#include "floyd_cycle_detection.c"

int main(void)
{
    int i;
    int arr[]={10,9,8,7,6,5,4,3,2,1};
    int n=sizeof(arr)/sizeof(int);

    node_link head=NULL;
    node_link temp_node_1;
    node_link temp_node_2;
    node_link loop_start_point;
    bool res;

    for(i=0;i<n;i++)
    {
        insert_node(&head,arr[i]);
    }

    temp_node_1=head;

    while(temp_node_1 && temp_node_1->data!=5)
    {
        temp_node_1=temp_node_1->next;
    }

    temp_node_2=temp_node_1;

    while(temp_node_2->next!=NULL)
    {
        temp_node_2=temp_node_2->next;
    }

    temp_node_2->next=temp_node_1;

    res=is_contain_loop(&head);

    if(res)
    {
        printf("there is a loop inside\n");
    }
    else
    {
        printf("there is no a loop inside\n");
    }

    loop_start_point=find_loop_start_point(&head);

    printf("The loop start point had been detected\n");
    getchar();

    return EXIT_SUCCESS;
}



#endif

  1. 小结

本文通过学习Floyd判圈算法,对快慢指针有了更加深入的理解,希望今后能更加数量运用快慢指针的思想,分析解决不同的实际问题。

参考资料:

tf(“there is no a loop inside\n”);
}

loop_start_point=find_loop_start_point(&head);

printf("The loop start point had been detected\n");
getchar();

return EXIT_SUCCESS;

}

#endif


5. 小结

本文通过学习Floyd判圈算法,对快慢指针有了更加深入的理解,希望今后能更加数量运用快慢指针的思想,分析解决不同的实际问题。



参考资料:

1.[Floyd’s Cycle Finding Algorithm - GeeksforGeeks](https://www.geeksforgeeks.org/floyds-cycle-finding-algorithm/)

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

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

相关文章

给初级测试工程师的一些避坑建议

我遇到的大多数开发人员都不怎么热衷于测试。有些会去做测试&#xff0c;但大多数都不测试&#xff0c;不愿意测试&#xff0c;或者勉而为之。我喜欢测试&#xff0c;并且比起编写新的代码&#xff0c;愉快地花更多的时间在测试中。我认为&#xff0c;正是因为专注于测试&#…

【Turfjs的java版本JTS】前面讲了Turfjs可以实现几何计算,空间计算的功能,如果后端要做这项功能也有类似的类库,JTS

JTS Java Topology Suite 几何计算&#xff1a; 1. 前端js就用这个 Turfjs的类库。参考网站&#xff1a; 计算两线段相交点 | Turf.js中文网 2. 后端java语言就可以用 JTS这个类库&#xff0c;参考网站&#xff1a; JTS参考网站&#xff1a; 1. https://github.com/locatio…

Windows11 安装 CUDA/cuDNN+Pytorch

一、准备工作&#xff1a; 查看torch版本&#xff1a;进入python交互环境&#xff1a; >>>import torch >>>torch.__version__ 查看cuda版本&#xff1a;CMD窗口 nvcc --version 如果版本不一致&#xff0c;需要卸载再重装。 二、安装 Windows 安装 CU…

unity制作愤怒的小鸟

文章目录 一、 介绍SpringJoint2D 、line renderer制作发射绳基类bird脚本的基础功能给bird添加飞行拖尾效果pig类游戏胜利的小星星烟花界面摄像机跟随移动游戏失败的界面多种小鸟的制作&#xff1a;黄鸟、绿鸟、黑鸟地图选择关卡选择数据保存制作多个关卡场景异步加载游戏全局…

go 调试利器之pprof指标分析

文章目录 概要一、指标类型1.1、堆栈指标1.2、CPU指标分析1.3、http-pprof 二、go tool pprof2.1、可视化2.2、CPU火焰图 概要 Go语言原生支持对于程序运行时重要指标或特征进行分析。pprof是其中一种重要的工具&#xff0c;其不仅可以分析程序运行时的错误&#xff08;内存泄…

绕过激活锁 ,拯救一台旧手机iphone

一台旧的iphone忘了apple id账号和密码了&#xff0c;导致锁住了 某宝上解锁要花50&#xff0c; 不是舍不得花钱&#xff0c;作为一个搞技术的&#xff0c;实在觉得花钱有点丢人 经过一番探索 最终确定了有用的流程 并贴出来 亲测可用 最终实现了趟再床上就可以打卡 1、 刷机 …

【软件测试】性能测试服务端—排查指标问题(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 软件性能测试的目…

node安装后的全局环境变量配置

安装node时&#xff0c;位置最好不要装在c盘&#xff0c;这里&#xff0c;我在D盘下创建了文件夹"node"&#xff0c;安装地址选择在该文件夹下 一直next&#xff0c;直到安装结束&#xff0c;打开"node"文件夹&#xff0c;安装完后&#xff0c;里面的配置…

未来10年,网络安全人才就业的黄金期

随着大数据、物联网、人工智能等新技术的发展&#xff0c;信息技术与经济社会各领域的融合也更加深入。网络攻击行为日趋复杂、黑客攻击行为组织性更强、针对手机无线终端的网络攻击日趋严重&#xff0c;近几年有关网络攻击和数据泄露的新闻层出不穷。因此&#xff0c;随着国家…

Nodejs一、初识

零、文章目录 Nodejs一、初识 1、初识 Node.js &#xff08;1&#xff09;回顾与思考 浏览器中的 JavaScript 的组成部分 为什么 JavaScript 可以在浏览器中被执行 为什么 JavaScript 可以操作 DOM 和 BOM 浏览器中的 JavaScript 运行环境 JavaScript 能否做后端开发&#…

MySQL - 第0节 - MySQL在Centos 7环境安装

目录 1.安装前说明 2.MySQL在Centos 7环境安装 2.1.卸载不要的环境 2.2.配置mysql官方yum源 2.3.检查yum源能否正常工作 2.4.安装mysql 2.5.检查mysql是否安装成功 2.6.启动mysqld数据库服务端 2.7.三种登录方法 2.7.1.登陆方法一 2.7.2.登陆方法二 2.7.3.登陆方法…

Pandas+Pyecharts | 中国高校及专业数据分析可视化

文章目录 &#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. Pandas数据处理2.1 读取数据 &#x1f3f3;️‍&#x1f308; 3. Pyecharts数据可视化3.1 全国高校分布地图3.2 全国高校分布城市地图3.3 本科/专科占比3.4 985/211/双一流高校数量占比…

【考研复习】李春葆新编C语言习题与解析(错误答案订正)持续更新

新编C语言习题与解析 做习题时发现有些错误答案&#xff0c;写篇博客进行改正记录。不对地方欢迎指正&#xff5e; 第二章 C. 其中b的表达形式错误&#xff0c;若加上0x1e2b则正确。所以C错误。 D. e后为整数。指数命名规则&#xff1a;e前有数&#xff0c;后有整数。所以D错…

【CEEMDAN-CNN-LSTM】完备集合经验模态分解-卷积神经长短时记忆神经网络研究(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

getopt函数和getopt_long函数

这个函数有点像无限迷宫&#xff0c;正确的路和错误的路都有很多&#xff0c;我们只需要能够满足当前需求就可以了&#xff0c;完全没有必要去探索每一条路。虽然&#xff0c;我很久以前试图这样干过。过滤后的回忆&#xff0c;只剩感觉了&#xff0c;过滤的多了&#xff0c;感…

【简单便捷】解决Ubuntu内存不足问题:Ubuntu16.0.4 进行内存扩容

文章目录 电脑环境前言一、总述二、先在标题&#xff1a;虚拟机-->设置上进行扩容三、扩容之后 打开终端 执行 sudo apt install gparted四、执行 sudo gparted五、扩容成功六、重启测试 可以看到大概率成功了。 电脑环境 Windows 11 专业版系统 前言 在开发初期&#xf…

二叉树的相关操作

一.二叉树 本文的数据结构基于C语言练习。 C语言中的二叉树是一种数据结构&#xff0c;用于表示具有层次关系的数据集合。它由一个根节点开始&#xff0c;每个节点最多有两个子节点&#xff0c;分别称为左子节点和右子节点。 二叉树有许多相关性质&#xff0c;其中一些重要的包…

【CSS---定位基础篇】

CSS---定位基础篇 CSS-----基础定位:一 、 学习定位原因&#xff1a;&#xff08;定位的作用&#xff09;二 、定位组成&#xff1a;2.1 四种定位模式&#xff1a;&#xff08;1&#xff09;静态定位&#xff08;了解&#xff09;&#xff1a;&#xff08;2&#xff09;相对定位…

ElasticSearch笔记02-ElasticSearch入门

ElasticSearch安装 下载软件 ElasticSearch的官网&#xff0c;视频教程里用的Version是7.8.0&#xff0c;所以&#xff0c;我们也是用7.8.0版本的ElasticSearch。 下载地址&#xff1a;https://www.elastic.co/cn/downloads/past-releases#elasticsearch&#xff0c;然后搜索…

lua的元表与元方法理解

元表 在 Lua 中&#xff0c;元表&#xff08;metatable&#xff09;是一种特殊的表&#xff0c;用于定义另一个表的行为。每个表都有一个关联的元表&#xff0c;通过元表可以重载表的各种操作&#xff0c;例如索引、新索引、相加等。在 Lua 中&#xff0c;元表的使用非常灵活&…