Полное бинарное дерево поиска с вставкой порядка уровней в Java - PullRequest
0 голосов
/ 09 октября 2018

Мы получили задание, в котором нам нужно кодировать:

  • Бинарное дерево поиска
  • Дерево имеет , чтобы быть завершено , а не perfect (что означает, что все узлы, которые не находятся на самом низком уровне или на втором низшем уровне, должны иметь 2 дочерних элемента, тогда как узлы на самом низком уровне должны быть как можно левее)* Нам нужно вставить в дерево в порядке уровень
  • Так что, если у меня есть массив с элементами {0, 1, 2, 3, 4, 5, 6, 7}, root должно быть 4, с 2, 1, 3, 0 с левой стороны и 6, 5, 7 с правой стороны.

  • Вставка порядка уровней будет выглядеть следующим образом: 4, 2, 6, 1, 3, 5, 7, 0

  • Просто взять середину массива и поставить его как корень не работает,Если у вас есть массив от 1 до 9 элементов, у вас будет 4 как root (значение int в java, double будет 4.5), и вы получите 5 элементов с правой стороны и 4 с левой стороны.Это не полное дерево.Даже не идеальное дерево.

enter image description here

Мой код может быть вставлен только слева или справа в зависимости от того, больше ли он на корень меньше, чем корень, нетвставка порядка уровня.Параметр Anytype x - это значение, которое нужно вставить, а BinaryNode t - текущий узел, в котором мы находимся в дереве (это то, как мы сравниваем, если нам нужно вставить новое значение слева или справа)

private BinaryNode<AnyType> insert( AnyType x, BinaryNode<AnyType> t )
{
    if( t == null )
        return new BinaryNode<>( x, null, null );

    int compareResult = x.compareTo( t.element );

    if( compareResult < 0 )
        t.left = insert( x, t.left );
    else if( compareResult > 0 )
        t.right = insert( x, t.right );
    else
        ;  // Duplicate; do nothing
    return t;
}

Как я могу вставить в порядке уровней и при этом поддерживать двоичное дерево поиска?Должен ли я использовать какую-либо форму рекурсии?

Вся моя программа

import java.nio.BufferUnderflowException;
import java.util.*;

import static java.lang.Math.pow;

/**
 * Implements an unbalanced binary search tree.
 * Note that all "matching" is based on the compareTo method.
 * @author Mark Allen Weiss
 */
public class BinarySearchTree<AnyType extends Comparable<? super AnyType>>
{
    /**
     * Construct the tree.
     */
    public BinarySearchTree( )
    {
        root = null;
    }

    /**
     * Insert into the tree; duplicates are ignored.
     * @param x the item to insert.
     */
    public void insert( AnyType x )
    {
        root = insert( x, root );
    }

    /**
     * Test if the tree is logically empty.
     * @return true if empty, false otherwise.
     */
    public boolean isEmpty( )
    {
        return root == null;
    }

    /**
     * Print the tree contents in sorted order.
     */
    public void printTree( )
    {
        if( isEmpty( ) )
            System.out.println( "Empty tree" );
        else
            printTree( root );
    }

    /**
     * Internal method to insert into a subtree.
     * @param x the item to insert.
     * @param t the node that roots the subtree.
     * @return the new root of the subtree.
     */
    private BinaryNode<AnyType> insert( AnyType x, BinaryNode<AnyType> t )
    {
        if( t == null )
            return new BinaryNode<>( x, null, null );

        int compareResult = x.compareTo( t.element );

        if( compareResult < 0 )
            t.left = insert( x, t.left );
        else if( compareResult > 0 )
            t.right = insert( x, t.right );
        else
            ;  // Duplicate; do nothing
        return t;
    }

    /**
     * Internal method to print a subtree in sorted order.
     * @param t the node that roots the subtree.
     */
    private void printTree( BinaryNode<AnyType> t )
    {
        if( t != null )
        {
            printTree( t.left );
            System.out.println( t.element );
            printTree( t.right );
        }
    }

    /**
     * Internal method to compute height of a subtree.
     * @param t the node that roots the subtree.
     */
    private int height( BinaryNode<AnyType> t )
    {
        if( t == null )
            return -1;
        else
            return 1 + Math.max( height( t.left ), height( t.right ) );    
    }

    // Basic node stored in unbalanced binary search trees
    private static class BinaryNode<AnyType>
    {
            // Constructors
        BinaryNode( AnyType theElement )
        {
            this( theElement, null, null );
        }

        BinaryNode( AnyType theElement, BinaryNode<AnyType> lt, BinaryNode<AnyType> rt )
        {
            element  = theElement;
            left     = lt;
            right    = rt;
        }

        AnyType element;            // The data in the node
        BinaryNode<AnyType> left;   // Left child
        BinaryNode<AnyType> right;  // Right child
    }

      /** The tree root. */
    private BinaryNode<AnyType> root;

        // Test program
    public static void main( String [ ] args )
    {
        BinarySearchTree<Integer> t = new BinarySearchTree<>( );

        t.insert(2);
        t.insert(1);
        t.insert(3);
        t.printTree();
    }
}

Ответы [ 2 ]

0 голосов
/ 11 октября 2018

Полная часть BST заняла немного времени, чтобы разобраться, что это на самом деле.Ваше требование также требует вставки уровня заказа.Я не могу сказать, что это «вставляет», но это создает BST на уровне порядка.

Входной список должен быть отсортирован первым.

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

