开发者

What is the Big O notation of this method?

开发者 https://www.devze.com 2023-03-13 06:37 出处:网络
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.

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 c开发者_开发知识库onditional 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);
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消