在类层次结构中查找最小值

时间:2009-07-22 00:18:22

标签: c#

鉴于以下类(假设它们已填充),您如何找到val实例的任何test1的最小值?

    public class test1
    {
        public int val;
        public List<test2> Tests;
    }

    public class test2
    {
        public int val;
        public List<test3> Tests;
    }

    public class test3
    {
        public int val;
        public List<test4> Tests;
    }

    public class test4
    {
        public int val;
    }

5 个答案:

答案 0 :(得分:3)

您可以在顶级类中编写一个方法,将结构展平为IEnumerable。

public IEnumerable<int> FlattenVal()
{
    yield return this.val;
    foreach (var t2 in this.Tests)
    {
        yield return t2.val;
        foreach (var t3 in t2.Tests)
        {
            yield return t3.val;
            foreach (var t4 in t3.Tests)
            {
                yield return t4.val;
            }
        }
    }
}

然后你可以这样称呼它:

var t = new Test1();

Console.WriteLine(t.FlattenVal().Min());

如果你不能将方法直接添加到类(非部分,代码生成或库中),那么你可以使用扩展方法:

public static IEnumerable<int> FlattenVal(this Test1 t1)
{
    yield return t1.val;
    foreach (var t2 in t1.Tests)
    {
        yield return t2.val;
        foreach (var t3 in t2.Tests)
        {
            yield return t3.val;
            foreach (var t4 in t3.Tests)
            {
                yield return t4.val;
            }
        }
    }
}

答案 1 :(得分:2)

非递归(和非测试)解决方案:

int minVal(test1 t1) {
   int min = t1.val;
   foreach (test2 t2 in t1.Tests) {
      min = Math.Min(min, t2.val);
      foreach (test3 t3 in t2.Tests) {
         min = Math.Min(min, t3.val);
         foreach (test4 t4 in t3.Tests) {
             min = Math.Min(min, t4.val);
         }
      }
   }
   return min;
}

答案 2 :(得分:2)

我必须承认这个问题看起来有些奇怪,但这里有一个解决方案,它引入了两个基类TestBaseTest<T>,因此最小查找算法可以保存在一个地方:

using System;
using System.Collections.Generic;
using System.Linq;

public abstract class TestBase {
  public int Val;
  public virtual int GetMin() {
    return Val;
  }
}
public abstract class Test<T> : TestBase where T : TestBase {
  public List<T> Tests;
  public override int GetMin() {
    return Math.Min(Val, Tests.Select(t => t.GetMin()).Min());
  }
}
public class Test1 : Test<Test2> {
}
public class Test2 : Test<Test3> {
}
public class Test3 : Test<Test4> {
}
public class Test4 : TestBase {
}

我将用于标识符的外壳更改为让我感觉更舒服的东西。

答案 3 :(得分:0)

我已经测试并编写了一个应该可行的完整控制台程序。你走了:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{
    public interface ITest
    {
        int val {get; set; }
        List<ITest> Tests {get; set; }
    }
    public class Test1 : ITest
    {
        public int val { get; set; }
        public List<ITest> Tests {get; set; }
        public Test1()
        {
            Tests = new List<ITest>();
        }
    }
    public class Test2 : ITest
    {
        public int val { get; set; }
        public List<ITest> Tests {get; set; }
        public Test2()
        {
            Tests = new List<ITest>();
        }
    }
    public class Test3 : ITest
    {
        public int val { get; set; }
        public List<ITest> Tests {get; set; }
        public Test3()
        {
            Tests = new List<ITest>();
        }
    }
    public class Test4 : ITest
    {
        public int val { get; set; }
        public List<ITest> Tests {
            get { return new List<ITest>(); }
            set {} 
        }
    }
    class Program
    {
        public static int GetMinVal(ITest initialTest, out ITest testWithMinVal)
        {
            int minVal = initialTest.val;
            testWithMinVal = initialTest;
            foreach (ITest t in initialTest.Tests)
            {
                if (t.val < minVal)
                {
                    minVal = GetMinVal(t, out testWithMinVal);
                }
            }
            return minVal;
        }

        static void Main(string[] args)
        {
            Random r = new Random();
            Test1 test = new Test1();
            test.val = r.Next(100);
            for (int i = 0; i < 5; i++)
            {
                Test2 test2 = new Test2();
                test2.val = r.Next(100);
                for (int j = 0; j < 4; j++)
                {
                    Test3 test3 = new Test3();
                    test3.val = r.Next(100);
                    for (int k = 0; k < 3; k++)
                    {
                        Test4 test4 = new Test4();
                        test4.val = r.Next(100);
                        test3.Tests.Add(test4);
                    }
                    test2.Tests.Add(test3);
                }
                test.Tests.Add(test2);
            }
            ITest testA;
            int minVal = GetMinVal(test, out testA);
            Console.WriteLine(minVal);
        }
    }
}

