1. 概念:node
Binary-search tree(BST)是一颗二叉树,每一个树上的节点都有<=1个父亲节点,ROOT节点没有父亲节点。同时每一个树上的节点都有[0,2]个孩子节点(left child AND right child)。每一个节点都包含有各自的KEY值以及相应的satellite data。其中KEY是几种BST基本操做的主要操做对象。算法
2. BST的特别性质:函数
BST任何一颗子树上的三个节点left, parent, right. 知足条件left.key<parent.key<=right.key,一颗典型的BST以下图所示:spa
观察以后不难发现若是对BST进行PREORDER walk(先序遍历),获得:2, 5, 5, 6, 7, 8 恰好是升序排列。code
P.S 所谓PREORDER walk,就是要访问以ROOT为根的树,先要访问ROOT.left, 而后访问ROOT, 最后访问ROOT.right。对象
用pseudocode的形式的话,就是这样: blog
PREORDER-WALK(x) 1 if(x!=NIL) 2 PREORDER-WALK(x.left) 3 print x.key 4 PREORDER-WALK(x.right)
3. BST的几种基本操做:递归
SEARCH, MINIMUM, MAXIMUM, PREDECESSOR, SUCCESSOR, INSERT, and DELETE.it
2.1 SEARCH:io
TREE-SEARCH(x, k) INPUT: BST ROOT node, value k. OUPUT: node in BST whose key equals to k 1 if(x==NIL) OR (k==x.key) 2 return x 3 if(k<x.key) 4 return TREE-SEARCH(x.left, k) 5 else return TREE-SEARCH(x.right, k)
算法解释:当咱们要找到key值为k的节点在BST中的位置,咱们通常调用上述函数TREE-SEARCH(ROOT, k)(ROOT为BST的根节点)。若是ROOT节点的key值等于k,则咱们要找的节点就是根节点ROOT。若是不是,根据BST的特殊性质:
left.key<parent.key<=right.key
咱们比较当前节点的key值,若是current.key<k,则要在当前节点的左子树中查找,反之,则在右子树中查找。[line3-line5]
2.2 MINIMUM:
TREE-MINIMUM(x) INPUT: BST ROOT node OUTPUT: the smallest key in BST 1 if(x==NIL) return; 2 while(x.left!=NIL) 3 x=x.left 4 return x.key
算法解释:一个BST的最左叶子节点的key值就是BST全部key值中最小的。这个根据BST的特殊性质很容易推导出来:
由于 left.key < parent.key < parent.key < .... < root.key
有了MINIMUM算法,MAXIMUM算法也就有了:
2.3 MAXIMUM:
TREE-MAXIMUM(x) INPUT: BST ROOT node OUTPUT: the smallest key in BST 1 if(x==NIL) return; 2 while(x.right!=NIL) 3 x=x.right 4 return x.key
2.4 SUCCESSOR:
TREE-SUCCESSOR(x) INPUT: arbitray node x in BST OUTPUT: x's successor node 1 if(x.right!=NIL) 2 TREE-MINIMUM(x.right) 3 y=x.parent 4 while(y!=NIL AND y.left==x) 5 x=y 6 y=y.parent 7 return y
这里说明一下SUCCESSOR的含义,x的SUCCESSOR知足x.key<=x.SUCCESSOR.key,而且x.SUCCESSOR.key是距离x.key最近的值,即x.SUCCESSOR.key是x.key的最小上限(minimum ceiling)
算法思想:由于在BST中,有x.key<=x.right.key。因此若是某BST的节点x有右孩子节点(x.right!=NIL),则利用TREE-MINIMUM在x的右子树中查找便可。若是x不存在右孩子,则检查x是否有父亲节点而且x必须是父亲节点的左孩子,只有这样才有parent.key>parent.left.key。但找到x的parent就结束了吗,尚未,就像TREE-MINIMUM函数同样,咱们须要逐层查找,当找到符合条件的parent后,咱们递归的继续检查parent节点有没有parent.parent节点符不符合上述条件。知道访问到的parent节点不符合该条件为止。
2.5 INSERT:
TREE-INSERT(T, z) 1 y=NIL 2 x=T.ROOT 3 while(x!=NIL) 4 y=x 5 if(z.key<x.key) 6 x=x.left 7 else x=x.right 8 z.p=y 9 if(y==NIL) T.ROOT=z 10 if(z.key<y.key) y.left=z 11 else y.right=z
用一张图来解释该算法:
虚线指向的key值为13的节点是即将要插入BST的点,其余的点已经在BST上。能够看到从ROOT节点出发,根据“左小右大”规则,咱们很快找到了key值为15的节点,由于13<15,因此检查‘15’节点是否有左孩子,结果是没有,因此把13放到15的左孩子节点处。咱们能够想象若是要插入的节点key是16会怎么样?一样的,咱们仍是找到‘15’节点,可是16>15,因此继续往‘右’查找,找到‘17’,由于16<17,看17有没有左孩子节点,没有,因此会把‘16’放到‘17’的左孩子节点处。
2.6 TRANSPLANT:
TRANPLANT(T, u, v) 1 if (u.parent==NIL) T.ROOT=v 2 else if(u==u.parent;.left) u.parent.left=v 3 else u.parent.right=v 4 if(v!=NIL) v.parent=u.parent
仍是用一张图来展现比较清晰:
2.7 DELETE:
TREE-DELETE(T, z) 1 if z.left==NIL 2 TRANSPLANT(T, z, z.right) 3 else if z.right == NIL 4 TRANSPLANT(T, z, z.left) 5 else y=TREE-MINIMUM(z.right) 6 if y.parent!=z 7 TRANSPLANT(T, y, y.right) 8 y.right=z.right 9 y.right.parent=y 10 TRANSPLANT(T, z, y) 11 y.left=z.left 12 y.left.parent=y
DELETE算法相对来讲比较麻烦一些,须要考虑的状况要多一些。由于要在删除BST的某一节点后仍能维持BST的基本性质。假设要删除的节点是z,z的key值为k。根据“左小右大”原则,z.left.key<k<=z.right.key.若是这时候吧z删了,谁来接替z的位置呢而且保证解体以后的新BST知足性质呢?方法咱们能够根据性质来推导:咱们要找到一个除了z之外的节点在BST中,该节点假设为P,那么P.key要大于z.left.key而且P.key>=z.right.key,实际上很明显的,惟一符合要求的就是z的SUCCESSOR。
若是z只有左子树或者只有右子树,那么问题就很简单,使z的左孩子或者右孩子来顶替z的位置便可。若是z的左子树和右子树都存在,那么问题稍微复杂一点,咱们要在BST上找到z的SUCCESSOR。如此一来,这个问题又变成咱们以前讨论的SUCCESSOR问题了,总共有两种情形:
第一种情形:z的右孩子就是咱们要找的z的SUCCESSOR,那咱们就直接TRANSPLANT移植以z.right为根的子树到z的位置中去。
第二种情形:z的右孩子不是咱们要找的z的SUCCESSOR,那咱们就从z.right出发,‘深刻’寻找知道找到z的SUCCESSOR,假设为Q。
那么咱们让Q成为z.right的父亲节点,而且让以Q为根的右子树(由于是根据“最左原则”找到的Q,Q要么是以z.right为根的left-most叶子节点,要么Q只有右子树。)取代Q的位置。最后让Q取代z的位置。。。很绕。。。仍是见图吧。