ขั้นตอนวิธีการตรวจสอบการเกิดวงวนของฟลอยด์

**ขั้นตอนวิธีการตรวจสอบการเกิดวงวนของฟลอยด์** () หรือเรียกอีกชื่อหนึ่งว่า **ขั้นตอนวิธีเต่าและกระต่าย** () เป็นขั้นตอนวิธีที่ง่ายและรวดเร็วที่สุดในการตรวจสอบวงในลำดับรายการของข้อมูล ถูกคิดค้นขึ้น ในปี ค.ศ. 1967 โดย นักวิทยาศาสตร์คอมพิวเตอร์สัญชาติอเมริกัน ชื่อ โรเบิร์ต ฟลอยด์ (Robert W. Floyd) เพื่อใช้เป็นขั้นตอนในการตรวจสอบวงที่เกิดขึ้นภายในลำดับของข้อมูลในโครงสร้างข้อมูลแบบรายการ (list) ขั้นตอนวิธีของฟลอยด์นี้ มีความน่าสนใจตรงที่ เป็นขั้นตอนที่ใช้ตัวชี้ 2 ตัว ในการทำงาน ใช้ขอบเขตเวลาไม่เกิน λ+μ (O (λ+μ)) และ ใช้เนื้อที่บนหน่วยความจำเป็นค่าคงตัว (O (1))

หมายเหตุ : λ คือ ความยาวจากจุดเริ่มต้นของรายการไปถึงจุดแรกของการเกิดวง μ คือ ค่าความยาวของ 1 รอบวง (ขนาดของวง) การตรวจสอบวงวนดังกล่าวได้ถูกนำมาใช้ในการตรวจสอบรายการของข้อมูลเพื่อหาตำแหน่งการเกิดของวงวนไม่สิ้นสุดที่เกิดขึ้นในรายการของข้อมูล หรือ วงวนเครื่องสถานะจำกัด หรือ "ไฟไนต์สเตทแมชชีน" (finite state machine) เพื่อที่จะกำจัดวงวนที่ตรวจพบได้ดังกล่าว

## แนวคิดการทำงาน
thumb|300px|ขั้นตอนวิธีการตรวจสอบการเกิดวงวนของฟลอยด์,ในชุดลำดับ 2, 0, 6, 3, 1, 6, 3, 1, ...
อธิบายแนวคิดการทำงานโดยการเปรียบเทียบพฤติกรรมของตัวชี้ทั้งสองเป็นเต่าและกระต่ายตามลำดับ (Tortoise and hare) ซึ่งตัวชี้ทั้งสองจะทำการวิ่งไปบนรายการของข้อมูล โดยเริ่มจากจุดเริ่มต้นของข้อมูลพร้อมกัน โดยที่ตัวชี้ที่เคลื่อนที่ช้ากว่า เปรียบเสมือนเป็นเต่า จะเคลื่อนที่ไปครั้งละ 1 ก้าว ส่วนตัวชี้อีกตัวหนึ่งซึ่งเคลื่อนที่เร็วกว่าเสมือนกับกระต่าย จะเคลื่อนไปบนรายการของข้อมูลด้วยความเร็วเป็นสองเท่าของเต่า จะตรวจสอบการเกิดวงได้จากการที่ตัวชี้ทั้งสองเคลื่อนที่ไปในรายการของข้อมูลจะมีการพิจารณาจากค่าภายในข้อมูลของตำแหน่งที่ที่ตัวชี้แต่ละตัวชี้อยู่ ถ้าในรายการนั้น มีวงวนแสดงว่ากระต่ายก็มีโอกาสวิ่งวนมาพบกับเต่า (ตรวจสอบได้จาก เมื่อตัวชี้ทั้งสองเคลื่อนที่มาพบกันที่ตำแหน่งเดียวกัน ค่าภายในข้อมูลเท่ากัน แสดงว่ามีวงวนในรายการ) แต่ถ้าหากภายในรายการไม่มีวงวนแล้วนั้นกระต่ายจะวิ่งไปจนถึงปลายทาง (ปลายสุดของรายการ) โดยไม่พบกับเต่าเลยนั่นเอง

