0

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 Answers1

0

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());
trincot
  • 317,000
  • 35
  • 244
  • 286
  • This is correct, but it is correct for an n-ary tree. However, my n-ary tree is represented as a binary tree (left-child, right-sibling representation), and sadly, your algorithm will not work on this type of representation. – Cristea Tudor Jan 21 '23 at 18:18
  • I don't understand the remark. Did you look at the code (even the first 6 lines)? This is a left-child, right-sibling implementation! – trincot Jan 21 '23 at 19:03
  • All right. Maybe I didn't properly understand the code. The n-ary tree provided by you, would look like this, as a binary tree: https://imgur.com/a/07kNjxy Would your algorithm work on this? – Cristea Tudor Jan 22 '23 at 16:20
  • That seems an attempt to depict the firstChild and nextSibling links as edges, but 7 is not a sibling of 9. It starts to get confusing if you are going to depict the **graph** with edges that are not the true edges of the graph, but are the links in the data structure. But did you try this code -- possibly implemented in your favourite programming language? What were your findings? Was there a problem? – trincot Jan 22 '23 at 19:22
  • NB: I added a visualisation of data structure in my answer. – trincot Jan 22 '23 at 19:37