Как было замечено, полная часть сложнее.Способ справиться с этим - вычислить корень для списка иначе, чем обычное сбалансированное дерево.В нормальном сбалансированном дереве корневой индекс имеет длину / 2.Чтобы BST был завершен, корневой индекс должен быть смещен, чтобы узлы, которые обычно появлялись бы с правой стороны корня, вместо этого появлялись с левой стороны корня.Пока вычисления работают для любого списка длин, каждый разделенный подсписок строится правильно.

Из того, что я могу сказать, вычисление смещения осуществляется путем увеличения смещения для каждого дополнительного элемента в длине до тех пор, пока вы не достигнете 1/2 ширины уровня.Итак, BST с высотой 4 имеет 8 элементов на самом низком уровне.Списки размером 8, 9, 10,… 15 создают BST с высотой 4. Для этих списков корневой индекс в списке равен 4, 5, 6, 7, 7, 7, 7, 7.

Кажется, работает.

public class Node<T extends Comparable<T>> {
    protected Node<T> left;
    protected Node<T> right;
    protected T data;   
}

public class BTree<T extends Comparable<T>> {
    private Node<T> root = new Node<>();
    public void addData(T data) {
        Node<T> parent = root;
        while (parent.data != null ) {
            if ( data.compareTo( parent.data ) > 0 ) {
                if ( parent.right == null ) 
                    parent.right = new Node<>();
                parent = parent.right;
            } else {
                if ( parent.left == null ) 
                    parent.left = new Node<>();
                parent = parent.left;
            }
        }
        parent.data = data;
    }
}

private void run() {
    for ( int i = 2; i < 65; ++i ) {
        List<Integer> intList = IntStream.range(1, i).boxed().collect(Collectors.toList());
        BTree<Integer> bTree = new BTree<>();
        List<List<Integer>> splitLists = new ArrayList<>();
        splitLists.add(intList);
        while (splitLists.size() > 0 ) {
            List<List<Integer>> tSplitLists = new ArrayList<>();
            for ( List<Integer> tIntList: splitLists) {
                int length = tIntList.size();
                // compute starting point
                int mid = calcMid(length);      // length/2 ; //+ calcOffset(length);
                bTree.addData(tIntList.get(mid));
                if ( mid - 0 > 0)
                    tSplitLists.add(tIntList.subList(0, mid));
                if ( length - (mid+1) > 0)
                    tSplitLists.add(tIntList.subList(mid+1, length));
            }
            splitLists = tSplitLists;
        }
        bTree.printNode();
    }
}
private int calcMid(int length) {
    if ( length <= 4 )
        return length / 2;
    int levelSize = 1;
    int total = 1;
    while ( total < length ) {
        levelSize *= 2;
        total += levelSize;
    }
    int excess = length - (total - levelSize);
    int minMid = (total - levelSize + 1) / 2;
    if ( excess <= levelSize / 2 ) {
        return minMid + (excess - 1); 
    } else {
        int midExcess = levelSize/2; 
        return minMid + (midExcess - 1);
    }

}

См. Как распечатать диаграмму двоичного дерева? код для печати двоичного дерева.

PS> Я уверен, что вы можетесделать его немного лучше, очистив и скопировав списки вместо того, чтобы каждый раз создавать новые.

РЕДАКТИРОВАТЬ: Вы пошли и получили код printNode, указанный выше?

1 

 2   
/   
1   

 2   
/ \ 
1 3

   3       
  / \   
 /   \  
 2   4   
/       
1

И такна…

0 голосов
/ 10 октября 2018

Я думаю, что вы должны сделать это таким образом (код на C #, но не должно быть очень сложно преобразовать его в Java):

//list should be sorted
public void myFunc(List<int> list){
        Queue<List<int>> queue = new Queue<List<int>>();
         queue.Enqueue(list);

        while(queue.Any()){
            List<int> l = queue.Dequeue();
            int rindex = findRoot(l);
            //print r or store it somewhere
            Console.WriteLine(l.ElementAt(rindex));
            List<int> leftlist = l.GetRange(0, rindex);
            List<int> rightlist = l.GetRange(rindex + 1, l.Count-rindex-1);
            //leftlist = list l from index 0 to r-1; rightlist = list l from index r+1 to end.
            if (leftlist.Any())
            {
                queue.Enqueue(leftlist);
            }

            if (rightlist.Any())
            {
                queue.Enqueue(rightlist);
            }

        }

    }

****** РЕДАКТИРОВАТЬ: *********************************************

Длянаходя корень каждый раз, когда у вас есть список размера n, выполните следующие действия:

public int findRoot(List<int> list)
        {
            int n = list.Count;

            double h = Math.Ceiling(Math.Log(n + 1, 2)) - 1;

            double totNodesInCompleteBinaryTreeOfHeighthMinusOne = Math.Pow(2, h) - 1;
            double nodesOnLastLevel = n - totNodesInCompleteBinaryTreeOfHeighthMinusOne;

            double nodesOnLastLevelInRightSubtree = 0;

            if (nodesOnLastLevel > Math.Pow(2, h - 1))
            {
                nodesOnLastLevelInRightSubtree = nodesOnLastLevel - Math.Pow(2, h - 1);
            }

            int rindex = (int)(n - nodesOnLastLevelInRightSubtree - 1 - ((totNodesInCompleteBinaryTreeOfHeighthMinusOne - 1) / 2));

            return rindex;
        }
...