"Diversión de la entrada a las estructuras de datos avanzadas" árbol binario de búsqueda de búsqueda binaria Árbol

Este artículo proviene de liuyubobobo de "Diversión de la entrada a las estructuras de datos avanzadas" tutoriales de vídeo

La figura es un árbol binario de búsqueda, debido al gran número de caracteres chinos, hay muchas traducciones, tales como: árboles binarios de búsqueda, árboles binarios de búsqueda, ...............

Árbol binario de búsqueda de árbol binario en base, pero más de dos características:

1, el valor de los nodos binaria comparabilidad árbol de búsqueda que tiene.

2, cada nodo de su subárbol izquierdo elementos arbitrariamente grandes, y cualquier elemento menor que el subárbol derecho (este artículo no trata árboles duplican los elementos).

Utiliza el siguiente código de Java para lograr una mayor árbol de búsqueda binaria, recuperar, operación de eliminación.

definiciones de clase Nodo Nodo

private class Node {
    // 节点值
    public E e;
    // 每个节点都可能有左节点、右节点。最后一层的节点没有左右节点可以视为left、right都为null
    public Node left, right;

    public Node(E e) {
        this.e = e;
        left = null;
        right = null;
    }
}

aplicación árbol

//二分搜索树
public static class BinarySearchTree<E extends Comparable<E>> {
    private class Node {
        // 节点值,二分搜索树的值是有比较性的,所以泛型E必须是Comparable的子类
        public E e;
        // 每个节点都可能有左节点、右节点。最后一层的节点没有左右节点可以视为left、right都为null
        public Node left, right;

        public Node(E e) {
            this.e = e;
            left = null;
            right = null;
        }
    }

    // 树使用root节点作为索引,增查删都从root开始操作
    private Node root;
    // 树中节点的数量,即树的大小
    private int size;

    public BinarySearchTree() {
        root = null;
        size = 0;
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    // 在此添加增查删方法
}

Bajo el primer recursiva, la recursividad es realmente un gran problema, grande datos divididos en problemas más pequeños del mismo tipo, los datos algoritmo pequeña.

El árbol recursivo natural. Figura azul de lujo caja de árbol es una versión más pequeña de todo el árbol, por lo que el árbol tiene un travieso recursiva.

Añadir el nodo del árbol de código

        // 向二分搜索树中添加新的元素e
        public void add(E e){
            // 第一次添加的是根节点
            if(root == null){
                root = new Node(e);
                size ++;
            }else{
                add(root, e);  //递归添加元素
            }
        }

        // 向以node为根的二分搜索树中插入元素e,递归算法
        private void add(Node node, E e){
            // 不考虑相同元素的情况
            if(e.equals(node.e)){
                return;
            }else if(e.compareTo(node.e) < 0 && node.left == null){
                // 新增元素比当前节点小,且当前节点左边无节点,新元素插入左边
                node.left = new Node(e);
                size ++;
                return;
            }else if(e.compareTo(node.e) > 0 && node.right == null){
                // 新增元素比当前节点大,且当前节点右边无节点,新元素插入右边
                node.right = new Node(e);
                size ++;
                return;
            }

            // 新增元素比当前节点小,且当前节点左边有节点,递归处理当前元素左边的节点
            if(e.compareTo(node.e) < 0)
                add(node.left, e);
            else{
                //e.compareTo(node.e) > 0 的情况
                // 新增元素比当前节点大,且当前节点右边有节点,递归处理当前元素右边的节点
                add(node.right, e);
            }
        }

Código nuevo nodo anteriormente apreciará fácilmente, pero la cantidad de código de gran tamaño puede ser simplificado, como sigue:

        public void add(E e){
            // 使用root为索引
            root = add(root, e);
        }

        public Node add(Node node, E e){
            if (node == null){
                // 第一次添加元素,root就为new Node(e)
                size++;
                return new Node(e);
            }

            if (e.compareTo(node.e) < 0){
                // 在节点左边添加节点
                node.left = add(node.left, e);
            }else if (e.compareTo(node.e) > 0){
                // 在节点右边添加节点
                node.right = add(node.right, e);
            }
            return node;
        }

nodo de recorrido

La figura recorrido en el camino, se llama un orden previo recorrido

