0. 定義
又叫二叉排序樹(Binary Sort Tree)、二叉搜索樹(Binary Search Tree), 即BST
二叉排序樹或者是一棵空樹,或者是具有下列性質(zhì)的二叉樹:
- 若左子樹不空,則左子樹上所有結(jié)點(diǎn)的值均小于或等于它的根結(jié)點(diǎn)的值;
- 若右子樹不空,則右子樹上所有結(jié)點(diǎn)的值均大于或等于它的根結(jié)點(diǎn)的值;
- 左、右子樹也分別為二叉排序樹;
1. 插入節(jié)點(diǎn)
插入的節(jié)點(diǎn)一定是葉子節(jié)點(diǎn),可以直接和節(jié)點(diǎn)的key
對(duì)比,然后遞歸搜索左/右子樹即可
BiTree *insertBST(BiTree *t, int key) {
if (t == NULL) {
t = new BiTree();
t->lchild = t->rchild = NULL;
t->key = key;
return t;
}
if (key < t->key) {
t->lchild = insertBST(t->lchild, key);
} else {
t->rchild = insertBST(t->rchild, key);
}
return t;
}
2. 刪除節(jié)點(diǎn)
在二叉排序樹刪去一個(gè)結(jié)點(diǎn),分三種情況討論:
- 若
*p
結(jié)點(diǎn)為葉子結(jié)點(diǎn),即PL(左子樹)和PR(右子樹)均為空樹。由于刪去葉子結(jié)點(diǎn)不破壞整棵樹的結(jié)構(gòu),則可以直接刪除此子結(jié)點(diǎn)。 - 若
*p
結(jié)點(diǎn)只有左子樹PL或右子樹PR,此時(shí)只要令PL或PR直接成為其雙親結(jié)點(diǎn)*f
的左子樹(當(dāng)*p
是左子樹)或右子樹(當(dāng)*p
是右子樹)即可,作此修改也不破壞二叉排序樹的特性。 - 若
*p
結(jié)點(diǎn)的左子樹和右子樹均不空。在刪去*p
之后,為保持其它元素之間的相對(duì)位置不變,可按中序遍歷保持有序進(jìn)行調(diào)整,可以有兩種做法:- 3.1 其一是令
*p
的左子樹為*f
的左/右(依*p
是*f
的左子樹還是右子樹而定)子樹,*s
為*p
左子樹的最右下的結(jié)點(diǎn),而*p
的右子樹為*s
的右子樹; - 3.2 其二是令
*p
的直接前驅(qū)(或直接后繼)替代*p
,然后再從二叉排序樹中刪去它的直接前驅(qū)(或直接后繼)-即讓*f
的左子樹(如果有的話)成為*p
左子樹的最左下結(jié)點(diǎn)(如果有的話),再讓*f
成為*p
的左右結(jié)點(diǎn)的父結(jié)點(diǎn)。
- 3.1 其一是令
bool deleteBST(BiTree *t) {
BiTree *q, *s;
//如果只有右子樹
if (t->lchild == NULL) {
q = t;
t = t->rchild;
delete q;
//如果只有左子樹
} else if (t->rchild == NULL) {
q = t;
t = t->lchild;
delete q;
//左右子樹都不為空
} else {
q = t;
s = t->lchild;
//找到節(jié)點(diǎn)t的前驅(qū)
while (s->rchild) {
q = s;
s = s->rchild;
}
//保存s的值
t->key = s->key;
//此時(shí)s的右子樹為空,續(xù)接s的左子樹
if (q != t) {
q->rchild = s->lchild;
} else {
q->lchild = s->lchild;
}
delete s;
}
return true;
}
3. 優(yōu)化
- avl 樹
- 二叉樹 - 紅黑樹
3. 實(shí)現(xiàn)示例
完整代碼
#include <iostream>
using namespace std;
typedef struct BiTree {
int key;
BiTree *lchild;
BiTree *rchild;
};
//插入節(jié)點(diǎn)
BiTree *insertBST(BiTree *t, int key) {
if (t == NULL) {
t = new BiTree();
t->lchild = t->rchild = NULL;
t->key = key;
return t;
}
if (key < t->key) {
t->lchild = insertBST(t->lchild, key);
} else {
t->rchild = insertBST(t->rchild, key);
}
return t;
}
//刪除節(jié)點(diǎn)
bool deleteBST(BiTree *t) {
BiTree *q, *s;
if (t->lchild == NULL) {
q = t;
t = t->rchild;
delete q;
} else if (t->rchild == NULL) {
q = t;
t = t->lchild;
delete q;
} else {
q = t;
s = t->lchild;
while (s->rchild) {
q = s;
s = s->rchild;
}
t->key = s->key;
if (q != t) {
q->rchild = s->lchild;
} else {
q->lchild = s->lchild;
}
delete s;
}
return true;
}
//中序遍歷
void print(BiTree *t) {
if (t != NULL) {
if (t->lchild != NULL) {
print(t->lchild);
}
printf("%3d", t->key);
if (t->rchild != NULL) {
print(t->rchild);
}
}
}
int main(int argc, const char *argv[]) {
int n, m;
BiTree *t = NULL;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> m;
t = insertBST(t, m);
}
print(t);
return 0;
}