Binary Search Tree

Binary Seach Tree

@(Algorithms)[JAVA|Algorithm]


BST Node

A binary search tree(BST) node has 4 fields:
1. lChild: left child
2. rChild: right child
3. parent:parent node
4. key: the data stored in the node


Binary Search Tree property

         这里写图片描述
Quote from Algorithms 4th edition by Sedgewick.
Let x be be a node in the BST, if y is a node in the left subtree (assume left subtree is not empty) of node x ,then y.key < x.key; if y is a node in the right subtree (assume left subtree is not empty)of x, then y.key > x.key.


Maximum node

public BSTNode getMax(BSTNode x){
    while(x.right != null){
        x = x.right;
    }
    return x;
}

Minimum node

To find the minimum node in the tree rooted at node x, we simply iterates the left child of x.

//Recursive version
public BSTNode getMin(BSTNode root) {
    if (root == null)
        return null;
    if (root.lChild == null)
        return root;
    else
        return getMin(root.lChild);
}
//Iterative version

Successor

The successor of node x is the next node of x when performing in-order traverse. In other words, it is the node with the smallest key that is greater than x.key.
Threre are 2 case:
1. x has a right child, so the successor is the minimum node of x’s right subtree
2. x has noright child, so the smallest node greater than x must be a node in whose left subtree lies x. So we just iterates x’s parent to find the root of this left subtree.

private BSTNode getSuccessor(BSTNode x) {
    if (x.rChild != null)
        return getMin(x.rChild);// node x has a right child
    else {// back track the parent of x
        BSTNode y = x.parent;
        while (y != null && x == y.rChild) {//loop until y is the root or x is the left child of y, which means y is greater than x, but all nodes in the right subtree of y is greater than y
            x = y;
            y = y.parent;//iterates the parent
        }
        return y;
    }
}

Predecessor

private BSTNode getPredecessor(BSTNode x){
    if(x.l!=null)
        return getMax(x.l);
    else{
        BSTNode y = x.p;
        while(y != null && x == y.1){
            x = x.p;
            y = x.p;
        }
    }
}

Insertion

To insert a key in the BST, firts you have to find the proper node y which meets one of following :
1. if (y.key > key ), then y.rChild==null, append key on the right subtree of y
2. if (y.keykey ), then y.lChild==null, append key on the left subtree of y
3. if( y == null) , then the BST is empty, append the key on the root of the tree

    /**
     * @param key
     *            the key to insert
     */
    public void insert(int key) {
        BSTNode y = null;
        BSTNode x = this.root;
        BSTNode node = new BSTNode(key);//new a node to append
        // search from the root the x that all the nodes on its left subtree is smaller than key
        while (x != null) {//find the insert position by iteration
            y = x;
            if (key < x.key)
                x = x.lChild;
            else
                x = x.rChild;
        }
        node.parent = y;//link node to y
        if (y == null) // empty tree
            this.root = node;
        else if (key < y.key) // compare the key with the counterpart of y to determine on which branch to append
            y.lChild = node;
        else 
            y.rChild = node;//link y to node
    }

Recursive version of insert

public void insert(BSTNode n, BSTNode r) {
    if (r == null) {// check input
        this.root = n;
    }
    else {
        if (n.key <= r.key) {
            if (r.l != null) {
                insert(n, r.l);
            }
            else {// termination condition 1
                r.l = n;
                n.p = r;
            }
        }
        else {
            if (r.r != null) {
                insert(n, r.r);
            }
            else {// Termination condiftion 2
                r.r = n;
                n.p = r;
            }
        }
    }
}

Transplant

This serves for deletion operation.
transplant(u, v) replaces the subtree rooted at node u with the subtree rooted at node v, u’s parent becomes v ‘s parent ,and node v becomes the appropriate child of us’ parent.

//Note: this method does not attempt to update v.lChild and v.rChild.To do so or not is determined by its caller
public void transplant(BSTNode u, BSTNode v){
    if(u.parent == null)//u is the root of BST
        this.root = v;
    else if(u == u.p.lChild)//u is left child of its parent
            u.p.lChild = v;//make v the left child of u's parent
        else//u is the rChild of its parent
            u.p.rChild = v;//make v the rChild of u's parent
    if(v != null)
        v.p = u.p;//make u's parent become v's parent
}

Deletion

To delete a node z, which node is actually removed is depend on the number of childs that node z has, and there are 3 cases:
1. if z has no child, we just remove z
2. if z has 1 child, we remove z and make the only child of z to be the child of z.parent
3. if z has 2 children, then we find z’s successor y,which must be in z’s right subtree, and have y take the position of z.The rest of z’s original right subtree becomes y’s new right subtree, and z’s left subtree becomes y’s new left subtree.

When performing deletion, these 3 cases can be concluded into 4 cases:
1. If z has no left child, then replace z with its right child.(if z.rChild==null,then we deal with z has no child; if z.rChild != null, then we deal with z has only right child.)
2. if z has only a left child(z.rChild == null && z.lChild != null), we simply replace z with z.lChild.
3. Otherwise, z.lChild != null && z.rChild != null ,then we find z’s successor y, that lies in the right subtree of z, and y.lChild == null
3.1. if z.rChild == y, then replace z by y,and do not change y’s right child.
3.2. Otherwise, if y lies in the right subtree of z , but z.rChild != y, we first replace y by its own right child, then replace z by

The difference between z.rChild==y and z.rChild!=y is that :
1.*if z.rChild==y and y is the successor of z, then we do not have to deal with z’s right subtree(‘cause y is the right child of z). we can simply (1)replace z with y ,(2)*set y as the root of the left subtree of z. as following :
           delete
