二叉树基础(下):有了如此高效的散列表,为什么还需要二叉树?

二叉树基础(下):有了如此高效的散列表,为什么还需要二叉树?

特殊的二叉树:二叉查找树,支持动态数据集合的快速插入、删除、查找操作

二叉查找树(Binary Search Tree)

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

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;
    }
  }
}
2.二叉查找树的插入操作

从根节点开始,依次比较要插入的数据和节点的大小关系,若要插入的数据比节点数据大,并且右子树为空,直接插到右子节点位置,不为空,再递归遍历右子树查找插入位置

public void insert(int data){
  if(tree == null){
    tree = new Node(data);
    return;
  }
  
  Node p = tree;
  while(p != null ){
    if(data > p.data){
      p.right = new Node(data);
      return;
    }
    p = p.right;
  }else(
    if(p.left == null){
      p.left = new Node(data);
      return;
    }
    p = p.left;
    )
}
3.二叉查找树的删除操作

1.要删除的节点没有子节点,只需要将父节点中指向要删除节点的指针置为Null

2.要删除的节点只有一个子节点(左子节点或者右子节点),只需要更新父节点中指向要删除结点的指针,让其指向要删除节点的子节点即可

3.要删除的节点有两个子节点,需要找到该节点的右子树中的最小节点,替换到要删除的节点上,再删除掉该最小节点

public void delete(int data){
  Node p = tree;   //p指向要删除的节点,初始化指向根节点
  Node pp = null;   //pp记录的是p的父节点
  whie( 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;
}
4.二叉查找树的其他操作

中序遍历二叉查找树可以输出有序的数据序列,也叫二叉排序树

支持重复数据的二叉查找树

二叉查找树存储的是一个包含很多字段的对象,利用对象的某个字段作为键值来构建二叉查找树,把对象中的其他字段叫做卫星数据

如果存储的两个对象键值相同,怎样处理二叉查找树的操作?

1.每个节点不仅会存储一个数据,可以通过链表和支持动态扩容的数组等数据结构,把值相同的数据都存储同一节点

2.每个节点荣然只存储一个数据,在查找插入过程中,如果碰到一个节点的值与要插入数据的值相同,将该要插入的数据放到该节点的右子树,把这个新插入的数据当做大于这个节点的值处理

当要查找数据的时候,遇到值相同的节点,继续在右子树中查找,直到遇到叶子节点才停止

删除操作中,先查到到每个要删除的节点,再按删除操作的方法依次删除

时间复杂度与树的高度成正比,O(Height)

为什么还用二叉查找树?

1.散列表中数据是无序的,如果要输出有序的数据,先排序,而对于二叉查找树,只需要中序遍历即可,在O(N)时间复杂度内输出有序的数据序列

2.散列表耗时很多,当遇到散列冲突的时候性能不稳定,常用的平衡二叉树性能很稳定

3.散列表的构造比二叉树要复杂,比如散列函数的设计、冲突如何解决、扩容和缩容

如果通过编程求出一颗给定二叉树的确切高度?

1.深度优先思想的递归,分别求左右子树的高度,当前节点的高度就是左右子树中较大的那个+1

2.采用层次遍历的方式,每一层记录都记录下当前队列的长度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值