views:

557

answers:

4

I need a class Person to describe persons. Each person has a name and an array consisting of Person-objects, which represent the person's children. The person class has a method getNumberOfDescendants, which returns an integer equal to the total number of descendants of the person, i.e. his children plus grandchildren plus their children etc. Is there a simple way to do this using recursion?

What if you want to count the descendants in a certain generation only? In other words, getNumberOfDescendants(int generation) would return the number of children if generation=1, number of grandchildren if generation=2 etc.

+4  A: 
getNumberOfDescendants()
{
  int sum = 0;
  for (int n=0; n < descendants.length; n++)
  {
    sum += 1 + descendants[n].getNumberOfDescendants();
  }
  return sum;
}

Note that the "1 +" is the only place where we're actually increasing the count. That line gets called once for every descendant in the tree.

Nate C-K
Only problem here is the assumption the descendants array will never be null.
JacobM
True... I guess I was thinking in terms of collections where even an empty one will still usually have an object allocated that you can traverse (0 times). Does Java allow 0-length arrays?
Nate C-K
Yes, the array can exist but have a zero length, in which case your code will work.
JacobM
If the descendants array is null, it's .length will be 0, and the loop won't be entered.
D'Nabre
D'Nabre: No, if the array is initialized but has no members, it's .length will be 0, but if it's null, calling .length on it will cause a null pointer exception.
JacobM
+4  A: 

Sure.

public class Person {

private Person[] myChildren;

public int getNumberOfDescendants() {
  if (myChildren == null || myChildren.length==0) return 0;
  int myDescendants = 0;
  for (Person child:myChildren) {
    myDescendants += 1; // for this particular child itself
    myDescendants += child.getNumberOfDescendants();  //add the child's children, grandchildren, etc.
  }
  return myDescendants;
}

}
JacobM
Note that the two lines that do the incrementing could easily be replaced with a single line "myChildren += 1 + child.getNumberOfDescendants();". I did it as two lines for clarity and ease of commenting.
JacobM
Yes, that's the way I finally wrote it. Anyway, thanks for example, now I got the hang of recursion in this.
rize
You are aware that this doesn't compile right?
mR_fr0g
Fixed a small problem (hadn't specified the return type). Compiles now.
JacobM
A: 

It's not really recursion, per se, but an instance of the class could sum the results of calling the getNumberOfDescendants() method for each of its children.

Alternatively, you could make this method faster by having each instance notify its parent whenever it got a new descendant (either a new child or from being notified by a child). That way, its count of the number of descendants would always be up-to-date.

Steve Emmerson
A: 
  public int getNumberDescendents()
  {
    int nDesc = 0;
    if (descendants != null)
    {
      for (Person p : descendants)
      {
        nDesc++; // this child
        nDesc += p.getNumberDescendents(); // this child's desc
      }
    }
    return nDesc;
  }

By the time I wrote the example up, others had posted basically the same thing, so I am kind of redundantly posting.

PaulP1975
If you put 4 spaces at the beginning of each line, it will put the code in a nice formatted code block.
Nate C-K
Thanks for the tip Nate and for the edit JacobM!
PaulP1975