BST

996Worker
996Worker
发布于 2021-07-03 / 256 阅读
0
0

BST

Definition

In a Binary Search tree:

  • If the left subtree of any node is not empty, then the value of all the nodes in the left subtree is less than the value of its root node;
  • The right subtree of any node is not empty, then the value of all nodes in the right subtree is greater than the value of its root node;
  • The left and right subtrees of any node are binary search trees respectively.

Implementation with Java

Node


public class BSTree<T extends Comparable<T>> {
    private BSTNode<T> mRoot;

    public class BSTNode<T extends Comparable<T>> {
        T key;
        BSTNode<T> left;
        BSTNode<T> right;
        BSTNode<T> parent;
    }
    public BSTNode(T key, BSTNode<T> parent, BSTNode<T> left, BSTNode<T> right) {
                this.key = key;
                this.parent = parent;
                this.left = left;
                this.right = right;
            }
}

Traverse

In-Order

    private void inOrder(BSTNode<T> treeRoot) {
        if(treeRoot != null) {
            inOrder(treeRoot.left);
            print(treeRoot.key)
            inOrder(treeRoot.right);
        }
    }

Pre-Order

    private void preOrder(BSTNode<T> treeRoot) {
        if(treeRoot != null) {
            print(treeRoot.key)
            preOrder(treeRoot.left);
            preOrder(treeRoot.right);
        }
    }

post-Order

    private void postOrder(BSTNode<T> treeRoot) {
        if(treeRoot != null) {
            postOrder(treeRoot.left);
            postOrder(treeRoot.right);
            print(treeRoot.key)
        }
    }

example:


Result:

  • pre: 8 3 1 6 4 7 10 14 13
  • in: 1 3 4 6 7 8 10 13 14
  • post: 1 4 7 6 3 13 14 10 8

Search

recursive

private BSTNode<T> search(BSTNode<T> x, T key) {
    if (x == null) {
        return x
    }

    int cmp = key.compareTo(x.key);
    if (cmp < 0) {
        return search(x.left, key)
    }
    else if (cmp > 0) {
        return search(x.right, key)
    }
    else
        return x;
}

Non-recursive

private BSTNode<T> iterativeSearch(BSTNode<T> x, T key) {
    while (x != null) {
        int cmp = key.compareTo(x.key);
        if(cmp < 0) {
            x = x.left;
        }
        else if (cmp > 0) {
            x = x.right
        }
        else
            return x;
}

Find max-min

/* 
 * 查找最大结点: 返回tree为根结点的二叉树的最大结点。
 */
private BSTNode<T> maximum(BSTNode<T> tree) {
    if (tree == null)
        return null;

    while(tree.right != null)
        tree = tree.right;
    return tree;
}

/* 
 * 查找最小结点: 返回tree为根结点的二叉树的最小结点。
 */
private BSTNode<T> minimum(BSTNode<T> tree) {
    if (tree == null)
        return null;

    while(tree.left != null)
        tree = tree.left;
    return tree;
}

Predecessor & successor

* 
 * 找结点(x)的前驱结点。即,查找"二叉树中数据值小于该结点"的"最大结点"。
 */
public BSTNode<T> predecessor(BSTNode<T> x) {
    // 如果x存在左孩子,则"x的前驱结点"为 "以其左孩子为根的子树的最大结点"。
    if (x.left != null)
        return maximum(x.left);
    // 如果x没有左孩子。则x有以下两种可能: 
    // (01) x是"一个右孩子",则"x的前驱结点"为 "它的父结点"。
    // (01) x是"一个左孩子",则查找"x的最低的父结点,并且该父结点要具有右孩子",找到的这个"最低的父结点"就是"x的前驱结点"。
        BSTNode<T> y = x.parent;
        while ((y!=null) && (x==y.left)) {
            x = y;
            y = y.parent;
        }

        return y;
}

/* 
 * 找结点(x)的后继结点。即,查找"二叉树中数据值大于该结点"的"最小结点"。
 */
public BSTNode<T> successor(BSTNode<T> x) {
    // 如果x存在右孩子,则"x的后继结点"为 "以其右孩子为根的子树的最小结点"。
    if (x.right != null)
        return minimum(x.right);

    // 如果x没有右孩子。则x有以下两种可能: 
    // (01) x是"一个左孩子",则"x的后继结点"为 "它的父结点"。
    // (02) x是"一个右孩子",则查找"x的最低的父结点,并且该父结点要具有左孩子",找到的这个"最低的父结点"就是"x的后继结点"。
    BSTNode<T> y = x.parent;
    while ((y!=null) && (x==y.right)) {
        x = y;
        y = y.parent;
    }

    return y;
}

Insert & remove

Insert

/* 
 * 将结点插入到二叉树中
 *
 * 参数说明: 
 *     tree 二叉树的
 *     z 插入的结点
 */
private void insert(BSTree<T> bst, BSTNode<T> z) {
    int cmp;
    BSTNode<T> y = null;
    BSTNode<T> x = bst.mRoot;

    // 查找z的插入位置
    while (x != null) {
        y = x;
        cmp = z.key.compareTo(x.key);
        if (cmp < 0)
            x = x.left;
        else
            x = x.right;
    }

    z.parent = y;
    if (y==null)
        bst.mRoot = z;
    else {
        cmp = z.key.compareTo(y.key);
        if (cmp < 0)
            y.left = z;
        else
            y.right = z;
    }
}

/* 
 * 新建结点(key),并将其插入到二叉树中
 *
 * 参数说明: 
 *     tree 二叉树的根结点
 *     key 插入结点的键值
 */
public void insert(T key) {
    BSTNode<T> z=new BSTNode<T>(key,null,null,null);

    // 如果新建结点失败,则返回。
    if (z != null)
        insert(this, z);
}

remove



/*
 * 删除结点(z),并返回被删除的结点
 *
 * 参数说明:
 *     bst 二叉树
 *     z 删除的结点
 */
private BSTNode<T> remove(BSTree<T> bst, BSTNode<T> z) {
    //这里没起个好名字,让人看着默默奇妙,实际上 x 就是子节点 child
    BSTNode<T> x=null;
    //这里的 y 节点就是要删除的节点 delete
    BSTNode<T> y=null;
    //这个写法理解比较绕,不如反转后容易理解
    //只有一个节点或者没有节点时
    if ((z.left == null) || (z.right == null) )
        //z 就是要删除的节点
        y = z;
    else
        //当有两个子节点时,删除后继结点
        // 上述图例是删除前驱节点
        y = successor(z);
    //获取需要删除的节点的子节点,不管是左是右
    if (y.left != null)
        x = y.left;
    else
        x = y.right;
    //如果存在子节点,就关联被删节点的父节点
    if (x != null)
        x.parent = y.parent;
    //如果父节点是空,说明要删的是根节点
    if (y.parent == null)
        //设置根为 child(此时根只有一个或没有节点)
        bst.mRoot = x;
    else if (y == y.parent.left)//要删的是左节点
        y.parent.left = x;//左节点关联子节点
    else//要删的是右节点
        y.parent.right = x;//右节点关联子节点
    //如果要删的节点和一开始传入的不一样,就是后继的情况
    if (y != z)
        z.key = y.key;//后继的值传给本来要删除的节点
    //返回被删除的节点
    return y;
}

评论