二叉查找树创建和查找

一、概念

二叉查找树也叫二叉搜索树(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;
    }
}
相关推荐
Indigo_code2 小时前
【数据结构】【顺序表算法】 删除特定值
数据结构·算法
阿史大杯茶2 小时前
Codeforces Round 976 (Div. 2 ABCDE题)视频讲解
数据结构·c++·算法
LluckyYH3 小时前
代码随想录Day 58|拓扑排序、dijkstra算法精讲,题目:软件构建、参加科学大会
算法·深度优先·动态规划·软件构建·图论·dfs
转调3 小时前
每日一练:地下城游戏
开发语言·c++·算法·leetcode
不穿格子衬衫4 小时前
常用排序算法(下)
c语言·开发语言·数据结构·算法·排序算法·八大排序
wdxylb4 小时前
使用C++的OpenSSL 库实现 AES 加密和解密文件
开发语言·c++·算法
aqua35357423584 小时前
蓝桥杯-财务管理
java·c语言·数据结构·算法
CV金科4 小时前
蓝桥杯—STM32G431RBT6(IIC通信--EEPROM(AT24C02)存储器进行通信)
stm32·单片机·嵌入式硬件·算法·蓝桥杯
sewinger4 小时前
区间合并算法详解
算法
XY.散人4 小时前
初识算法 · 滑动窗口(1)
算法