What would be a good algorithm for a circular reference check in this case?

前端 未结 2 1543
旧巷少年郎
旧巷少年郎 2021-02-19 03:12

Given you have the following class (bad C#, but you get the drift):

public abstract class AmICircular
{
  // assume Children is never null
  private List

        
2条回答
  •  南笙
    南笙 (楼主)
    2021-02-19 03:36

    In the case where you never add self-referencing (to be defined later) objects, your data structure describes a directed acyclic graph (http://en.wikipedia.org/wiki/Directed_acyclic_graph), where each instance of the of the IAmCircular class describes a node with a set of direct successor nodes = Children.

    Assuming the precondition that up to this moment, no cycle was created, the function you want, PerformCircularReferenceCheck, needs only to check if "this" is reachable from "target". If it is, it should return an exception.

    Complexity theory wise, this problem is ST-connectivity (http://en.wikipedia.org/wiki/St-connectivity) and is complete for the class NL (http://en.wikipedia.org/wiki/NL_(complexity)), even when you restrict the input to acyclic graphs (which is your case).

    In particular, Savitch's theorem (http://en.wikipedia.org/wiki/Savitch%27s_theorem) gives a constructive way to create a O(log^2 n) space algorithm (running in time O(n^2)) for it, where n is the number of nodes.

    Also, being NL-complete, it is unlikely that there exists an algorithm which runs in space O(log n) (i.e. use only a constant number of pointers to nodes), since that would imply the unlikely NL = L. EDIT: in particular, small variations of the hare and turtle algo suggested by someone would not work (because they would use too little space).

    I would recommend implementing the trivial O(n) time, O(n) space algorithm, which generates for "target" its set of successors (recursively) and verifying if "this" appears in this set.

    Be careful, the explicit construction of the set is important. Otherwise, if you just recursively verify if "this" is reachable by any successor of "target", you risk to run in exponential time.

    I recommended the O(n) time/O(n) space algorithm because it is asymptotically the best you can do time-wise, and you are already using O(n) space for your data structure.

提交回复
热议问题