## ขั้นตอนวิธี
อธิบายใจความสำคัญของขั้นตอนวิธีได้ดังนี้ ในทุกๆ ค่า i >= μ, X (i) = X (i + kλ), โดยที่ k >= 0 หรืออธิบายง่ายๆ คือที่ i = kλ (โดยที่ k มีค่ามากกว่า 0) เมื่อเราพบตำแหน่งที่ X (i) = X (2i) ( หรือ ในทางกลับกันคือ ถ้าเราพบตำแหน่งที่ X (2i) = X (i) ) เราจะพบว่าค่า i ที่น้อยที่สุดจะเป็นตัวคูณของ λ (โดยที่ i มีค่า มากกว่าเท่ากับ μ) ดังนั้นเราต้องทำการตรวจสอบค่าซ้ำกันที่เกิดในกรณีที่กล่าวข้างต้นเพื่อหาจุด v ที่ ค่าใน X (i) = X (2i) เมื่อเราพบจุด v ดังกล่าวแล้ว นั่นคือเราพบว่ามีวงอยู่ในรายการของข้อมูลนั่นเอง

นอกจากนั้นเรายังสามารถย้อนหาระยะจากต้นรายการมาจนถึงจุดแรกที่เกิดวง (λ) ได้โดย การหาจุดที่ X (ν + μ) = X (μ) ทำได้ดังนี้ คือ ให้ตัวชี้เต่ากลับไปเริ่มต้นใหม่ที่ต้นรายการ และตัวชี้ที่แทนกระต่ายอยู่ที่เดิม (เต่าและกระต่ายอยู่ห่างกันเป็นระยะ v) แล้วให้ทั้งสองวิ่งด้วยความเร็วเท่ากันคือ 1 จนกว่าจะพบจุดที่ค่าใน X (ν + μ) = X (μ) เป็นจุดแรกของการเกิดวงนั่นเอง และ เรายังสามารถหาความยาวสั้นสุดของวงได้โดยหาจากจุดที่ X (μ + λ) = X (μ) นั่นเอง สามารถทำได้ดังนี้ เมื่อเราได้ ระยะจากต้นรายการมาจนถึงจุดแรกที่เกิดวง (λ) มาแล้วเริ่มจากจุดแรกที่เกิดวง ให้เราทำการวิ่งโดยใช้ตัวชี้เต่าหยุดอยู่กับที่ และให้ตัวชี้กระต่ายวิ่งไปทีละ 1 แล้วนับจำนวนครั้งการเคลื่อนที่ของตัวชี้กระต่ายจนกว่าจะวนกลับมาพบกับตัวชี้เต่าอีกครั้งหนึ่ง จะได้จำนวนครั้งของการเคลื่อนที่ที่ได้เท่ากับจำนวนระยะสั้นสุดของ 1 รอบวง

## รหัสเทียม
เขียนรหัสเทียมได้ดังนี้

    tortoise = head
    hare = head
    Forever:
        if end==hare : return 'No loop' : else : hare = hare.next
        if end==hare : return 'No loop' : else : hare = hare.next
        tortoise = tortoise.next
        if hare==tortoise: return 'Loop found'

รหัสเทียมภาษาไทย

    ขั้นตอนวิธี การตรวจสอบการเกิดวงวนของฟลอยด์ :
    เต่าเริ่มที่ตำแหน่งต้นของรายการ
    กระต่ายเริ่มที่ตำแหน่งต้นของรายการ
    วนซ้ำ {
        ถ้า ตำแหน่งกระต่ายเท่ากับตำแหน่งปลายทาง “ไม่พบวงวน” : หรือ : กระต่ายเคลื่อนตำแหน่งถัดไปอีก 1 ช่อง
        ถ้า ตำแหน่งกระต่ายเท่ากับตำแหน่งปลายทาง “ไม่พบวงวน” : หรือ : กระต่ายเคลื่อนตำแหน่งถัดไปอีก 1 ช่อง
        เต่าเคลื่อนตำแหน่งถัดไปอีก 1 ช่อง
        ถ้าตำแหน่งเต่าเท่ากับตำแหน่งกระต่าย “พบวงวน”
    }

## ประสิทธิภาพการทำงาน

การทำงาน ใช้ขอบเขตเวลาไม่เกิน λ+μ (O (λ+μ)) และ ใช้ เนื้อที่บนหน่วยความจำเป็นค่าคงตัว (O (1))

หมายเหตุ : λ คือ ความยาวจากจุดเริ่มต้นของรายการไปถึงจุดแรกของการเกิดวง , μ คือ ค่าความยาวของ1รอบวง (ขนาดของวง)

## ขั้นตอนวิธีที่เกี่ยวข้อง
* ขั้นตอนวิธีโรห์ของพอลลาร์ด
* ขั้นตอนวิธีของเบรนท์

## อ้างอิง
* http://www.siafoo.net/algorithm/10
* http://www.brilliantsheep.com/floyds-cycle-finding-algorithm-implementation-in-java/ 
* http://c2.com/cgi/wiki?TortoiseAndHare
* http://www.geeksforgeeks.org/archives/112

หมวดหมู่:ขั้นตอนวิธี
หมวดหมู่:ขั้นตอนวิธีการจัด