        // 前序遍历
        public void preOrder(){
            preOrder(root);
        }

        public void preOrder(Node node){
            if (node == null){
                return;
            }
            // 打印当前元素值
            System.out.println(node.e);
            preOrder(node.left);
            preOrder(node.right);
        }

En el recorrido orden, orden posterior recorrido

        // 中序遍历结果从大到小排序
        public void inOrder(){
            inOrder(root);
        }

        public void inOrder(Node node){
            if (node == null){
                return;
            }

            inOrder(node.left);
            System.out.println(node.e);
            inOrder(node.right);
        }

        // 后续遍历,先遍历父节点的子节点,在遍历父节点
        public void postOrder(){
            postOrder(root);
        }

        public void postOrder(Node node){
            if (node == null){
                return;
            }
            postOrder(node.left);
            postOrder(node.right);
            System.out.println(node.e);
        }

Escribir los próximos principales pruebas de función

       public static void main(String[] args) {
            BinarySearchTree<Integer> bts = new BinarySearchTree<>();
            int[] nums = {28, 16, 30, 22, 13, 42, 29};
            for (int num:nums){
                bts.add(num);
            }
            System.out.println("-------前序遍历------");
            bts.preOrder();
            System.out.println("------中序遍历-------");
            bts.inOrder();
            System.out.println("------后序遍历-------");
            bts.postOrde
        }

El preámbulo de la posterior, pertenecen a la orden de profundidad-primero, primero traversal para alcanzar el siguiente

En primer recorrido de 28, 16, 30 iterate de nuevo, finalmente atravesar 13,22,29,42. Se puede lograr a través de uno más de recorrido de amplitud primero de la cola.

El flujo se muestra anteriormente

1,28 en el equipo

2,28 a un equipo, y si el nodo de la izquierda y la derecha no está vacío, coloque aproximadamente 28 nodos (16, 30) en el equipo

3,16 un equipo, y si el nodo izquierdo y derecho no está vacía, el 16 a la izquierda y el nodo derecho (13, 22 en el equipo)

4,30 a un equipo, y si el nodo de la izquierda y la derecha no está vacía, el 30 a la izquierda y la derecha del nodo (29, 42 en el equipo)

Código se implementa de la siguiente manera:

        // 广度优先遍历
        public void levelOrder(){
            if (root == null){
                return;
            }
            Queue<Node> q = new LinkedBlockingQueue<>();
            q.add(root);
            while (!q.isEmpty()){
                Node node = q.remove();
                System.out.println(node.e);
                if (node.left != null)
                    q.add(node.left);
                if (node.right != null)
                    q.add(node.right);
            }
        }

Encontrar un árbol de mínimo, máximo. Cuando el nodo más a la izquierda del árbol node.left == null, entonces el valor del nodo mínimo. Cuando node.right == nodo del árbol nulo más a la derecha, el valor máximo de nodos.

Encontrar el valor mínimo de la realización anterior de la figura. Encontrar el valor máximo de una manera similar, que es encontrar la línea correcta de la forma más

// 最小值元素
public E minimum(){
    if(size == 0)
        throw new IllegalArgumentException("空树");
    Node minNode = minimum(root);
    return minNode.e;
}

// 最小值节点
private Node minimum(Node node){
    if( node.left == null )
        return node;
    return minimum(node.left);
}

// 最大值元素
public E maximum(){
    if(size == 0)
        throw new IllegalArgumentException("空树");
    return maximum(root).e;
}

// 最大值节点
private Node maximum(Node node){
    if( node.right == null )
        return node;
    return maximum(node.right);
}

mínimo de eliminación

        public E removeMin(){
            // 查找最小值
            E ret = minimum();
            // 删除最小节点
            root = removeMin(root);
            // 返回最小值
            return ret;
        }

        public Node removeMin(Node node){
            // node.left == null,node必然是最小节点
            if (node.left == null){
                // 先保存最小节点的right
                Node nodeRight = node.right;
                // 再把最小节点的right指向null,以便java虚拟机回收最小节点内存
                node.right = null;
                size--;
                return nodeRight;
            }
            // node.left != null,递归node.left
            node.left = removeMin(node.left);
            return node;
        }

Eliminar el valor máximo, acaba de dar el código, no el dibujo. Consulte a eliminar el valor mínimo de la lógica

