循環参照検知:続・考察2

昨日の続き、記載通りを素直に実装してみた。とりあえず循環参照の検出は出来ている。

// code coloring/formated by http://manoli.net/csharpformat/
using System;
using Lx.Collections.Generic;

public static class Program
{
    static LinkList<int> CreateList()
    {
        LinkList<int> list = new LinkList<int>(10);
        list.Insert(5)
            .Insert(1)
            .Insert(3)
            .Insert(40)
            .Insert(1)
            .Insert(9);

        return list;
    }

    static void Main()
    {
        // 循環なし
        LinkList<int> list1 = CreateList();
        Console.WriteLine(HasLoop(list1));

        // 距離のある循環による終端
        list1.Next.Next.Next.Next.Next.SetNext(list1.Next.Next.Next);
        Console.WriteLine(HasLoop(list1));

        // 自己循環による終端
        LinkList<int> list2 = CreateList();
        list2.Last.SetNext(list2.Last);
        Console.WriteLine(HasLoop(list2));

        // 完全循環
        LinkList<int> list3 = CreateList();
        list3.Last.SetNext(list3);
        Console.WriteLine(HasLoop(list3));
        
        // 要素数1で自己循環
        LinkList<int> list4 = new LinkList<int>(10);
        list4.Last.SetNext(list4.Last);
        Console.WriteLine(HasLoop(list4));
    }

    static bool HasLoop<T>(LinkList<T> node)
    {
        if (node.Next == null) return false;

        int m = 1;
        while (true)
        {
            // 先頭から m 個の要素を調べる
            LinkList<T> cur = node;
            for (int i = 0; i < m; i++)
            {
                // m - i 個目まで調べる
                int n = HasLoop(cur, m - i);

                // 終端を発見
                if (n < m - i) return (n < 0);

                // 次の要素を調べる
                cur = cur.Next;
            }
            m++;
        }
    }

    /// <param name="m">最大のステップ数</param>
    /// <returns>
    /// 0 以上 : node と終端の間にある要素数<br>
    /// 0 未満 : ループの検出
    /// </returns>
    static int HasLoop<T>(LinkList<T> node, int m)
    {
        if (node.Next == null) return 0;

        int n = 0;
        foreach (LinkList<T> cur in node.Next.Walk())
        {
            n++;

            if (cur == node) return -n;
            if (n == m) break;
        }

        return n;
    }
}