4
Class Diagnostic {

//Get the size in bytes of an object
static long sizeOf(Object object);

//Get the references for an object (leafs)
static List<Object> getRefs(Object object);

//Implement this with those above
public Long objectSize(Object object);
}

How would you implement objectSize to return the size in bytes of the object?

The method objectSize return the size in bytes of all children nodes combined (every node on the tree).

Example:

               Object A (19 bytes)
                      /    \
                     /      \
                   B(20)    C(37)
                   /
                  /
                C(15)

Answer: 19+20+37+15 = 91

I had this question during an interview and I am very curious to see others answers. Since, I didn't know much about tree traversal algorithm.

I came up with this... (I know it's bad or not ;) , just trying to learn)

    public Long objectSize(Object object) {
    List<Object> objectList = new ArrayList<Object>();

    Long sum = sizeOf(object);
    objectList = getRefs(object);

    for(Object object : objectList){
           sum += objectSize(object);
    }

return sum;
}

I noticed that I could have a cycle and run through a stackoverflow error, because I didn't check if I had already went trough a "node". Then I tough I should have another datastructure (like a hashmap for handling key/value) to handle temporary list for comparison.

fneron
  • 1,057
  • 3
  • 15
  • 39
  • Your question is unclear. Is `objectSize(Object object);` supposed to return the size of itself and all children nodes combined? – BLuFeNiX May 15 '13 at 13:47
  • 2
    You don't have cycles in a tree. – MAV May 15 '13 at 13:49
  • 1
    Trees don't have cycles, but your code may still run into cycles if the references of the structure don't actually form a DAG. By that I mean for every pair Object A and Object B, you could have A in getObjects(B) and B in getObjects(A) if for some reason the references are symmetrical. Otherwise, I think you meant `sum += objectSize(object);` in that loop. – G. Bach May 15 '13 at 13:59
  • Correct me if I'm wrong but in your example, the function should return `19 + 20 + 37 + 15 = 91`, am I right ? – Rerito May 15 '13 at 13:59
  • @G.Bach Indeed, you are right for both. – fneron May 15 '13 at 14:01
  • I assume you have declared `sum` as an instance variable or class variable. If that is the case, you will need to remember to always reset `sum` to `0` before you call the `objectSize` method. Otherwise, the algorithm seems to work fine. The fact that `sum` is an instance/class variable feels a bit weird though... – Alderath May 15 '13 at 14:02
  • @G.Bach Actually, if he puts `sum += objectSize(object);` in the loop, then the result for the example would be: "19 + 20 + 15 + 54 + 108 + 37 + 253" (i.e. 506). In his loop, the `sum` variable is an instance/class variable which is incremented each time a node is visited. – Alderath May 15 '13 at 14:13
  • @Alderath "In his loop, the sum variable is an instance/class variable which is incremented each time a node is visited." That's the idea, yeah. I don't see how you come up with those numbers. It's not like that would add the sum of the subtree every step in the hierarchy. – G. Bach May 15 '13 at 14:18
  • @G.Bach I was talking about the original question. The OP has updated the question now and made `sum` a local variable. I.e. `sum += sizeOf(object)` (an instance/class variable) has been replaced with `Long sum = sizeOf(object)` (a local variable). If he had kept `sum` as a class variable, the `sum` variable would've been doubled every time `sum += objectSize(object);` was called. – Alderath May 15 '13 at 14:29
  • @Alderath I see, I hadn't seen the initial version of the question. – G. Bach May 15 '13 at 14:33
  • @Alderath My bad! I just wrote my question to quick and made some errors while writing down my code. =/ – fneron May 15 '13 at 14:38
  • @G.Bach How would you attack the problem if it was actually a DAG? Would you use instead of a list an hashmap and verify if key as already been seen for instance... – fneron May 16 '13 at 15:09
  • @fneron If the reference structure you have actually forms a DAG, what you wrote works fine. If what you wrote terminates, you can be sure that your structure is a DAG as well, because otherwise any circle would put you in an endless recursive loop. – G. Bach May 16 '13 at 17:31

3 Answers3

2

If you're dealing with a true "tree" structure, then you don't have to worry about cycles.

You've got the basic idea, but you need to take the actual return value of the recursive call into account. If we assume that the object's total size (objectSize()) is equal to the sum of the sizes of its children plus its own size (sizeOf()), then you just need to make sure you're adding all the subtree sizes together.

Here's one way you could do it:

public Long objectSize(Object object) {
    List<Object> objectList = getRefs(object);
    long sum = sizeOf(object);

    for(Object object : objectList) {
         sum += objectSize(object);
    }

    return Long.valueOf(sum);
}

The thing you were missing was that the recursive objectSize call returned a value and that value needed to be included (in this case via addition) into your return value.

Platinum Azure
  • 45,269
  • 12
  • 110
  • 134
0

I did not test it but this simple BFS search algorithm should do it.

public Long objectSize(Object object) {
   long sum=sizeOf(object);

   Queue<Object> q= new LinkedList<Object>();
   for (Object o : getRefs(object)) {
      q.add(o);
   }
   while (q.peek() != null) {
      Object child= q.poll();
      sum+= sizeOf(child);
      fore (Object o : getRefs(child)) {
         q.add(o);
      }
   }
   return sum;   
}
darijan
  • 9,725
  • 25
  • 38
0

Here is what I would do :

I would build a stack containing the nodes that remains to be explored and process it in a while loop. Since my Java skills are lost somewhere in my mind I won't give you an implementation but I will explain the process :

Input : A tree T
Output: The total size of the node objects

  1. Initialize the stack S by pushing T.root (the root node) into it
  2. Initialize the total size size to 0 : size = 0
  3. While S is not empty :
    1. Let N be the head of S, we pop S : N = pop(S)
    2. Push N.leftChild and N.rightChild into S if they exist
    3. Update size : size = size + N.size
  4. Return size
Rerito
  • 5,886
  • 21
  • 47