        public E removeMax(){
            E ret = maximum();
            root = removeMax(root);
            return ret;
        }

        private Node removeMax(Node node){
            // node.right == null,节点必然是最大节点
            if(node.right == null){
                // 保存最大节点的right
                Node leftNode = node.left;
                node.left = null;
                size --;
                return leftNode;
            }
            // node.right != null,递归node.right
            node.right = removeMax(node.right);
            return node;
        }

Eliminar cualquier valor, la situación es cada vez más, de la siguiente manera:

1, nodo hijo izquierdo es nulo, se elimina el valor mínimo.

2, el nodo hijo derecho es nulo, es eliminar el máximo.

3, sobre el nodo hijo tiene un valor, elimine el valor usando el algoritmo Hibbard Supresión.

Hibbard Supresión se llama Hibbard en 1962, científicos de la computación, este algoritmo es simplemente esto: Suponiendo que el nodo eliminado es D, D tanto en niños como de izquierda, los niños tienen derecho, se puede utilizar el derecho d sub-árbol Alternativamente, la mínima d.

        public void remove(E e){
            remove(root, e);
        }

        private Node remove(Node node, E e){
            if (node == null)
                return null;
            if (e.compareTo(node.e) < 0){
                // 递归左侧节点
                node.left = remove(node.left, e);
                return node;
            }else if (e.compareTo(node.e) > 0){
                // 递归右侧节点
                node.right = remove(node.right, e);
                return node;
            }else {
                // 删除最小值
                if (node.left == null){
                    Node rightNode = node.right;
                    node.right = null;
                    size--;
                    return rightNode;
                }
                // 删除最大值
                if (node.right == null){
                    Node leftNode = node.left;
                    node.left=null;
                    size--;
                    return leftNode;
                }

                //当前node有左右孩子,找出右树中的最小节点successor
                Node successor = minimum(node.right);
                // successor.right = 删除当前node最小值后的树
                successor.right = removeMin(node.right);
                // successor.left = 当前node节点的left
                successor.left = node.left;
                node.left = node.right = null;
                // 返回successor
                return successor;
            }
        }

todos los códigos

//二分搜索树
public class BinarySearchTree<E extends Comparable<E>> {
    private class Node {
        // 节点值
        public E e;
        // 每个节点都可能有左节点、右节点。最后一层的节点没有左右节点可以视为left、right都为null
        public Node left, right;

        public Node(E e) {
            this.e = e;
            left = null;
            right = null;
        }
    }

    // 树使用root节点作为索引,增查删都从root开始操作
    private Node root;
    // 树中节点的数量,即树的大小
    private int size;

