二叉排序树
二叉排序树(BST)又称“二叉查找树”、“二叉搜索树”。
二叉排序树的性质
- 是一颗空树
- 具有下列性质的二叉树
- 若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值
- 若它的有字数不空,则右子树上所有节点的值均大于它的根节点的值
- 它的左、右子树也分别为二叉排序树
二叉排序树的实现
// 二叉排序树使用二叉链表作为存储结构
typedef struct BNode {
int value;
struct BNode *left;
struct BNode *right;
} BNode, *PBTree, *PBNode;
// 定义根二叉树节点指针
PBTree root = NULL;
// 创建指定value的二叉排序树的节点
PBNode _makeBNode(int value)
{
PBNode pBNode = (PBTree)malloc(sizeof(BNode));
pBNode->value = value;
pBNode->left = NULL;
pBNode->right = NULL;
return pBNode;
}
二叉排序树的删除
void _insertHelper(PBTree *root, int value)
{
PBTree pBTree = *root;
BNode *pBNode = _makeBNode(value);
if (pBTree == NULL) {
*root = pBNode;
} else {
if (pBTree->value < value) {
_insertHelper(&(pBTree->right), value);
} else if (pBTree->value > value) {
_insertHelper(&(pBTree->left), value);
} else {
puts("element is exist!!");
return;
}
}
}
// 使用insert方式创建二叉排序树
void InsertToBinarySearchTree(int value)
{
_insertHelper(&root, value);
}
二叉排序树的中序遍历
// 中序遍历二叉排序树
void Traversal(PBTree root)
{
if (root == NULL)
return;
if (root->left) {
Traversal(root->left);
}
printf(" %d", root->value);
if (root->right) {
Traversal(root->right);
}
}
二叉排序树节点的查找
PBNode _findHelper(PBTree root, int value)
{
if (root) {
if (root->value < value) {
return _findHelper(root->right, value);
} else if (root->value > value) {
return _findHelper(root->left, value);
} else {
return root;
}
}
return NULL;
}
// 二叉排序树中查找 value,成功返回其指针失败返回NULL
PBNode FindBNode(int value)
{
return _findHelper(root, value);
}
// 二叉排序树中序遍历时的某值的后继节点
PBNode TreeSuccessor(int value)
{
PBNode pBNode = NULL;
pBNode = FindBNode(value);
pBNode = TreeMinimum(pBNode->right);
return pBNode;
}
二叉排序树节点的删除
删除指定节点
删除节点时要注意三种情况:
- 叶节点
- 仅有左子树或右子树的节点
- 左右子树都有的节点
bool _delNodeHelper(PBNode* ppNode)
{
PBNode q = NULL, s = NULL;
// 1. 叶节点
if ((*ppNode)->left == NULL
&& (*ppNode)->right == NULL) {
free((*ppNode));
*ppNode = NULL;
// 2. 仅有左子树或右子树
// 2.1 仅有右子树
} else if ((*ppNode)->left == NULL) {
q = *ppNode;
*ppNode = (*ppNode)->right;
free((q);
// 2.2 仅有左子树
} else if ((*ppNode)->right == NULL) {
q = *ppNode;
*ppNode = (*ppNode)->left;
free(q);
// 3. 左右子树均不为空
} else {
q = (*ppNode);
s = (*ppNode)->left;
while (s->right) { // 左转,向右走到尽头
q = s;
s = s->right;
}
(*ppNode)->value = s->value;
if (q != *ppNode) // 是否执行while循环
q->right = s->left;// 执行,重接右子树
else
q->left = s->left;// 未执行,重接左子树
free(s);
}
return true;
}
bool DeleteBTreeNode(PBTree root, int value)
{
if (root == NULL)
return false;
if (root->value > value) {
return DeleteBTreeNode(root->left, value);
} else if (root->value < value) {
return DeleteBTreeNode(root->right, value);
}
return _delNodeHelper(&root);
}
删除所有节点
void _deleteHelper(PBTree *root)
{
PBNode pBNode = *root;
if (pBNode) {
if (pBNode->left) {
_deleteHelper(&(pBNode->left));
printf("%p\n", pBNode->left);
}
if (pBNode->right) {
_deleteHelper(&(pBNode->right));
printf("%p\n", pBNode->left);
}
if (pBNode->left == NULleft||
pBNode->right == NULL) {
free(pBNode);
*root = NULL;
}
}
}
// 删除二叉排序树
void DeleteBTree()
{
_deleteHelper(&root);
}
二叉排序树的最大值和最小值
// 二叉排序树的最小值
PBNode TreeMinimum(PBTree root)
{
PBNode pBNode= root;
if (!pBNode)
return NULL;
while (pBNode->left) {
pBNode = pBNode->left;
}
return pBNode;
}
// 二叉排序树的最大值
PBNode TreeMaximum(PBTree root)
{
PBNode pBNode = root;
if (!pBNode)
return NULL;
while (pBNode->right) {
pBNode = pBNode->right;
}
return pBNode;
}
二叉排序树的高度
// 二叉排序树的高度
int Height(PBTree root, int h)
{
if (!root) {
return h;
}
h++;
int h1 = Height(root->left, h);
int h2 = Height(root->right, h);
return h1 > h2 ? h1 : h2;
}
// 常用版本
int Height2(PBTree root)
{
if (!root)
return 0;
int hLeft = Height2(root->left);
int hRight = Height2(root->right);
return hLeft > hRight ? hLeft:hRight + 1;
}
二叉排序树的测试
// 测试二叉排序树
int main()
{
// 创建二叉排序树
int a[] = {8, 2, 10, 3, 7, 1, 6};
size_t count = sizeof(a)/sizeof(a[0]);
for (size_t i = 0; i < count; i++) {
InsertToBinarySearchTree(a[i]);
}
// 二叉排序树的高度
printf("The height of BTree is %d\n", Height(root, 0));
// 遍历二叉排序树
Traversal(root);
puts("");
// 二叉排序树的最小值
PBNode p = TreeMinimum(root);
printf("Min node is %p, value is %d\n", p, p->value);
// 二叉排序树的最大值
p = TreeMaximum(root);
printf("Max node is %p, value is %d\n", p, p->value);
// 二叉排序树中某值的后继节点(或值)
p = TreeSuccessor(3);
printf("3's successor is %d\n", p->value);
// 查找指定value
PBNode pBNode = FindBNode(7);
printf("Node %d's adress is %p\n", 7, pBNode);
// 删除二叉排序树
DeleteBTree();
Traversal(root);
}
二叉排序树性能
最好情况是二叉排序树的形态和这般查找的判定树相同,其平均查找长度和logN成正比(Olog2(N))。
最坏情况是插入的关键字有序,构成的二叉排序树为一颗斜树,树的深度为N,其平均查找长度为(N+1)/2;时间复杂度也为O(N),和顺序查找一样。