1.定义
二叉查找树或者是一棵空树,或者是具有下列性质的二叉树:
1)若左子树不空,则左子树上所有结点的值均小于或等于它的根节点的值;
2)若右子树不空,则右子树上所有结点的值均大于或等于它的根节点的值;
3)左、右子树也分别为二叉排序树;
2.操作
[1]查找,从根开始查找,小于根的查左子树,否则查由子树。
[2]插入,小于根的往左子树插入,否则往右子树插入。插入的节点必定是插到最下面那一层,不会插入到树的中间位置。
[3]删除,如果释放节点的右子树为空,则把左节点接到释放节点位置。
如果左子树为空,则把右节点接到释放节点位置。
如果左右都不为空,则把删除节点的左子树的最右节点(释放节点,注意这个节点的右子树是空的,因为这个节点已经是最右节点)替换到要删除的节点,然后把释放节点的左子树接到其父节点上面。
struct pnode{ int data; struct pnode *lchild; struct pnode *rchild; }; //查找 static struct pnode *search(struct pnode * p, int x) { int find = 0; while (p && !find) { if (x == p->data) find = 1 else if (x < p->data) p = p->lchild; else p = p->rchild; } if (p == NULL) printf("not found\n"); return p; } //插入 struct pnode *insert(struct pnode *root, int key) { if (root == NULL){ root = malloc(sizeof(struct pnode)); root->lchild = root->rchild = NULL; root->data = key; return root; } if (key < root->data) root->lchild = insert(root->lchild, key); else root->rchild = insert(root->rchild, key); return root; } //删除 int do_delete(struct pnode **p) { struct pnode *q, s; if ((*p)->rchild == NULL) { //右子树空,则只需要重接它的左子树 q = *p; *p = (*p)->lchild; free(q); }else if ((*p)->lchild == NULL){ //左子树空,则只需要重接它的右子树 q = *p; *p = (*p)->rchild; free(q); }else{ q = *p; s = (*p)->lchild; while (s->rchild) { q = s; s = s->rchild; } /* p是要删除的节点,此时用节点s覆盖此节点,然后删除s。 s是要覆盖到p的节点。递归查找p的左子树的最右结点就是s。 q是s的父节点。 */ (*p)->data = s->data; /* 此时释放节点是没有右节点的。释放节点是其父节点的右节点。 q != *p,表示要删除的节点和要释放的节点父节点不一样,此时要把释放节点的左子树接到释放节点的父节点的右节点。 q == *p,表示要删除的节点和要释放的节点父节点一样,此时要把释放节点的左子树接到释放节点的父节点的左节点。 */ if (q != *p) q->rchild = s->lchild; //因为此时s要释放掉,而s没有右节点,所以把s的左节点赋值给s父节点的右节点。 else q->lchild = s->lchild; //此时表示p的左侧 free(s); } return 0; } int delete(struct pnode **root, int key) { if (!*root) return -1; if (key == (*root)->data) return do_delete(root); else if (key < (*root)->data) return delete(&(*root)->lchild, key); else return delete(&(*root)->rchild, key); }
3.相关定义
[1]前驱和后继,就是按照某种顺序遍历二叉树后,这个排列中位于这个节点前面和后面的结点,就是这个节点的前驱和后继。因此,找一个节点的前驱和后继,对于不同的遍历方式,会得到不同的值。
另外,网上提到的下面的定义:
前驱结点:节点val值小于该节点val值并且值最大的节点。
后继节点:节点val值大于该节点val值并且值最小的节点。
这只是在中序遍历的条件下所满足的定义。
另外,对于各种遍历方式查找前驱和后继的方法不再描述。
查找前驱和后继的用途:例如在二叉查找树删除时,删除节点的左右子树都不为空,这时候就是找到删除节点的前驱或后继节点(注意这里是中序遍历方式下的前驱或后继)来替换到删除的位置。
4.总结