    public BinarySearchTree() {
        root = null;
        size = 0;
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public void add(E e){
        // 使用root为索引
        root = add(root, e);
    }

    public Node add(Node node, E e){
        if (node == null){
            // 第一次添加元素,root就为new Node(e)
            size++;
            return new Node(e);
        }

        if (e.compareTo(node.e) < 0){
            // 在节点左边添加节点
            node.left = add(node.left, e);
        }else if (e.compareTo(node.e) > 0){
            // 在节点右边添加节点
            node.right = add(node.right, e);
        }
        return node;
    }

    // 前序遍历
    public void preOrder(){
        preOrder(root);
    }

    public void preOrder(Node node){
        if (node == null){
            return;
        }
        // 打印当前元素值
        System.out.println(node.e);
        preOrder(node.left);
        preOrder(node.right);
    }

    // 中序遍历,结果从小到大排序
    public void inOrder(){
        inOrder(root);
    }

    public void inOrder(Node node){
        if (node == null){
            return;
        }

        inOrder(node.left);
        System.out.println(node.e);
        inOrder(node.right);
    }

    // 后序遍历,先遍历父节点的子节点,在遍历父节点
    public void postOrder(){
        postOrder(root);
    }

    public void postOrder(Node node){
        if (node == null){
            return;
        }
        postOrder(node.left);
        postOrder(node.right);
        System.out.println(node.e);
    }

    // 广度优先遍历
    public void levelOrder(){
        if (root == null){
            return;
        }
        Queue<Node> q = new LinkedBlockingQueue<>();
        q.add(root);
        while (!q.isEmpty()){
            Node node = q.remove();
            System.out.println(node.e);
            if (node.left != null)
                q.add(node.left);
            if (node.right != null)
                q.add(node.right);
        }
    }

    // 最小值元素
    public E minimum(){
        if(size == 0)
            throw new IllegalArgumentException("空树");
        Node minNode = minimum(root);
        return minNode.e;
    }

    // 最小值节点
    private Node minimum(Node node){
        if( node.left == null )
            return node;
        return minimum(node.left);
    }

    // 最大值元素
    public E maximum(){
        if(size == 0)
            throw new IllegalArgumentException("空树");
        return maximum(root).e;
    }

    // 最大值节点
    private Node maximum(Node node){
        if( node.right == null )
            return node;
        return maximum(node.right);
    }

    public E removeMin(){
        // 查找最小值
        E ret = minimum();
        // 删除最小节点
        root = removeMin(root);
        // 返回最小值
        return ret;
    }

    public Node removeMin(Node node){
        // node.left == null,node必然是最小节点
        if (node.left == null){
            // 先保存最小节点的right
            Node nodeRight = node.right;
            // 再把最小节点的right指向null,以便java虚拟机回收最小节点内存
            node.right = null;
            size--;
            return nodeRight;
        }
        // node.left != null,递归node.left
        node.left = removeMin(node.left);
        return node;
    }

    public E removeMax(){
        E ret = maximum();
        root = removeMax(root);
        return ret;
    }

    private Node removeMax(Node node){
        // node.right == null,节点必然是最大节点
        if(node.right == null){
            // 保存最大节点的right
            Node leftNode = node.left;
            node.left = null;
            size --;
            return leftNode;
        }
        // node.right != null,递归node.right
        node.right = removeMax(node.right);
        return node;
    }

    public void remove(E e){
        remove(root, e);
    }

    private Node remove(Node node, E e){
        if (node == null)
            return null;
        if (e.compareTo(node.e) < 0){
            // 递归左侧节点
            node.left = remove(node.left, e);
            return node;
        }else if (e.compareTo(node.e) > 0){
            // 递归右侧节点
            node.right = remove(node.right, e);
            return node;
        }else {
            // 删除最小值
            if (node.left == null){
                Node rightNode = node.right;
                node.right = null;
                size--;
                return rightNode;
            }
            // 删除最大值
            if (node.right == null){
                Node leftNode = node.left;
                node.left=null;
                size--;
                return leftNode;
            }

            //当前node有左右孩子,找出右树中的最小节点successor
            Node successor = minimum(node.right);
            // successor.right = 删除当前node最小值后的树
            successor.right = removeMin(node.right);
            // successor.left = 当前node节点的left
            successor.left = node.left;
            node.left = node.right = null;
            // 返回successor
            return successor;
        }
    }

    public static void main(String[] args) {

        _5_BinarySearchTree.BinarySearchTree<Integer> bst = new _5_BinarySearchTree.BinarySearchTree<>();
        int[] nums = {28, 16, 30, 22, 13, 42, 29};
        for (int num:nums){
            bst.add(num);
        }

        System.out.println("-------前序遍历------");
        bst.preOrder();
        System.out.println("------中序遍历-------");
        bst.inOrder();
        System.out.println("------后序遍历-------");
        bst.postOrder();
        System.out.println("------广度优先遍历-------");
        bst.levelOrder();


        ArrayList<Integer> nums2 = new ArrayList<>();

        //while(!bst.isEmpty())
        //    nums2.add(bst.removeMin());
        //System.out.println(nums2);

        //while(!bst.isEmpty())
        //    nums2.add(bst.removeMax());
        //System.out.println(nums2);


        //bst.remove(16);
        //bst.preOrder();

    }

}

 

 

 

Publicado 51 artículos originales · elogios ganado 14 · Vistas a 40000 +

Supongo que te gusta

Origin blog.csdn.net/u010606397/article/details/98464575
Recomendado
Clasificación