二叉查找树创建和查找

一、概念

二叉查找树也叫二叉搜索树(BST),是为了实现快 速查找而生的。不仅支持快速查找一个数据,还支持快速插入、删除一个数据。

二叉查找树要求,在树中的任意一个节点,其左子树中的每 个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值。

平衡二叉查找树的高度接近 logn,所以插入、删除、查找操作的时间复杂度也比较稳定,是 O(logn)。

二、操作

1、创建

2、节点定义

节点有顺序,所以实现 Comparable 接口

csharp 复制代码
public class BinaryNode<T> implements Comparable<T> {

    /**
     * 数据
     */
    T data;

    /**
     * 左节点
     */
    private BinaryNode left;

    /***
     * 右节点
     */
    private BinaryNode right;


    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public BinaryNode getLeft() {
        return left;
    }

    public void setLeft(BinaryNode left) {
        this.left = left;
    }

    public BinaryNode getRight() {
        return right;
    }

    public void setRight(BinaryNode right) {
        this.right = right;
    }

    @Override
    public int compareTo(T o) {
       return this.compareTo(o);
    }
}

2、树的定义

scala 复制代码
public class BinarySearchTree<T extends Comparable> {

    // 根节点
    private BinaryNode<T> root;

    // 树的节点数
    private int size = 0;


    public BinaryNode<T> getRoot() {
        return root;
    }

    public int getSize() {
        return size;
    }
}

3、添加节点

  1. 从根节点开始,依次比较要插入的数据和节点的大小关系;
  2. 插入的数据比节点数值大,并且节点的右子树为空,就将新数据直接插到右子节点的位置;不为空,就再递归遍历右子树,查找插入位置;
  3. 插入的数据比节点数值小,并且节点的左子树为空,就将新数据插入到左子节点的位置;不为空,就再递归遍历左子树,查找插入位置。
scss 复制代码
/**
 * 添加节点
 * @param data
 */
public void insert(T data) {
    BinaryNode<T> childNode = new BinaryNode<>();
    childNode.setData(data);
    // 根节点为空,直接作为根
    if (root == null) {
        root = childNode;
    } else {
        // 后续递归处理
        insert(root,childNode);
    }

}

/**
 * 实际的插入
 * @param pNode
 * @param childNode
 */
private void insert(BinaryNode<T> pNode, BinaryNode<T> childNode) {
    if (pNode == null) {
        pNode = childNode;
    }
    T pData = pNode.getData();
    T cData = childNode.getData();
    int compare = pData.compareTo(cData);
    // 父节点大于子节点
    if  (compare > 0) {
        // 父节点的左节点为空
        if (pNode.getLeft() == null) {
            pNode.setLeft(childNode);
        } else {
            // 向下递归
            insert(pNode.getLeft(),childNode);
        }
    } else if (compare < 0) {
        if (pNode.getRight() == null) {
            pNode.setRight(childNode);
        } else {
            insert(pNode.getRight(),childNode);
        }
    }
}

// 中序遍历进行测试
public List<T> midTraversal() {
    ArrayList<T> ts = new ArrayList<>();
    midTraversal(root,ts);
    return ts;
}


private void  midTraversal(BinaryNode<T> binaryNode,List<T> result) {
    if (binaryNode != null) {
        if (binaryNode.getLeft() != null) {
            midTraversal(binaryNode.getLeft(),result);
        }
        result.add(binaryNode.getData());
        if (binaryNode.getRight() != null) {
            midTraversal(binaryNode.getRight(),result);
        }
    }
}

测试方法

ini 复制代码
BinarySearchTree<Integer> binarySearchTree = new BinarySearchTree<>();

binarySearchTree.insert(6);
binarySearchTree.insert(4);
binarySearchTree.insert(8);
binarySearchTree.insert(5);
binarySearchTree.insert(3);
binarySearchTree.insert(7);
binarySearchTree.insert(9);

List<Integer> integers = binarySearchTree.midTraversal();

System.out.println(integers);

输出如下:

csharp 复制代码
[3, 4, 5, 6, 7, 8, 9]

2、查找

