Как найти максимальное значение (не ключ) в дереве AVL?

Я строю простое дерево AVL, как показано ниже, у каждого узла есть ключ и значение. Теперь я хочу реализовать метод, который мог бы возвращать ключ узла с наибольшим значением. Например, если у меня есть такое дерево, как:

               (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)

Метод вернет 8, так как узел (8,19) имеет наибольшее значение. Ниже приведено мое дерево avl и конструктор узлов. Я пытаюсь реализовать этот метод вручную, но как-то не получается. Буду признателен, если кто-нибудь мне поможет.

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;
    }

Ниже моя реализация этого метода, я не уверен, что с этим не так.

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;
    }

person simon s    schedule 19.10.2017    source источник
comment
Для этого вам нужно пройти по всему дереву, BST - это не запросы значений.   -  person DAle    schedule 19.10.2017
comment
Я думаю, что тут какое-то недоразумение; в вашем примере значение корневого узла 1. Однако его левый дочерний элемент имеет значение 3 (которое больше, чем 1), а его правый дочерний элемент имеет значение 8 (которое также больше, чем 1), поэтому ваш пример, похоже, не является деревом поиска. Просьба уточнить.   -  person Codor    schedule 19.10.2017
comment
@Codor дерево организовано по ключу, а не по значению.   -  person Henry    schedule 19.10.2017
comment
@ Генри Хорошо, спасибо за разъяснения.   -  person Codor    schedule 19.10.2017


Ответы (2)


Ваш рекурсивный метод findMax неверен. Вы назначаете result = node; , но это только локальное назначение, не обновляющее результат при вызове findMax(node.left,result); и findMax(node.right,result);. Это должно работать:

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;
}

Подробнее о передаче параметров Java здесь Является ли передача Java по ссылке или передача по значению?

person Piro says Reinstate Monica    schedule 19.10.2017
comment
Спасибо, вот в чем проблема. - person simon s; 19.10.2017
comment
ЛЮБОЙ, у кого такая же проблема со мной, строка 3 этого кода изменяет значение root на 0, если кто-то хочет использовать это, пожалуйста, избавьтесь от этой строки. Не знаю, зачем я сам набираю эту строчку .. - person simon s; 19.10.2017

У вас сбалансированный BST! Это означает, что следующие операции эффективны:

  1. Вставить / Удалить
  2. Клавиша Max / Min
  3. Запрос на членство

Но оказывается, как предполагалось в комментарии, вам придется пройти по всему дереву, чтобы найти элемент, соответствующий вашим критериям, что является операцией O (N), а не оптимальным. Хуже того, ваша структура рекурсивна!

Ты сможешь,

  1. Поддерживайте приоритетную очередь, основанную на вашем «значении»
  2. Постройте еще одно дерево с ключом к вашему «значению»

Они оба намного более эффективны, чем просмотр полного дерева.

Однако, без дальнейшего контекста, я считаю, что использование дерева вызывает у вас сомнения? Почему ваше дерево связано с чем-то, над чем вы не работаете?

person Shane Hsu    schedule 19.10.2017
comment
Привет, Шейн, спасибо за объяснение. Что я хочу поместить в дерево, так это, например, ключи могут быть разными классами, а значения могут быть количеством студентов. Я использую идентификатор класса в качестве ключа, потому что это может быть проще для вставки (добавления) и поиска элемента. Если я рассматриваю количество студентов как ключи, хотя дубликаты могут обрабатываться с помощью multimap, добавлять элементы в дерево непросто. - person simon s; 19.10.2017
comment
А что насчет деревьев внутри дерева? Внешнее дерево с ключами по классам, внутреннее дерево по ученикам. Это эквивалент двойного словаря. Это кажется эффективным для вашего случая использования. - person Shane Hsu; 19.10.2017
comment
Однако из того, что я видел, реализация собственного дерева занимает много времени, и, честно говоря, я бы использовал встроенный HashMap. Обладает всеми эксплуатационными характеристиками дерева. Но без полного описания проблемы и анализа использования это спорный вопрос. - person Shane Hsu; 19.10.2017