我希望这会有所帮助......

答案 4 :(得分:0)

如果订单无关紧要,我强烈建议将数据存储在比List更合适的数据结构中。去玩小工具堆!

interface ILeftistHeap<T> : IEnumerable<T>
{
    Func<T, T, int> Comparer { get; }
    int Height { get; }
    T Item { get; }
    ILeftistHeap<T> Left { get; }
    ILeftistHeap<T> Right { get; }
    ILeftistHeap<T> Delete();
    ILeftistHeap<T> Add(T item);
    bool IsEmpty { get; }
}

sealed class LeftistHeap<T> : ILeftistHeap<T>
{
    private static IEnumerator<T> CreateEnumerator(ILeftistHeap<T> heap)
    {
        while (!heap.IsEmpty)
        {
            yield return heap.Item;
            heap = heap.Delete();
        }
    }

    private static ILeftistHeap<T> Balance(T item, Func<T, T, int> comparer, ILeftistHeap<T> a, ILeftistHeap<T> b)
    {
        if (a.Height >= b.Height) { return new LeftistHeap<T>(comparer, b.Height + 1, item, a, b);  }
        else { return new LeftistHeap<T>(comparer, a.Height + 1, item, b, a); }
    }

    public static ILeftistHeap<T> Merge(ILeftistHeap<T> x, ILeftistHeap<T> y)
    {
        if (x.IsEmpty) { return y; }
        else if (y.IsEmpty) { return x; }
        else
        {
            Func<T, T, int> comparer = x.Comparer;
            if (comparer(x.Item, y.Item) <= 0) { return Balance(x.Item, comparer, x.Left, Merge(x.Right, y)); }
            else { return Balance(y.Item, comparer, y.Left, Merge(x, y.Right)); }
        }
    }

    public static ILeftistHeap<T> Make(Func<T, T, int> comparer) { return EmptyHeap<T>.Make(comparer); }
    public static ILeftistHeap<T> Make(Func<T, T, int> comparer, T item)
    {
        EmptyHeap<T> empty = EmptyHeap<T>.Make(comparer);
        return new LeftistHeap<T>(comparer, 1, item, empty, empty);
    }

    public Func<T, T, int> Comparer { get; private set; }
    public int Height { get; private set; }
    public T Item { get; private set; }
    public ILeftistHeap<T> Left { get; private set; }
    public ILeftistHeap<T> Right { get; private set; }
    public ILeftistHeap<T> Add(T item) { return Merge(this, Make(this.Comparer).Add(item)); }
    public ILeftistHeap<T> Delete() { return Merge(this.Left, this.Right); }
    public bool IsEmpty { get { return false; } }

    protected LeftistHeap(Func<T, T, int> comparer, int height, T item, ILeftistHeap<T> left, ILeftistHeap<T> right)
    {
        this.Comparer = comparer;
        this.Height = height;
        this.Item = item;
        this.Left = left;
        this.Right = right;
    }

    public IEnumerator<T> GetEnumerator() { return LeftistHeap<T>.CreateEnumerator(this); }
    IEnumerator IEnumerable.GetEnumerator() { return LeftistHeap<T>.CreateEnumerator(this); }
}

sealed class EmptyHeap<T> : ILeftistHeap<T>
{
    private static IEnumerator<T> CreateEnumerator() { yield break; }
    public static EmptyHeap<T> Make(Func<T, T, int> comparer) { return new EmptyHeap<T>(comparer); }
    private EmptyHeap(Func<T, T, int> comparer) { this.Comparer = comparer; }
    public Func<T, T, int> Comparer { get; protected set; }
    public T Item { get { throw new Exception("Empty heap"); } }
    public int Height { get { return 0; } }
    public ILeftistHeap<T> Left { get { throw new Exception("Empty heap"); } }
    public ILeftistHeap<T> Right { get { throw new Exception("Empty heap"); } }
    public ILeftistHeap<T> Add(T item) { return LeftistHeap<T>.Make(this.Comparer, item); }
    public ILeftistHeap<T> Delete() { throw new Exception("Empty Heap"); }
    public bool IsEmpty { get { return true; } }
    public IEnumerator<T> GetEnumerator() { return EmptyHeap<T>.CreateEnumerator(); }
    IEnumerator IEnumerable.GetEnumerator() { return EmptyHeap<T>.CreateEnumerator(); }
}

向堆中添加项目是O(log n)。获得最小/最大值是O(1)。