Diameter of an N-ary Tree represented as a Binary Tree

57 views Asked by At

I need to compute the diameter of an N-ary tree represented as a Binary Tree (left-child, right-sibling representation). Can someone give me an idea or a pseudocode?

My best attempt was to add a +1 to the result whenever there was a left child, but I do not think that this is enough.

1

There are 1 answers

5
trincot On

The idea is to traverse the tree in a post-order traversal, collecting two pieces of information about each node:

  • Its height
  • Its diameter

When this information is known for each of the children of a given node, then you can find out which are the two subtrees with the greatest heights. The sum of these two heights represents a candidate for a diameter for the current node. It should be compared with the diameters retrieved for each of the children. The greatest of these all is the diameter of the current node.

And so the diameter can bubble up out of recursion.

Here is an (runnable) implementation in JavaScript that executes the process on this example n-ary tree:

                _ _0_
               / / | \
              1 2 11  12
               / \   
              3   8 
             /|\  |
            4 5 7 9
             /   / 
            6  10

Note that the longest path in this tree connects node 6 with node 10, giving a path length of 6, which is the diameter of the whole tree.

If we picture the data structure, not with the above edges, but with its links to nodes, then it looks like this (downward arrows = firstChild; rightward arrows = nextSibling):

          0
          ↓
          1 → 2  →  11  →  12
              ↓  
              3  →   8 
              ↓      ↓
              4→5→7  9
                ↓    ↓ 
                6    10

Here is an implementation to solve the problem with that data structure:

class Node {
    constructor(value, firstChild=null, nextSibling=null) {
        this.value = value;
        this.firstChild = firstChild;
        this.nextSibling = nextSibling;
    }
    
    getInfo() {
        let greatestHeight = 0;
        let secondGreatestHeight = 0;
        let greatestDiameter = 0;
        
        for (let child = this.firstChild; child; child = child.nextSibling) {
            let [height, diameter] = child.getInfo();
            height++;
            if (height > greatestHeight) {
                secondGreatestHeight = greatestHeight;
                greatestHeight = height;
            } else if (height > secondGreatestHeight) {
                secondGreatestHeight = height;
            }
            if (diameter > greatestDiameter) {
                greatestDiameter = diameter;
            }
        }
        const diameter = greatestHeight + secondGreatestHeight;
        if (diameter > greatestDiameter) {
            greatestDiameter = diameter;
        }
        return [greatestHeight, greatestDiameter];
    }

    getDiameter() {
        const [height, diameter] = this.getInfo();
        return diameter; // We don't need the height anymore
    }
}

// Create the example tree:
const tree = new Node(0,
    new Node(1,
        null,
    new Node(2,
        new Node(3,
            new Node(4, 
                null, 
            new Node(5,
                new Node(6),
            new Node(7))),
        new Node(8,
            new Node(9,
                new Node(10)))),
    new Node(11,
        null,
    new Node(12)))));

// Print the diameter:
console.log("diameter:", tree.getDiameter());