二叉查找树 Java实现

简介: 二叉查找树 Java实现定义:一棵二叉查找树是一棵二叉树,每个节点都含有一个Comparable的键(以及对应的值)。每个节点的键都大于左子树中任意节点的键而小于右子树中任意节点的键。image树的术语:Name Function路径 顺着连接点的边从一个节点走向另一个节点,所经过的节点的顺序排列就称为路径。

二叉查找树 Java实现
定义:
一棵二叉查找树是一棵二叉树,每个节点都含有一个Comparable的键(以及对应的值)。
每个节点的键都大于左子树中任意节点的键而小于右子树中任意节点的键。

image

树的术语:

Name Function
路径 顺着连接点的边从一个节点走向另一个节点,所经过的节点的顺序排列就称为路径。
根 树顶端的节点就称为根,一棵树只有一个根,如果要把一个节点和边的集合定义为树,那么从根到其他任何一个节点都必须有一条路径。
父节点 每个节点(除了根)都恰好有一条边向上连接到另一个节点,上面的节点就称为下面节点的“父节点”。
子节点 每个节点都可能有一条或多条边向下连接其他节点,下面的这些节点就称为它的“子节点”。
叶节点 没有子节点的节点称为“叶子节点”或简称“叶节点”。树只能有一个根,但是可以有很多叶节点。
子树 每个节点都可以作为子树的根,它和它所有的子节点,子节点的子节点等都含在子树中。
访问 当程序控制流程到达某个节点的时候,就称为“访问”这个节点,通常是为了在这个节点处执行某种操作,例如查看节点某个数据字段的值或者显示节点。
遍历 遍历树意味着要遵循某种特定的顺序访问树中的所有节点。
层 一个节点的层数是指从根开始到这个节点有多少“代”。
关键字 可以看到,对象中通常会有一个数据域被指定为关键字值。这个值通常用于查询或者其他操作。
二叉树 如果树中的每个节点最多只能有两个子节点,这样的树就称为“二叉树”。
性质:

若它的左子树不为空,则左子树上的所有节点的值都小于它的根节点的值;
若它的右子树不为空,则右子树上所有节点的值都大于它的根节点的值;
其他的左右子树也分别为二叉查找树;
二叉查找树是动态查找表,在查找的过程中可见添加和删除相应的元素,在这些操作中需要保持二叉查找树的以上性质。
根据其二叉树的特性,节点类如下:

public class Node {

public int index;//关键字段
public String data;//值
public Node leftNode;//左节点
public Node rightNode;//右节点

@Override
public boolean equals(Object obj) {
    return EqualsBuilder.reflectionEquals(this, obj);
}

@Override
public int hashCode() {
    return HashCodeBuilder.reflectionHashCode(this);
}

}
其中引用了commons-lang3包中的内容,作为对象进行比较

查找某个节点,相当于二分查找,如果小于当前节点,则走左边,如果大于当前节点,则走右边。当最后叶子节点还没有找到,则没有找到

public Node findNode(int key){

Node current = root;
while(current.index != key){
    if(key < current.index){//左节点
        current = current.leftNode;
    }else{//右节点
        current = current.rightNode;
    }
    if(current == null){
        return null;
    }
}
return current;

}
插入节点,按照插入的节点都不会出现重复关键字。每一次插入都将变为根节点的子节点,例如根节点关键字为1,接下来插入的节点则变为根节点的右子节点。

public void insertNode(int key,String value){

Node node = new Node();
node.index = key;
node.data = value;

if(root == null){
    root = node;
    return;
}
//找到插入节点的位置
Node parent = root;
Node current = root;
while(true){
    parent = current;
    if(key == current.index){
        return;
    }
    if(key < current.index){//左节点
        current = current.leftNode;
        if(current == null){//当前节点已经是叶子结点了
            parent.leftNode = node;    
            return;
        }
    }else{
        current = current.rightNode;
        if(current == null){
            parent.rightNode = node;
            return;
        }
    }
}

}
遍历节点,中序遍历.

调用自身来遍历节点的左子树
访问这个节点
掉用自身来遍历节点的右子树
public void inOrder(Node localRoot) {

if (localRoot != null) {
    inOrder(localRoot.leftNode);
    System.out.println("索引:" + localRoot.index + ",值:" + localRoot.data);
    inOrder(localRoot.rightNode);
}

}
删除节点,分三种情况:

删除节点没有子节点,那么将父节点的左节点或者是右节点设置为空
删除节点只有一个子节点,删除该节点后,该节点的子节点变为父节点的子节点,如果删除节点时父节点的左节点,那么父节点的左节点指向该节点的子节点,反之则右节点指向删除节点的子节点。
删除节点有两个字节点,删除了该节点后,则需要选择一个后继节点,并且还不破坏该二叉树的特性(左节点要小于右节点),一般是从删除节点的右节点中找到一个后继节点,而这个节点是右子树的最小值。
public boolean delete(int key) {

    Node current = root;
    Node parent = root;
    boolean isLeftChild = true;
    //找到被删除的节点,并标识该节点是否为左节点
    while (current.index != key) {
        parent = current;
        if (key < current.index) {
            isLeftChild = true;
            current = current.leftNode;
        } else {
            isLeftChild = false;
            current = current.rightNode;
        }
        if (current == null) {
            return false;
        }
    }
    //第一种情况,删除节点为子节点
    if (current.leftNode == null && current.rightNode == null) {
        if (current == root) {
            root = null;
        } else {
            if (isLeftChild) {
                parent.leftNode = null;
            } else {
                parent.rightNode = null;
            }
        }
    } else if ((current.leftNode != null && current.rightNode == null) || (current.leftNode == null && current.rightNode != null)) {
        //第二中情况,删除节点只包含一个子节点,则将子节点移动动当前节点中
        if (current.rightNode == null) {//删除的节点的左节点有值,右节点为空
            if (root == current) {
                root = current.leftNode;
            } else {
                if (isLeftChild) {
                    parent.leftNode = current.leftNode;
                } else {
                    parent.rightNode = current.leftNode;
                }
            }
        } else {//删除的节点的右节点有值,左节点为空
            if (root == current) {
                root = current.rightNode;
            } else {
                if (isLeftChild) {
                    parent.leftNode = current.rightNode;
                } else {
                    parent.rightNode = current.rightNode;
                }
            }
        }
    } else if (current.leftNode != null && current.rightNode != null) {
        //第三种情况,删除节点中有左右两个节点
        //找到后继节点
        Node processer = processer(current);
        if (current == root) {//删除是根节点,则
            root = processer;
        } else {
            if (isLeftChild) {
                parent.leftNode = processer;
            } else {
                parent.rightNode = processer;
            }
        }
        //选中的节点的左节点与删除节点的左节点相连
        processer.leftNode = current.leftNode;
    }
    return true;
}

//找到后继节点
private Node processer(Node delNode) {
    Node parent = delNode;
    Node success = delNode;
    Node current = delNode.rightNode;
    while (current != null) {
        // 后继节点父节点首先保存后继节点的状态
        parent = current;
        success = current;
        // 后继节点 不断的向左更新
        current = current.leftNode;
    }
    // 假如我们找到的后继节点不直接是 要删除节点的右节点  而是在其右节点那条子树上面最小的一个节点
    if (success != delNode.rightNode) {
        //后继节点的父节点断开其与后继节点左边的引用,重新连接上后继节点的右子节点(因为后继节点是没有左子节点的,锁以要保存之前树的状态,还要把后继节点的右子节点处理一下,不管 其存在不存在)
        parent.leftNode = success.rightNode;
        // 这时候后继节点的右边已经空了 上一条语句已经将其给了自己父节点的左子节点    然后让后继节点的右边 连接要删除节点的右子树
        success.rightNode = delNode.rightNode;
    }
    return success;
}

原文地址https://www.cnblogs.com/skyice/p/10618303.html

相关文章
|
3月前
|
存储 Java
1038. 从二叉搜索树到更大和树 --力扣 --JAVA
给定一个二叉搜索树 root (BST),请将它的每个节点的值替换成树中大于或者等于该节点值的所有节点值之和。 提醒一下, 二叉搜索树 满足下列约束条件: 节点的左子树仅包含键 小于 节点键的节点。 节点的右子树仅包含键 大于 节点键的节点。 左右子树也必须是二叉搜索树。
38 1
|
2月前
|
Java
AVL树(Java)
AVL树(Java)
29 0
|
3月前
|
Java
数据结构 AVL树概念以及实现插入的功能(含Java代码实现)
数据结构 AVL树概念以及实现插入的功能(含Java代码实现)
54 0
|
8月前
|
存储 算法 Java
2-3-4树【数据结构与算法java】
2-3-4树【数据结构与算法java】
50 1
|
8月前
|
存储 Java
Java数据结构之第十五章、Trie(前缀树/单词查找树)
1.前缀树的概念:前缀树又叫字典树或单词查找树(高效的存储和查找字符串集合的数据结构)。2.3.存储形式:存储的字符串可能:全是 小写字母 或全是 大写字母 或全是 数字 或全是 0和1。它是一棵,每个代表一个,从。字典树的根节点不包含字符,每个子节点代表一个字符,从根节点到任意一个节点所经过的路径上的字符连接起来即为该节点所代表的字符串。每个节点可以存储一个或多个字符串,通常使用一个标志来标记一个节点代表的字符串是否存在。当需要在一组字符串中查找某个字符串时,可以利用字典树来实现高效的查找操作。
45 0
|
8月前
|
算法 Java 数据库
树-用Java托举
树-用Java托举
|
Java
Java 实现汉字按照首字母分组排序
Java 实现汉字按照首字母分组排序
561 0
|
10月前
|
算法 Java
Java数据结构与算法分析(八)二叉查找树(BST)
二叉查找树又叫二叉排序树(Binary Sort Tree),或叫二叉搜索树,简称BST。BST是一种节点值之间有次序的二叉树。
58 0
|
算法 Java
基础算法题_最古老的树(java)
基础算法题_最古老的树(java)
树的子结构(剑指offer 26)Java先序遍历+子结构判断
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构) B是A的子结构, 即 A中有出现和B相同的结构和节点值。
树的子结构(剑指offer 26)Java先序遍历+子结构判断