二叉搜索树的特点是, A.left<=A<=A.right A . l e f t <= A <= A . r i g h t 。对于一个节点来说,左子树是比该节点小的,右子树是比该节点大的。
由四个部分组成,节点值,左子树,右子树,父节点。
struct node{
int val;
node* left;
node* right;
node* p;
node(int x) : val(x), left(NULL), right(NULL) ,p(NULL){}
};
在一个树中查询操作的时间是O(h),h 为树的高度。如果待查询的值在比当前节点的值小,则该值在节点的左子树,反之右子树。
node* Tree_search(node* x, int k){
if (x == NULL || x->val == k){
return x;
}
if (k < x->val){
x = x->left;
return Tree_search(x, k);
}
else
return Tree_search(x->right, k);
}
node* It_tree_search(node* x,int k){
while (x != NULL&&k != x->val){
if (k < x->val) x = x->left;
else x = x->right;
}
return x;
}
递归方法和迭代方法查询。
子树的最大值一定在子树的右子树上,反之左子树。
node* Tree_minmum(node* x){
while (x->left != NULL){
x = x->left;
}
return x;
}
node* Tree_maxmum(node*x){
while (x->right != NULL){
x = x->right;
}
return x;
}
前驱就是小于该节点值的最大值。后继就是大于该节点值的最小值。以后继为例,如果节点的右子树不为空,那么后继节点是右子树上的最小值。因为右子树上都是大于该节点的值,要找后继,就是找右子树上的最小值。如果右子树为空,就是向上找,找到一个节点,这个节点满足,要查询的节点在这个节点的左子树上。那么该节点就是后继节点。解释:由于右子树为空,说明节点的子树中没有比节点x大的值,因此需要向父节点上找,如果节点x是在父节点的右子树上的,那么父节点y的子树中也没有比x大的,需要继续找父节点的父节点,直到节点在父节点的左子树上时,那么父节点就是后继节点,因为父节点的右子树和父节点都比该节点大,因此该节点就是大于x的最小值。
node* Tree_successor(node* x){
if (x->right != NULL){
return Tree_minmum(x->right);
}
node* y = x->p;
while (y != NULL&&x == y->right){
x = y;
y = y->p;
}
return y;
}
node* Tree_predecessor(node*x){
if (x->left != NULL){
return Tree_maxmum(x->left);
}
node* y = x->p;
while (y != NULL&&x == y->left){
x = y;
y = y->p;
}
return y;
}
插入操作比较简单,就是先找到插入值应该在的位置,把该值作为叶子节点插入就可以了。
void Tree_insert(node* &T,node* z){
node* y = NULL;
node* x = T;
while (x != NULL){
y =x;
if (z->val > x->val){
x = x->right;
}
else{
x = x->left;
}
}
z->p = y;
if (y == NULL) T = z;
else if (y->val < z->val){
y->right = z;
}
else{
y->left = z;
}
}
删除一个节点可能会带来二叉搜索树的性质不满足。这里为了方便进行树的移动和交换定义了一个子过程。
void Transplant(node* &T, node*u, node* v){
if (u->p == NULL){
T = v;
}
else if (u = u->p->left){
u->p->left = v;
}
else{
u->p->right = v;
}
if (v != NULL){
v->p = u->p;
}
}
删除可以分为三种情况,1.要删除的z只有一个子树,那么可以直接将z删掉,然后将子树变为z的父节点的子树。2.z有两个子树,那么需要先找到z的后继y(为什么要找后继呢?把后继的值y放在z的位置,因为z的左子树本来就比z小,后继比z大,且左子树内没有发生变化。所以对于左子树满足性质。对于右子树,y是右子树中最小的值,所以也满足性质。)后继y是没有左子树的。如果y的父节点不是z,那么将y的右子树变为y的父节点的左子树,然后用y来替换z。如果z是y的父节点,那么简单的将y把z替换就可以。
void Tree_delete(node* &T, node *z){
if (z == NULL){
return;
}
if (z->left == NULL){
Transplant(T, z, z->right);
}
else if (z->right == NULL){
Transplant(T, z, z->right);
}
else{
node* y = Tree_minmum(z->right);
if (y->p != z){
Transplant(T, y, y->right);
y->right = z->right;
y->right->p = y;
}
Transplant(T, z, y);
y->left = z->left;
y->left->p = y;
}
return;
}
就是简单的将值插入到一个空树里面。
node* build_tree(int*a,int len){
node* root =NULL;
for (int i = 0; i < len; ++i){
node* z= new node(0);
z->val = a[i];
Tree_insert(root, z);
}
return root;
}
int main(){
int r4[10] = { 12, 16, 3, 2,9,10,5,7,14,18};
node* root = build_tree(r4, 10);
node* c = It_tree_search(root, 12);
node* x = Tree_maxmum(c);
node* v = Tree_predecessor(c);
node* u = Tree_successor(v);
Tree_delete(root,u);
node* w1= Tree_successor(v);
}
暂时没有发现什么问题,有问题请批评指正,不胜感激!