二叉查找树

来源:互联网 发布:迅雷淘宝充值卡号密码 编辑:程序博客网 时间:2024/06/05 00:46

定义

二叉查找树(Binary Search Tree),也称二叉搜索树,是指一棵空树或者具有下列性质的二叉树:

  • 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 任意节点的左、右子树也分别为二叉查找树;
  • 没有键值相等的节点。

二叉查找树相比于其他数据结构的优势在于查找、插入的时间复杂度较低。为O(log n)。二叉查找树是基础性数据结构,用于构建更为抽象的数据结构,如集合、multiset、关联数组等。
这里写图片描述

二叉查找树是基于二叉树的,其结点数据结构定义为如下:

private class Node {     private Key key;                private Value val;         // 存储的数据     private Node left, right;  // 左或右子树     private int size;          // 子树的节点数     public Node(Key key, Value val, int size) {          this.key = key;          this.val = val;          this.size = size;      }  }

查找操作

在二叉查找树中查找x的过程如下:

1、若二叉树是空树,则查找失败。

2、若x等于根结点的数据,则查找成功,否则。

3、若x小于根结点的数据,则递归查找其左子树,否则。

4、递归查找其右子树。

根据上述的步骤,写出其查找操作的代码:

    public boolean contains(Key key) {        if (key == null) throw new IllegalArgumentException("argument to contains() is null");        return get(key) != null;    }    public Value get(Key key) {        return get(root, key);    }    private Value get(Node x, Key key) {        if (key == null) throw new IllegalArgumentException("called get() with a null key");        if (x == null) return null;        int cmp = key.compareTo(x.key);        if      (cmp < 0) return get(x.left, key);//递归进左子树查找        else if (cmp > 0) return get(x.right, key);//递归进右子树查找        else              return x.val;//查找命中    }

插入操作

二叉树查找树b插入操作x的过程如下:

1、若b是空树,则直接将插入的结点作为根结点插入。

2、x等于b的根结点的数据的值,则直接返回,否则。

3、若x小于b的根结点的数据的值,则将x要插入的结点的位置改变为b的左子树,否则。

4、将x要出入的结点的位置改变为b的右子树。

这里写图片描述

代码如下:

public void put(Key key, Value val) {        if (key == null) throw new IllegalArgumentException("calledput() with a null key");        if (val == null) {            delete(key);            return;        }        root = put(root, key, val);        assert check();    }    private Node put(Node x, Key key, Value val) {        if (x == null) return new Node(key, val, 1);        int cmp = key.compareTo(x.key);        if      (cmp < 0) x.left  = put(x.left,  key, val);        else if (cmp > 0) x.right = put(x.right, key, val);        else              x.val   = val;        x.size = 1 + size(x.left) + size(x.right);        return x;    }

删除操作

二叉查找树中最难实现的就是删除操作。下面是一个解决办法:
在删除节点x后,用他的后继节点填补它的位置。步奏如下:

1,将指向即将被删除的节点的链接保存为t;

2,将x指向它的后继节点min(t.right);

3,将x的右链接指向deleteMin(t.right);

4,将x的左链接(本为空)设为t.left。
这里写图片描述

代码如下:

//删除最小节点(热身)public void deleteMin() {    if (isEmpty()) throw new NoSuchElementException("Symbol table underflow");    root = deleteMin(root);}private Node deleteMin(Node x) {    if (x.left == null) return x.right;//不断检索左子树,直到遇到空的左链接,返回右链接    x.left = deleteMin(x.left);    return x;}//删除最大节点(热身)public void deleteMax() {    if (isEmpty()) throw new NoSuchElementException("Symbol table underflow");    root = deleteMax(root);}private Node deleteMax(Node x) {    if (x.right == null) return x.left;//不断检索右子树,直到遇到空的右链接,返回左链接    x.right = deleteMax(x.right);    return x;}//删除任意节点 public void delete(Key key) {        if (key == null) throw new IllegalArgumentException("called delete() with a null key");        root = delete(root, key); } private Node delete(Node x, Key key) {     if (x == null) return null;     int cmp = key.compareTo(x.key);     if      (cmp < 0) x.left  = delete(x.left,  key);     else if (cmp > 0) x.right = delete(x.right, key);     else {          if (x.right == null) return x.left;         if (x.left  == null) return x.right;         Node t = x;         x = min(t.right);//将x指向它的后继节点         x.right = deleteMin(t.right);//将x的右链接指向删除后所有节点都大于x.key的子二叉查找树         x.left = t.left;     }      return x; }   public Key min() {        if (isEmpty()) throw new NoSuchElementException("called min() with empty symbol table");        return min(root).key;    }     private Node min(Node x) {         if (x.left == null) return x;         else                return min(x.left);     } 
2 0
原创粉丝点击