查找一个节点

  1. 找根节点,等于就返回;
  2. 比根节点小,左子树中递归查找;
  3. 比根节点大,右子树中递归查找
kotlin 复制代码
public Boolean find (T data) {
   return find(data,root);
}

private Boolean find(T data, BinaryNode<T> node) {
    while (node != null) {
        T data1 = node.getData();
        int compare = data1.compareTo(data);
        // 父节点大
        if (compare > 0) {
            node = node.getLeft();
        } else if (compare < 0) {
            node = node.getRight();
        } else {
            return true;
        }
    }
    return false;
}

3、删除

要删除节点的子节点个数的不同,分三种情况来处理。

  1. 要删除的节点没有子节点,只需要直接将父节点中,指向要删除节点的指 针置为 null。
  2. 要删除的节点只有一个子节点(只有左子节点或者右子节点),只需要更 新父节点中,指向要删除节点的指针,让它指向要删除节点的子节点就可以了。
  3. 要删除的节点有两个子节点。我们需要找到这个节点的右子树中的最小节点,把它替换到要删除的节点上,然后再删除掉这个最小节点。
ini 复制代码
public void del(T data) {

    BinaryNode<T> node = root;
    BinaryNode<T> parent = root;
    while (node != null) {
        T data1 = node.getData();
        int compare = data1.compareTo(data);
        // 父节点大
        if (compare > 0) {
            parent = node;
            node = node.getLeft();

        } else if (compare < 0) {
            parent = node;
            node = node.getRight();
        } else {
            // 找到了node节点,
            break;
        }
    }
    // 节点在树中不存在
    if (node == null) {
        return;
    }


    // 删除没有右节点的
    if (node.getRight() == null) {
        // 没有左节点
        if (node.getLeft() == null) {
            //删除父节点指向即可
            if (parent.getLeft().equals(node)) {
                parent.setLeft(null);
            }
            if (parent.getRight().equals(node)) {
                parent.setRight(null);
            }
            return;
        }
        // 获取左边节点的最大节点
        BinaryNode<T> maxLeft = node.getLeft();
        BinaryNode<T> PMaxLeft = node.getLeft();
        while (maxLeft.getRight() != null) {
            PMaxLeft = maxLeft;
            maxLeft = maxLeft.getRight();
        }
        // 删除这个节点
        if (PMaxLeft.getLeft().equals(maxLeft)) {
            PMaxLeft.setLeft(null);
        }
        if (PMaxLeft.getRight().equals(maxLeft)) {
            PMaxLeft.setRight(null);
        }
        // 值替换
        node.setData(maxLeft.getData());


    } else {
        // 获取右边节点最大值
        BinaryNode<T> maxRight = node.getRight();
        BinaryNode<T> PMaxRight = node.getRight();
        while (maxRight.getLeft() != null) {
            PMaxRight = maxRight;
            maxRight = maxRight.getLeft();
        }
        // 删除这个节点,主要是不知道是那边
        if (PMaxRight.getLeft().equals(maxRight)) {
            PMaxRight.setLeft(null);
        }
        if (PMaxRight.getRight().equals(maxRight)) {
            PMaxRight.setRight(null);
        }
        // 值替换
        node.setData(maxRight.getData());
    }

}

三、深度

ini 复制代码
public int depth() {
   return depth(root);
}

private int depth(BinaryNode<T> node) {
    int dep1 = 0, dep2 = 0;
    if (node == null) {
        return  0;
    }
    dep1 = depth( node.getLeft());
    dep2 = depth( node.getRight());
    if ( dep1 > dep2 ) {
        return dep1 + 1;
    }
    else {
        return dep2 + 1;
    }
}
相关推荐
倒头就睡的小比特4 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!4 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼4 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
旖旎夜光4 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark4 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her14 天前
并查集-听课笔记
笔记·算法·并查集
码流子4 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven4 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark4 天前
从算法设计模式看编程思维的抽象能力4
算法
2601_962218614 天前
万象生鲜系统称重自动多退少补算法解决生鲜非标品痛点
大数据·数据库·人工智能·python·算法