二叉查找树

二叉查找树

1.1二叉树与散列表对比

二叉树最大的特点就是支持动态的快速插入、删除、查找等操作。

散列表也是支持这些操作的,而且散列表的这些操作都是比二叉树要高效,时间复杂度都是o(1),既然有了这么高效的散列表,为什么还要有二叉树呢?

  • 一,散列表是无序存储的,如果要有序输出,还是需要进行排序的,对于顺序二叉树来说,直接中序遍历输出的结果就是有序的。
  • 二,散列表的扩容缩容耗时很多,虽然我们可以吧这些操作均摊到其他的步骤上,但是整体来说的好事还是一定的。二叉树之需要考虑平衡的方案,而且这个方案比较成熟、固定。
  • 三,散列表存在散列冲突,会导致散列表的性能不太稳定,平衡二叉树的性能非常稳定,时间复杂度也会稳定在O(logn)。

总体来说散列表的设计比较复杂,散列函数的要求比较高,并且散列表的装载因子不能太大,特别是对于开放寻执法解决冲突的散列表,会浪费一定的存储空间。

两者各有各的优势,散列表效率极高,散列函数的设计和装载因子的设定根据对应的场景来确定。二叉树比较稳定,方案成熟,效率来讲偏低。

1.2二叉查找树(Binary Search Tree)

二叉查找树又叫二叉搜索树,是一种专门没了快速查找而生的数据结构。

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

1.2.1 二叉查找树的查找操作

二叉查找树要查找一个数,首先取根节点比较,大于根节点就在右子树中递归查找,小于根节点就在左子树中递归查找。

代码如下:

public class BinarySearchTree{
    private Node tree;
     public Node find(int data) {
    Node p = tree;
    while (p != null) {
      if (data < p.data) p = p.left;
      else if (data > p.data) p = p.right;
      else return p;
    }
    return null;
  }
  
    public static class Node { 
    	private int data;
    	private Node left;
        private Node right;
		public Node(int data){
            this.data=data;
		}
    }
}

1.2.2 二叉查找树的插入操作

二叉查找树的插入操作类似于查找操作,插入的数据都是在叶子节点上的。

  public void insert(int data) {
    if (tree == null) {
      tree = new Node(data);
      return;
    }

    Node p = tree;
    while (p != null) {
      if (data > p.data) {
        if (p.right == null) {
          p.right = new Node(data);
          return;
        }
        p = p.right;
      } else { // data < p.data
        if (p.left == null) {
          p.left = new Node(data);
          return;
        }
        p = p.left;
      }
    }
  }

1.2.3 二叉查找树的删除操作

二叉查找树的删除操作就比较复杂了。大致可以分为三种情况。

  • 删除的节点有左右两个字节点。需要找到对应节点右子树中的最小值,替换掉这个节点。然后删除右子树的最小节点。
  • 删除的节点没有子节点。直接删除就可以了。
  • 删除的节点只有一个字节点,把删除节点的父节点指向对应的字节就可以了。注意,左子节点还是左子节点,右子节点也还是右子节点。
public void delete(int data) {
    Node p = tree; // p指向要删除的节点,初始化指向根节点
    Node pp = null; // pp记录的是p的父节点
    while (p != null && p.data != data) {
      pp = p;
      if (data > p.data) p = p.right;
      else p = p.left;
    }
    if (p == null) return; // 没有找到

    // 要删除的节点有两个子节点
    if (p.left != null && p.right != null) { // 查找右子树中最小节点
      Node minP = p.right;
      Node minPP = p; // minPP表示minP的父节点
      while (minP.left != null) {
        minPP = minP;
        minP = minP.left;
      }
      p.data = minP.data; // 将minP的数据替换到p中
      p = minP; // 下面就变成了删除minP了
      pp = minPP;
    }

    // 删除节点是叶子节点或者仅有一个子节点
    Node child; // p的子节点
    if (p.left != null) child = p.left;
    else if (p.right != null) child = p.right;
    else child = null;

    if (pp == null) tree = child; // 删除的是根节点
    else if (pp.left == p) pp.left = child;
    else pp.right = child;
  }

1.3 二叉查找树的时间复杂度分析

如果二叉树的左右分布及其不平衡,时间复杂度就会退化到O(n),不管是二叉树的那种操作

他的时间复杂度都是根树的高度成正比。可以看出在二叉树左右相对平衡的情况下的时间复杂度为

O(long)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值