1

给定类型:

class Field{
    public string Name{get;set;}
    public string[] DependsOn{get;set;}
}

假设我有一系列Field项目:

List<Field> fields = new List<Field>();
fields.Add(new Field() { Name = "FirstName" });
fields.Add(new Field() { Name = "FullName", 
                         DependsOn = new[] {"FirstName","LastName"}});
fields.Add(new Field() { Name = "Age", 
                         DependsOn = new[] { "DateOfBirth" } });
fields.Add(new Field() { Name = "LastName" });
fields.Add(new Field() { Name = "DateOfBirth" });

很明显,我们按以下顺序获取我们的项目:

  1. 全名
  2. 年龄
  3. 出生日期

我的第一个问题: 重新排列列表/数组中的项目的最佳方法是什么,以便将依赖列(全名和年龄)放在它们依赖的列之后,例如:

  1. 全名
  2. 出生日期
  3. 年龄

所以像Age 这样的字段总是在它所依赖的DateOfBirth之后。

我的第二个问题:有没有办法检测循环依赖?即何时
Field1 取决于 Field2
Field2 取决于 Field3
Field3 取决于 Field1

所以我们不会陷入一个圈子。例如,当你大学毕业后,你需要有 2 年的工作经验才能找到工作。但是要获得工作经验,您首先需要有工作。

4

2 回答 2

3

听起来您需要按拓扑顺序对这些项目进行排序。网络上有很多页面,维基百科可能是一个很好的起点: http ://en.wikipedia.org/wiki/Topological_sort

于 2009-02-13T16:32:21.283 回答
1

感谢 Grzenio 的提示,我实际上在http://www.java2s.com/Code/Java/Collections-Data-Structure/Topologicalsorting.htm的 java 中找到了类似的东西

以下是 C# 改编:

class Class1
{
    public static void Run()
    {
        doTopologicalTest();
    }

    private static void doTopologicalTest()
    {
        List<Field> fields = new List<Field>();
        fields.Add(new Field() { Name = "FirstName" });
        fields.Add(new Field()
        {
            Name = "FullName",
            DependsOn = new[] { "FirstName", "LastName" }
        });
        fields.Add(new Field()
        {
            Name = "Age",
            DependsOn = new[] { "DateOfBirth" }
        });
        fields.Add(new Field() { Name = "LastName" });
        fields.Add(new Field() { Name = "DateOfBirth" });

        foreach (var field in fields)
        {
            Console.WriteLine(field.Name);
            if(field.DependsOn != null)
                foreach (var item in field.DependsOn)
                {
                    Console.WriteLine(" -{0}",item);
                }
        }

        Console.WriteLine("\n...Sorting...\n");

        int[] sortOrder = getTopologicalSortOrder(fields);

        for (int i = 0; i < sortOrder.Length; i++)
        {
            var field = fields[sortOrder[i]];
            Console.WriteLine(field.Name);
            if (field.DependsOn != null)
                foreach (var item in field.DependsOn)
                {
                    Console.WriteLine(" -{0}", item);
                }
        }

    }

    private static int[] getTopologicalSortOrder(List<Field> fields)
    {
        TopologicalSorter g = new TopologicalSorter(fields.Count);
        Dictionary<string, int> _indexes = new Dictionary<string, int>();

        //add vertices
        for (int i = 0; i < fields.Count; i++)
        {
            _indexes[fields[i].Name.ToLower()] = g.AddVertex(i);
        }

        //add edges
        for (int i = 0; i < fields.Count; i++)
        {
            if (fields[i].DependsOn != null)
            {
                for (int j = 0; j < fields[i].DependsOn.Length; j++)
                {
                    g.AddEdge(i,
                        _indexes[fields[i].DependsOn[j].ToLower()]);
                }
            }
        }

        int[] result = g.Sort();
        return result;

    }


    class Field
    {
        public string Name { get; set; }
        public string[] DependsOn { get; set; }
    }
}

以及 TopologicalSort.cs 的代码

class TopologicalSorter
{
    #region - Private Members -

    private readonly int[] _vertices; // list of vertices
    private readonly int[,] _matrix; // adjacency matrix
    private int _numVerts; // current number of vertices
    private readonly int[] _sortedArray;

    #endregion

    #region - CTors -

    public TopologicalSorter(int size)
    {
        _vertices = new int[size];
        _matrix = new int[size, size];
        _numVerts = 0;
        for (int i = 0; i < size; i++)
            for (int j = 0; j < size; j++)
                _matrix[i, j] = 0;
        _sortedArray = new int[size]; // sorted vert labels
    }

    #endregion

    #region - Public Methods -

    public int AddVertex(int vertex)
    {
        _vertices[_numVerts++] = vertex;
        return _numVerts - 1;
    }

    public void AddEdge(int start, int end)
    {
        _matrix[start, end] = 1;
    }

    public int[] Sort() // toplogical sort
    {
        while (_numVerts > 0) // while vertices remain,
        {
            // get a vertex with no successors, or -1
            int currentVertex = noSuccessors();
            if (currentVertex == -1) // must be a cycle                
                throw new Exception("ERROR: Graph has cycles");

            // insert vertex label in sorted array (start at end)
            _sortedArray[_numVerts - 1] = _vertices[currentVertex];

            deleteVertex(currentVertex); // delete vertex
        }

        // vertices all gone; return sortedArray
        return _sortedArray;
    }

    #endregion

    #region - Private Helper Methods -

    // returns vert with no successors (or -1 if no such verts)
    private int noSuccessors()
    {
        for (int row = 0; row < _numVerts; row++)
        {
            bool isEdge = false; // edge from row to column in adjMat
            for (int col = 0; col < _numVerts; col++)
            {
                if (_matrix[row, col] > 0) // if edge to another,
                {
                    isEdge = true;
                    break; // this vertex has a successor try another
                }
            }
            if (!isEdge) // if no edges, has no successors
                return row;
        }
        return -1; // no
    }

    private void deleteVertex(int delVert)
    {
        // if not last vertex, delete from vertexList
        if (delVert != _numVerts - 1)
        {
            for (int j = delVert; j < _numVerts - 1; j++)
                _vertices[j] = _vertices[j + 1];

            for (int row = delVert; row < _numVerts - 1; row++)
                moveRowUp(row, _numVerts);

            for (int col = delVert; col < _numVerts - 1; col++)
                moveColLeft(col, _numVerts - 1);
        }
        _numVerts--; // one less vertex
    }

    private void moveRowUp(int row, int length)
    {
        for (int col = 0; col < length; col++)
            _matrix[row, col] = _matrix[row + 1, col];
    }

    private void moveColLeft(int col, int length)
    {
        for (int row = 0; row < length; row++)
            _matrix[row, col] = _matrix[row, col + 1];
    }

    #endregion
}

……

于 2009-02-13T20:53:09.067 回答