【数据结构】二叉搜索树

目录

二叉搜索树

二叉搜索树不是空树就包含以下性质:

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值。
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值。
  • 它的左右子树也分别为二叉搜索树。

也就是说根节点左边比根节点小右边比根节点大。

二叉搜索树的模拟实现

一般实现的二叉搜索树中都不含有相同值的节点。

接口实现

实现的接口(成员方法)如下:

java 复制代码
public class BinarySearchTree {
    // 插入一个元素
    public boolean insert(int key) {}
    //查找key是否存在
    public TreeNode search(int key) {}
    //删除key的值
    public boolean remove(int key) {}
}

成员变量

我们使用内部类来表示二叉树的每一个节点。并定义出来根节点。

java 复制代码
static class TreeNode {
        public int key;
        public TreeNode left;
        public TreeNode right;
        TreeNode(int key) {
            this.key = key;
        }
    }
    public TreeNode root;

插入一个元素

逻辑就是插入一个元素总能在空节点位置找到该插入的位置。

就是下图中由黑线连接的空节点。

实现思路:

  1. 如果当前树为空则插入节点为根节点。
  2. 依次向下找到该插入的位置,同时要获得该位置的父亲节点。
  3. 最后插入。

注意:**一般实现的二叉搜索树中都不含有相同值的节点。**所以插入已有元素是不会成功的。

java 复制代码
	// 插入一个元素
	public boolean insert(int key) {
        TreeNode node = new TreeNode(key);
        if(root == null) root = node;
        TreeNode pre = null;
        TreeNode cur = root;
        
        while (cur != null){
            if(cur.key == key) {
                return false;
            } else if(cur.key > key) {
                pre = cur;
                cur = cur.left;
            } else {
                pre = cur;
                cur = cur.right;
            }
        }
        if(pre.key > key) pre.left = node;
        if(pre.key < key) pre.right = node;
        return true;
    }

查找key是否存在

逻辑与二分查找类似。

代码实现思路:

  1. 当前节点等于key,返回当前节点。
  2. 当前节点比key大就去左子树找。
  3. 当前节点比key小就去右子树找。
  4. 都没找到返回空。
java 复制代码
//查找key是否存在
    public TreeNode search(int key) {
        TreeNode cur = root;
        while(cur != null) {
            if(cur.key == key) return cur;
            if(cur.key < key) cur = cur.right;
            if(cur.key > key) cur = cur.left;
        }
        return null;
    }

查询分析:

最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:logN。

最差情况下,二叉搜索树退化为单支树,其平均比较次数为:N / 2。

删除key的值

实现思路:

  1. 设待删除结点为 cur, 待删除结点的双亲结点为 pre。

  2. cur.left == null:

    1) cur 是 root,则 root = cur.right,

    2)cur 不是 root,cur 是 parent.left,则 parent.left = cur.right,

    3)cur 不是 root,cur 是 parent.right,则 parent.right = cur.right。

  3. cur.right == null:

    1) cur 是 root,则 root = cur.left,

    2)cur 不是 root,cur 是 parent.left,则 parent.left = cur.left,

    3)cur 不是 root,cur 是 parent.right,则 parent.right = cur.left。

  4. cur.left != null && cur.right != null:

    两个思路:在左子树找最大值进行替换,右子树找最小值进行替换。

java 复制代码
//删除key的值
    public boolean remove(int key) {
        TreeNode node = new TreeNode(key);
        if(root == null) throw new NullPointerException();
        TreeNode pre = null;
        TreeNode cur = root;

        while (cur != null){
            if(cur.key == key) {
                removeNode(cur,pre);
                return true;
            } else if(cur.key > key) {
                pre = cur;
                cur = cur.left;
            } else {
                pre = cur;
                cur = cur.right;
            }
        }
        return false;
    }

    private void removeNode(TreeNode cur, TreeNode pre) {
        if(cur.left == null) {
          if(cur == root) {
              root = cur.right;
          } else if(cur == pre.right) {
              pre.right = cur.right;
          } else {
              pre.left = cur.right;
          }
        } else if(cur.right == null) {
            if(cur == root) {
                root = cur.left;
            } else if(cur == pre.right) {
                pre.right = cur.left;
            } else {
                pre.left = cur.left;
            }
        } else {
            //找到右树最小值替换
            TreeNode target = cur;
            pre =  cur;
           cur = cur.right;
           while (cur.left != null) {
               pre = cur;
               cur = cur.left;
           }
           //排除待删除节点左子树为空
           if(pre.right == cur) {
               pre = cur;
               return;
           }
           target.key = cur.key;
           cur = null;
        }
    }

TreeMap 和 TreeSet 即 java 中利用搜索树实现的 Map 和 Set;实际上用的是红黑树,而红黑树是一棵近似平衡的二叉搜索树,即在二叉搜索树的基础之上 + 颜色以及红黑树性质验证。

练习

二叉搜索树与双向链表

题目描述:

题解

解题思路:

要有一个前驱pre节点。 递归到上一级的时候 当前的根节点(pRootOfTree)就是pre的后继。

按中序遍历来遍历二叉搜索树即可。

java 复制代码
public class Solution {
    TreeNode pre = null;
    TreeNode head = null;
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree ==null) return null;
        Convert(pRootOfTree.left);
        if(head == null) {
            head = pRootOfTree;
        }
        if(pre != null) {
            pRootOfTree.left=pre;
            pre.right=pRootOfTree;
        }
        pre=pRootOfTree;
        Convert(pRootOfTree.right);
        return head;
    }
}
相关推荐
reyas34 分钟前
B树系列解析
数据结构·b树
快乐就好ya35 分钟前
Java多线程
java·开发语言
IT学长编程39 分钟前
计算机毕业设计 二手图书交易系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·二手图书交易系统
CS_GaoMing1 小时前
Centos7 JDK 多版本管理与 Maven 构建问题和注意!
java·开发语言·maven·centos7·java多版本
Indigo_code1 小时前
【数据结构】【顺序表算法】 删除特定值
数据结构·算法
艾伦~耶格尔2 小时前
Spring Boot 三层架构开发模式入门
java·spring boot·后端·架构·三层架构
man20172 小时前
基于spring boot的篮球论坛系统
java·spring boot·后端
阿史大杯茶2 小时前
Codeforces Round 976 (Div. 2 ABCDE题)视频讲解
数据结构·c++·算法
2401_858120532 小时前
Spring Boot框架下的大学生就业招聘平台
java·开发语言
S hh2 小时前
【Linux】进程地址空间
java·linux·运维·服务器·学习