简体   繁体   中英

What is the Big O notation of this method?

I have run across this method in our code base and wonder what the Big O is. The method takes a flat list and creates a tree, assigning the Parent and Children values as it goes.

private void AddChildren(Group group, IEnumerable<Group> groups)
{
    foreach (var g in groups)
    {
        if (g.ParentId == group.Id)
        {
            g.Parent = group;
            group.Children.Add(g);
            AddChildren(g, groups);
        }
    }
}

It's been a while since I have done Big O outside of identifying straight forward n^2 (or worse) methods, but my take on it goes like this:

  • We are iterating every node in the list, giving us n
  • We are using a conditional to process a subset of the items being iterated. There can be multiple matches here and don't know how to express that number, or how it modifies the recursive call to AddChildren
  • We have some simple assignments, and I don't know if that warrants a +1 modifier
  • We are recursing but it's not for every item in the enclosing iteration

Just tossing something out there so I can see if I was in the ballpark:

n + (x * n)

where x is the number of matches in the if loop.

Any thoughts on what this actually is would be great, thanks.

Observe that the recursive function is only called once per parent-child relationship. In a tree structure with n nodes, there are n - 1 such relationships, so AddChildren() is called n times (including the initial call). In each call, the work performed by the method itself (excluding the recursive call) is O(n) due to the iteration. Hence, O(n^2) in total.

You can improve the complexity to O(n) by putting all groups in a hashmap first and traverse the list once, looking up each parent node in the hashmap.

There is already a lot of discussion on the runtime order of your code, so I won't comment on that. Aasmund Eldhuset's answer looks correct to me.

Perhaps you want something like this, which is O(n) :

void AssignChildrenAndParent(IEnumerable<Group> groups)
{

    var groupById=new Dictionary<GroupId,Group>();
    foreach(Group group in groups)
    {
      groupById.Add(group.Id,group);
    }
    foreach(Group group in groups)
    {
       Group parent=groupsById(group.ParentId);
       group.Parent=parent;
       parent.Children.Add(group);
    }
}

This behaves a bit different from the original code because it fixes up all parent-child relationships, and not only those below the root.

Or if you really want code that that behaves exactly like your original code (once again O(n) if the hashes work well):

private void AddChildren(Group group, IEnumerable<Group> groups)
{
  var children=groups.ToLookup(group=>group.ParentId);
  AddChildren(group, groups, lookup); 
}

private void AddChildren(Group group, IEnumerable<Group> groups,Lookup<GroupId,Group> lookup)
{
    foreach (var g in lookup[group.Id])
    {
       g.Parent = group;
       group.Children.Add(g);
       AddChildren(g, groups,lookup);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM