3

I build a simple AVL tree as following, each node has key and value. Now I want to implement a method that could return the key of node which has the largest value. For example, if I have a tree like:

               (7,1)
             /       \
        (4,3)       (13,8)
        /  \       /      \
    (2,4) (6,3) (11,8)      (15,2)
     / \   /      /  \      /     \
(1,9)(3,0)(5,16)(9,2)(12,3)(14,3)(16,5)
                 / \
              (8,19)(10,4)

The method would return 8, as the node (8,19) has the largest value. Following is my avl tree and node constructor. I do try to implement this method by hand but somehow it doesn't work. I'd be grateful if someone coule help me.

public class AVLTreeImp<T extends Comparable<? super T>,V> implements AVLTree<T,V>{
    private Node<T, V> root;
    public class Node<T extends Comparable<? super T>,V> implements AVLTree.Node{
        T key;
        V value;
        Node<T,V> left;
        Node<T,V> right;
        Node<T,V> parent;
        int height;
        public Node(){
            this.key = null;
            this.left = null;
            this.right = null;
            this.parent = null;
            this.height = 0;
            this.value = null;
        }
        public Node(T key, V value, Node<T,V> left, Node<T,V> right){
            this.key = key;
            this.left = left;
            this.right = right;
            this.parent = null;
            this.height = 0;
            this.value = value;
        }
    }

    public AVLTreeImp(){
        this.root = null;
    }
@Override
    public void insert(T key, V value){
        root = insert(root,key,value);

    }
    private Node<T,V> insert(Node<T,V> node, T key, V value){
        if (node == null){
            node = new Node<T,V>(key, value,null,null);
        }else{
            if (key.compareTo(node.key) < 0){
                node.left = insert(node.left, key, value);
                if (!(isBalanced(node))) {
                    if (key.compareTo(node.left.key) < 0) {
                        node = leftLeftRotation(node);
                    } else {
                        node = leftRightRotation(node);
                    }
                }
            }else if (key.compareTo(node.key) > 0){
                node.right = insert(node.right,key,value);
                if (!(isBalanced(node))){
                    if (key.compareTo(node.right.key) > 0){
                        node = rightRightRotation(node);
                    }else{
                        node = rightLeftRotation(node);
                    }
                }
            }
        }
        regenerateHeight(node);
        return node;
    }

Below is my implementation of this method, I'm not sure what's wrong with this.

public Integer findMax(){
        Node<Integer,Integer> result = (Node<Integer,Integer>)root;
        result.value = 0;
        return findMax((Node<Integer, Integer>) root,result);
    }
    private Integer findMax(Node<Integer,Integer> node,Node<Integer,Integer> result){
        if (node == null){
            return result.key;
        }
        if (node.value > result.value || 
                (node.value == result.value && node.key.compareTo(result.key) < 0)){
            result = node;
        }
        findMax(node.left,result);
        findMax(node.right,result);
        return result.key;
    }
simon s
  • 135
  • 1
  • 4
  • 15
  • 1
    You need to traverse an entire tree to do that, BST is not about value queries. – DAle Oct 19 '17 at 07:30
  • I think there is some misunderstanding; in your example, the value of the root node is `1`. However, its left child hase value `3` (which is larger than `1`) and its right child has value `8` (which is also larger than `1`), so your example seems not to be a search tree. Please clarify. – Codor Oct 19 '17 at 07:33
  • 1
    @Codor the tree is organized according to the key, not the value. – Henry Oct 19 '17 at 07:39
  • @Henry Ok, thanks for the clarification. – Codor Oct 19 '17 at 07:41

2 Answers2

4

You have a balanced BST! That means operations like the following are efficient,

  1. Insert/Remove
  2. Max/Min key
  3. Membership Query

But turns out, as comment suggested, you’d have to traverse the entire tree to find an element matching your criteria, which is a O(N) op, not optimal. Worse, your structure is recursive!

You can,

  1. Maintain a priority queue keyed by your “value”
  2. Build another tree keyed by your “value”

They are both far more efficient than a full tree look up.

However, without further context, I find you usage of the tree questionable? Why is your tree keyed by something you’re not operating on?

Shane Hsu
  • 7,937
  • 6
  • 39
  • 63
  • Hi Shane, thanks for your explanation. What I want to put in the tree is, for example, keys can be different classes and values can be the number of students. I use the class id as the key because it could be easier for inserting(adding) and searching element. If I treat the number of students as keys, though duplicates can be handled by using multimap, it's not easy to add elements to the tree. – simon s Oct 19 '17 at 08:12
  • What about trees within a tree? Outer tree keyed by class, inner tree by student. This is equivalent to a double dictionary. This seems to be efficient brought for your use case. – Shane Hsu Oct 19 '17 at 11:30
  • However, from what I’ve saw, implementing you own tree is time consuming, and frankly, I would’ve used the built-in HashMap. It has all the performance characteristics of the tree. But without full problem description and usage analysis, that’s all a moot poeint. – Shane Hsu Oct 19 '17 at 11:33
1

Your recursive findMax method is incorrect. You are assigning result = node; but this is only local assignment not updating result when calling findMax(node.left,result); and findMax(node.right,result); . This should work:

public Integer findMax(){
    Node<Integer,Integer> result = (Node<Integer,Integer>)root;
    result = findMax((Node<Integer, Integer>) root,result);
    return result.key;
}

private Node<Integer,Integer> findMax(Node<Integer,Integer> node,Node<Integer,Integer> result){
    if (node == null){
        return result;
    }
    if (node.value > result.value || 
            (node.value == result.value && node.key.compareTo(result.key) < 0)){
        result = node;
    }
    result = findMax(node.left,result);
    result = findMax(node.right,result);
    return result;
}

More about passing java parameters here Is Java "pass-by-reference" or "pass-by-value"?

Piro
  • 1,367
  • 2
  • 19
  • 40
  • Thanks, that's the problem. – simon s Oct 19 '17 at 08:38
  • ANYONE who has the same problem with me, line 3 of this code changes the value of root to 0, if anyone wants to make use of this, please get rid of this line. I don't know why I type this line myself.. – simon s Oct 19 '17 at 08:52