数据结构之二叉树

41 阅读3分钟

概念:二叉树是每个结点最多有两个子树的树结构

一、为什么要使用二叉树?

因为它通常结合了另外两种数据结构的优点:一种是有序数组,另一种是链表。在树中查找数据项的速度和在有序数组中查找一样快,并且插入数据项和删除数据项的速度也和链表一样

二、java实现二叉树(新增、删除、查询、遍历)

package datasStructure;

import lombok.Data;

/**
 * @program: practise-model
 * @description: 二叉树
 * @author: lbw
 * @create: 2022-04-07 17:53
 **/

public class binaryNumber {
    //根节点
     Node root;
    @Data
     class Node {
        private int value;
        private Node left;
        private Node right;
        Node() {
        }

        Node(int value) {
            this.value = value;
        }
    }

向二叉树中插入节点

   
    public Node insertNode(int key) {
        Node node = new Node(key);
        if (root == null) {
            root=node;
            return node;
        }
        Node current = root;
        Node parent = null;
        //循环查找需要插入的节点prev
        //当p为null时候退出循环,此时prev为要插入key的上级节点
        while (current != null) {
            parent = current;
            if (key < current.getValue()) {
                current = current.getLeft();
            } else {
                current = current.getRight();
            }
        }
        if (key < parent.getValue()) {
            parent.left = node;
        } else {
            parent.right = node;
        }
        return node;
    }

删除二叉树节点,其中分为三种情况
1.该节点是叶节点,只要把父节点对应的子节点改成null即可

2.节点有一个子节点,删除该节点,只需要将需要删除的节点的唯一一个 子节点连接到需要删除的节点的父亲节点之上即可

3.有两个子节点,需要找到该删除节点的中序后继节点来替换当前删除的节点

其中第三种情况:

1649578429(1).png


    public boolean deleteNode(int value) {
        //引用当前节点,从根节点开始
        Node current = root;
        //应用当前节点的父节点
        Node parent = root;
        //是否为左节点
        boolean isleft = true;

        while (current.value != value) {
            parent = current;
            //进行比较,比较查找值和当前节点的大小
            if (current.value > value) {
                current = current.left;
                isleft = true;
            } else {
                current = current.right;
                isleft = false;
            }
            if (current == null) {
                return false;
            }
        }
        //1.该节点是叶节点,只要把父节点对应的子节点改成null即可
        if (current.left == null && current.right == null) {
            if (current == root) {
                root = null;
            } else if (isleft) {//如果它是父节点的左子节点
                parent.left = null;
            } else {
                parent.right = null;
            }
            return true;
        }
        //2.节点有一个子节点,删除该节点,只需要将需要删除的节点的唯一一个
        // 子节点连接到需要删除的节点的父亲节点之上即可
        if (current.right == null) {
            if (current == root) {
                root = current.left;
            } else if (isleft) {
                parent.left = current.left;
            } else {
                parent.right = current.left;
            }
            return true;
        }

        if (current.left == null) {
            if (current == root) {
                root = current.right;
            } else if (isleft) {
                parent.left = current.right;
            } else {
                parent.right = current.right;
            }
            return true;
        }

        //3.有两个子节点,需要找到该删除节点的中序后继节点来替换当前删除的节点

        Node successor = getSuccessor(current);
        System.out.println("successor:"+successor);
        if (current == root) {
            root = successor;
        } else if (isleft) {
            parent.left = successor;
        } else {
            parent.right = successor;
        }
        successor.left = current.left;
        return true;
    }

    /**
     * 这是寻找中序后继节点方法
     * 寻找中序后继节点.先找出待删除节点右子节点,然后一直往左边找到最小值,此节点就是中序后继节点
     *
     * @param delNode
     * @return
     */
    public Node getSuccessor(Node delNode) {

        Node successor = delNode;
        Node successorParent = delNode;
        Node current = delNode.right;
        while (current != null) {
            successorParent = successor;
            successor = current;
            current = current.left;
        }
        if (successor != delNode.right) {
            //将后继节点的父节点的左子节点值设置为后继的右子节点
            //后继节点的右子节点放置到后继节点父节点的左子节点
            successorParent.left = successor.right;
            //将删除的节点的整个右子树挂载到中继节点的右子树上
            //即把要删除的右子节点放置到中序后继节点右子节点
            successor.right = delNode.right;
        }
        return successor;
    }

遍历二叉树上的节点


    /**
     * 中序遍历
     */
    public void inOrder(Node localNode) {

        if (localNode != null) {
            //中序遍历左子树
            inOrder(localNode.left);
            //访问根节点
            System.out.println(localNode.value + "," + localNode.value);
            //中序遍历右子树
            inOrder(localNode.right);
        }
    }

   //这是查找node
   

查找二叉树上的节点

 public Node find(int key) {
     Node current = root;
     while (current != null) {
         if (current.value > key) {
             //当前值比查找值大 则继续遍历左子树
             current = current.left;
         } else if (current.value < key) {
             //当前值小于查找值 则继续遍历右子树
             current = current.right;
         } else {
             //查找到 返回
             return current;
         }
     }

     return null;
 }

 public static void main(String[] args) {

     binaryNumber binaryNumber=new binaryNumber();
     binaryNumber.insertNode(20);
     binaryNumber.insertNode(19);
     binaryNumber.insertNode(21);
     binaryNumber.insertNode(22);
     binaryNumber.insertNode(10);
     binaryNumber.insertNode(9);
     binaryNumber.insertNode(15);
     binaryNumber.insertNode(13);
     binaryNumber.insertNode(11);
     Node node=binaryNumber.find(20);
     binaryNumber.inOrder(node);
     System.out.println("========================");
     Node node1=binaryNumber.find(21);
     binaryNumber.inOrder(node1);
     System.out.println("========================");
     binaryNumber.deleteNode(10);
     Node node2=binaryNumber.find(20);
     binaryNumber.inOrder(node2);
 }


}

结果:

90d956c0ddc28ffabbf347f20c7cbc3.png