Создание бинарного дерева поиска Java - PullRequest
1 голос
/ 25 марта 2012

Итак, вот класс Node:

public class Node
{
    private int _info;
    private Node _left;
    private Node _right;

    public Node()
    {
        //this._info = Integer.MIN_VALUE;
        this._left = null;
        this._right = null;
    }


    public int getInfo()
    {
        return _info;
    }

    public void setInfo(int _info)
    {
        this._info = _info;
    }

    public Node getLeft()
    {
        return _left;
    }

    public void setLeft(Node _left)
    {
        this._left = _left;
    }

    public Node getRight()
    {
        return _right;
    }

    public void setRight(Node _right)
    {
        this._right = _right;
    }  
}

Как создать дерево:

public class BalancedBinaryTree
{
    private ArrayList<Integer> _numbers;
    private Node _root;

    public BalancedBinaryTree(ArrayList<Integer> numbers)
    {
        this._numbers = new ArrayList<>();
        this._numbers.addAll(numbers);
        Collections.sort(this._numbers);

        this._root = new Node();

        this.create(this._root, 0, this._numbers.size());
    }

    private void create(Node tree, int i, int j)
    {
        if (i < j)
        {
            int m = i + (j - i) / 2;

            tree.setInfo(this._numbers.get(m));

            tree.setLeft(new Node());
            create(tree.getLeft(), i, m);

            tree.setRight(new Node());
            create(tree.getRight(), m + 1, j);
        }
    }

Этот метод вычисляет глубину:

    public static int getDepth(Node node)
    {
        if (node == null)
        {
            return 0;
        }
        else
        {
            int max = 0;
            if (getDepth(node.getLeft()) > getDepth(node.getRight()))
            {
                max = getDepth(node.getLeft());
            }
            else
            {
                max = getDepth(node.getRight());
            }
            return max + 1;
        }
    }

И эти два вместе должны напечатать дерево по его уровням:

    public static void printLevel(Node node, int levelToDisplay, int currentLevel)
    {
        if (node != null)
        {
            printLevel(node.getLeft(), levelToDisplay, currentLevel);
            if (currentLevel == levelToDisplay)
            {
                System.out.print(node.getInfo() + " ");
            }
            currentLevel++;
            printLevel(node.getRight(), levelToDisplay, currentLevel);
        }
    }

    public static void printLevels(Node node)
    {
        for (int i = 0; i < getDepth(node); i++)
        {
            System.out.println("Level :" + i);
            printLevel(node, i, 0);
            System.out.println();
        }
    }

В тестовом классе у меня есть:

    testNumbers.add(15);
    testNumbers.add(20);
    testNumbers.add(25);
    testNumbers.add(30);
    testNumbers.add(35);
    testNumbers.add(40);
    testNumbers.add(45);


    BalancedBinaryTree tree = new BalancedBinaryTree(testNumbers);
    BalancedBinaryTree.printLevels(tree.getRoot());

И я получаю этот вывод:

Level :0
0 15 20 30 
Level :1
0 0 25 0 35 40 
Level :2
0 0 0 45 
Level :3
0

Я должен получить

Level :0
30
Level :1
20 40
Level :2
15 25 35 45
  1. Что не так с методом getDepth, поскольку кажется, что он возвращает 4 уровня вместо 3?
  2. Почему существуют дополнительные узлы? (эти нули)

Я почти уверен, что решил проблемы, но мне понадобится объяснение следующего:

Это модифицированный printlevel метод:

public static void printLevel(Node node, int levelToDisplay, int currentLevel)
{
    if (node.getLeft() != null && node.getRight() != null)           
    {
        printLevel(node.getLeft(), levelToDisplay, currentLevel+1);  
        if (currentLevel == levelToDisplay)
        {
            System.out.print(node.getInfo() + " ");
        }
        printLevel(node.getRight(), levelToDisplay, currentLevel+1);  
    }
}

Как вы можете видеть, я проверяю, есть ли у текущего узла дочерние элементы, вместо того, чтобы проверять, существует ли текущий узел, и именно поэтому эти нули появляются, потому что обход достиг листьев, у которых не было информации, назначенной для их правого и левого дочерних элементов.

Вещь, которую я хочу понять, - это разница между увеличением currentLevel и последующей передачей его на вызов printLevel и простой передачей currentLevel+1 на вызов. Разве это не должно быть то же самое?

И функция getDepth:

public static int getDepth(Node node)
{
    if (node.getLeft() == null && node.getRight() == null)
    {
        return 0;
    }
    else
    {
        int max = 0;
        if (getDepth(node.getLeft()) > getDepth(node.getRight()))
        {
            max = getDepth(node.getLeft());
        }
        else
        {
            max = getDepth(node.getRight());
        }
        return 1 + max;
    }
}

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

1 Ответ

2 голосов
/ 26 марта 2012

Что не так с методом getDepth, потому что кажется, что он возвращает 4 уровня вместо 3?

Из вашего метода печати кажется, что вы нумеруете уровни от 0 до n (корень дерева 0).Однако ваш метод getDepth никогда не вернет 0. Две вещи: if (node != null) эта проверка не имеет особого смысла.Нуль не представляется допустимым входом (так как корень построен на построении дерева).Если это так (и вы хотите это проверить), может быть более подходящим исключение.Основная проблема, кажется, заключается в следующем: return max + 1;Таким образом, минимальное возвращаемое значение равно 0 + 1, что равно 1.

Как небольшая заметка: я бы сохранил значения двух рекурсивных вызовов getDepth, это значительно повысило бы производительность.Кроме того, если вы используете короткие имена переменных, такие как i, m или j (в виде нецикличного индекса), было бы полезно документировать их значение.

И сохранить ваш первый вопрос: tree.setLeft(new Node()); Какова будет стоимость этого узла на данный момент?И что будет, если кодировка i < j в повторном вызове не пройдет?Если вы сможете ответить на эти вопросы, вы сможете исправить код самостоятельно.

...