2.*ifz.rChild!=y and y is the successor of z, we should (1) replace y with r.rChild, (2)set y as the root of z’s right subtree, (3)replace z with y,(4)*set y as the root of z’s left
Alt text

public void delete(BSTNode n) {
        if (n.lChild == null) {
            transplant(n, n.rChild);
        }
        else if (n.rChild == null) {
            transplant(n, n.lChild);//n.lChild!=null && n.rChild==null
        }
        else {//n has 2 children
            BSTNode s = getMin(n.rChild);// find the successor of n
            if (s.parent != n) {//if s is not the direct right child of n
                transplant(s, s.rChild);//replace the successor with its right child
                s.rChild = n.rChild;
                n.rChild.parent = s;//set n's right child to s's right child
            }
            transplant(n, s);//if m is the direct right child of n, then s must have no 
            s.lChild = n.lChild;
            s.lChild.parent = s;//set n's left child to s's right child
        }
    }

Tree walk / Traverse

  Running time is O(N) , where N is the number of the nodes.

In-order tree walk

Pre-order tree walk

Post-order tree walk



Exercise

12.3.1

  Give a recursive version of BST insertprocedure.

Solution:

/**
 * Recursively insert node x from node r
*/
public void insert(BSTNode x, BSTNode r){
    if(x.key <= r.key){
        if(r.l != null){
            insert(x, r.l);
        }else{//r.l == null
            r.l = x;
            x.p = r;
        }
    }else{
        if(r.r != null){
            insert(x, r.r);
        }else{
            r.r = x;
            x.p=r;
        }
    }   
}

12.3.2

  Suppose that we construct a BST by repeatedly inserting distinct values to the tree. Argue that the number of the nodes examined in searching for a value in the tree (Ns) is 1 plus the number of nodes examined when the value was first inserted into the tree (Ni).

Ns=1+Ni

Pr:

  When insert a node x into the BST at the depth of h, we have to compare h nodes. So Ni = h;
  When we search for a node x in the BST, assuming that the target node is at the depth of h, we have to compare h times to find the right branch, and at last to compare the node at the branch with node x.The examined nodes Ns are totally h+1.

12.3.3

  We can sort a given set of n numbers by first building a binary search tree containing
these numbers (using TREE-INSERT repeatedly to insert the numbers one by one) and then printing the numbers by an inorder tree walk. What are the worstcase and best-case running times for this sorting algorithm?

Solution:

The algorithm:

TREESORT(A)fori=0ndoTREEINSERT(A[i])INORDERTRAVERSE()

The worst case: Θ(N2) : when the input set of data is already sorted, thus the insert operation results a linear linked chain.
The best case: Θ(NlogN) :when the BST is strictly balanced——for input set with n items, the height of the resulted BST is logN .

12.3.4

  Is the operation of deletion “commutative” in the sense that deleting x and then y
from a binary search tree leaves the same tree as deleting y and then x? Argue why
it is or give a counterexample.

Solution:

  No.
Example for the answer

12.3.5

  Suppose that instead of each node x keeping the attribute x.p, pointing to x’s parent, it keeps x.succ, pointing to x’s successor. Give pseudocode for SEARCH, INSERT, and DELETE on a binary search tree T using this representation. These procedures should operate in time O(h) , where h is the height of the tree T . (Hint: You may wish to implement a subroutine that returns the parent of a node.)

Solution:

O(h)O(NlogN) , where h is the height and N is the number of nodes.

Lemma: To find the parent of node x, we should find the maximum key M in the subtree rooted at x first. Then, we go downward to the right from M.succ.left. When we reach x, the node we encounter before x is x’s parent.
Alt textAlt text


If node m is the max of the subtree rooted at x, then m must have no right child, hence m.succ is the first ancestor of x whose left child is also the ancestor of x. If x has no right child, then x is the max node, and all the above still satisfies.

public BSTNode getParent(BSTNode x)
{
  if(x == root) 
      return NULL;
  BSTNode max = getMax(x);//get the max key in the subtree rooted at x
  BSTNode parent = max.succ;
  BSTNode t = null;

  if(parent != null) 
      t = parent.left;
  else 
      t = root;

  while(t != x){//for java, we may use t.equals() method instead 
      parent = t;
      t = t.right;
  }//after the iteration, parent points to the 
  return parent;
}

12.3-6

**W**hen node z in TREE-DELETE has two children, we could choose node y as its predecessor rather than its successor. What other changes to TREE-DELETE would be necessary if we did so? Some have argued that a fair strategy, giving equal priority to predecessor and successor, yields better empirical performance. How might TREE-DELETE be changed to implement such a fair strategy?

Solution:

**W**e find the successor when deleting node x in BST simply to replace the position of x.The successor can take position, so does the predecessor.
Here is the pseudocode of delete:

DELETE(x)if(x.lNIL)transplant(x,x.r)elseif(x.rNIL)transplant(x,x.l)elseyx.getSuccessor(x)if(yx.r)transplant(y,y.r)y.rx.rx.r.pytransplant(x,y)y.lx.lx.l.py

If we try to use predecessor to replace successor, then we have the change the algorithm as follow:

DELETE(x)if(x.lNIL)transplant(x,x.r)elseif(x.rNIL)transplant(x,x.l)elseyx.getPredecessor(x)if(yx.l)transplant(y,y.r)y.lx.lx.l.pytransplant(x,y)y.rx.rx.r.py


Extension Excercise

1. Get depth

Given a BST, try to find the depth of the tree using recursion

Solution:
public int getDepth(BSTNode r){
    if(r == null)
        return 0;
    else{
        int depthL = getDepth(r.l);
        int depthR = getDepth(r.r);
        return (depthL > depthR)?(depthL+1):(depthR+1);
    }
}

2.Non-recursive tree walk

Solution:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值