Retrieve all the leaf nodes of java TreeMap

2019-09-03 09:58发布

问题:

Is there a way to retrieve all the leaf nodes of a Java TreeMap?

I have a TreeMap like this

TreeMap<String, FooBar> myTree = new TreeMap<String, FooBar>(new Comparator<String>() {
  public int compare(String o1, String o2)
  {
    int b1 = Integer.parseInt(o1, 2);
    int b2 = Integer.parseInt(o2, 2);
    return (b1 > b2 ? 1 : (b1 == b2 ? 0 : -2));
  }
});

How do I get all the leaf nodes of this tree?

回答1:

This doesn't make much sense to me. The elements stored at the leaves are dependent on how the implementation of TreeMap balances the tree.

But, let's say you needed to do this for some reason. To actually do this, you would need to do a bit of a hack: write a class packaged in java.util that can access the package private methods of TreeMap.

After doing some more digging, I found that the default tree implementation in the JDK is a red-black tree, and its Entry implementation look like the following:

static final class Entry<K,V> implements Map.Entry<K,V> {
    K key;
    V value;
    Entry<K,V> left = null;
    Entry<K,V> right = null;
    Entry<K,V> parent;
    boolean color = BLACK;

    ....

There doesn't seem to be any direct way to get at the root. But, if you can grab one of these Entryies, though, you can traverse the parent all the way up to the root, then do a traversal of the tree any way you want to get the leaves (Entry where left == null and right == null). An inorder traversal would preserve the sorted ordering.

But, to reiterate, I don't see any good reason why you'd want to do this. You'd also need to do it in the java.util package to be able to investigate those Entryies. But here's code, for fun. (You won't be able to execute this without overriding the security restrictions on the JVM.)

package java.util;

import java.util.TreeMap.Entry;

public class TreeMapHax {

    static <K,V> List<Entry<K, V>> getLeafEntries(TreeMap<K, V> map) {      
        Entry<K, V> root = map.getFirstEntry();
        while( root.parent != null ) root = root.parent;

        List<Entry<K,V>> l = new LinkedList<Entry<K,V>>();
        visitInOrderLeaves(root, l);
        return l;
    }

    static <K,V> void visitInOrderLeaves(Entry<K, V> node, List<Entry<K, V>> accum) {       
        if( node.left != null ) visitInOrderLeaves(node.left, accum);       
        if( node.left == null && node.right == null ) accum.add(node);      
        if( node.right != null ) visitInOrderLeaves(node.right, accum);
    }

    public static void main(String[] args) {
        TreeMap<String, Integer> map = new TreeMap<String, Integer>();

        for( int i = 0; i < 10; i++ )
            map.put(Integer.toString(i), i);

        System.out.println(getLeafEntries(map));
    }

}