一. 定义, 性质
二叉查找树(Binary Search Tree),也称二叉搜索树、有序二叉树(ordered binary tree),排序二叉树(sorted binary tree),是指一棵空树或者具有下列性质的二叉树:
- 若任意节点的左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值;
- 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 任意节点的左、右子树也分别为二叉查找树;
- 没有键值相等的节点(no duplicate nodes)
- 中序遍历为递增序列
搜索、插入、删除的复杂度等于树高,期望O(logN),最坏O(N)(数列有序,树退化成线性表)。
二. 查询操作
Node* search(int key) {
Node* n = root;
while(n!=NULL && key!=n->data)
{
if (key<n->data) n = n->left;
else n = n->right;
}
return n;
}
// 找到以x为根的(子)树的最小结点
Node* minimum(Node* x)
{
if (x == 0) return 0;
while (x->left!=NULL)
x = x->left;
return x;
}
// find the minimum node in the whole tree
Node* minimum() {return minimum(root);}
// 找到以x为根的(子)树的最大结点
Node* maximum(Node* x)
{
if (x == 0) return 0;
while (x->right!=NULL)
x = x->right;
return x;
}
// find the maximum node in the whole tree
Node* maximum() {return maximum(root);}
三. 插入操作
插入的步骤如下:
1) 若树是空树, 则申请一个新节点, 赋给root
2) 若在树中找到key, 说明树中已经有该字段, 不能再插入, 否则
3) 若key小于当前结点的值, 则检查左孩子. 否则
4) 若key大于当前结点的值, 则检查右孩子.
递归算法:
Node* BinarySearchTree::insert(int key, Node*& n)
{
if (n == 0)
{
n = new Node(key);
return n;
}
else if (key < n->data)
return insert(key, n->left);
else if (key > n->data)
return insert(key, n->right);
else return n;
}
非递归算法:
Node* BinarySearchTree::insert_iterative(int key)
{
if (root == 0)
{
root = new Node(key);
return root;
}
Node* n = root;
// parent总是指向当前结点的父节点
Node* parent = 0;
while (n != 0)
{
parent = n;
if (key < n->data)
n = n->left;
else if (key > n->data)
n = n->right;
else;
}
if (key < parent->data)
{
parent->left = new Node(key);
return parent->left;
}
else
{
parent->right = new Node(key);
return parent->right;
}
}
四. 删除操作
由于删除操作要保证不破坏二叉搜索树树的性质, 因此要分两种情况考虑
1. 至多有一棵非空子树:
如果左子树非空, 那么用左子树替换当前结点. 否则用右子树替换当前结点.
2. 有两棵非空子树:
要转化为第一种情况------用该节点的直接后继来代替该节点, 并在该节点的右子树中删除其直接后继. 由于中序遍历的直接后继必然没有左子树, 因此能够转化为第一种情况
递归:
void BinarySearchTree::remove(int key, Node*& n)
{
if (n == 0)
return;
if (key < n->data)
remove(key, n->left);
else if (key > n->data)
remove(key, n->right);
else if (n->left != 0 && n->right != 0) //having two children
{
// 由于节点没有parent属性, 用重新安排指针的方法来移除结点很困难.
// 因此把直接后继结点的值赋给待删除结点
// 并且在右子树中删除该直接后继结点
n->data = minimum(n->right)->data;
remove(n->data, n->right);
}
else
{
Node* tmp = n;
n = (n->left != 0) ? n->left : n->right;
delete tmp;
}
}
非递归:
void BinarySearchTree::remove_iterative(int key)
{
// STEP 1 : 找到待删除结点和它的父节点
#pragma region STEP 1
Node *replacer, *successor, *successor_parent, *toRemove, *parent_toRemove;
toRemove = root; parent_toRemove = 0;
while (toRemove != NULL && key != toRemove->data)
{
parent_toRemove = toRemove;
if (key < toRemove->data)
toRemove = toRemove->left;
else
toRemove = toRemove->right;
}
if (toRemove == 0) return;
#pragma endregion STEP 1
#pragma region STEP 2 : 如果是第二种情况
if (toRemove->left && toRemove->right)
{
successor = toRemove->right;
successor_parent = toRemove;
while (successor->left)
{
successor_parent = successor;
successor = successor->left;
}
// 把直接后继的值赋给待删除结点
toRemove->data = successor->data;
// 待删除结点改为直接后继
toRemove = successor;
parent_toRemove = successor_parent;
}
#pragma endregion
if (toRemove->left)
replacer = toRemove->left;
else
replacer = toRemove->right;
if (toRemove == root)
root = replacer;
else if (toRemove == parent_toRemove->left)
parent_toRemove->left = replacer;
else
parent_toRemove->right = replacer;
delete toRemove;
}
来源:https://www.cnblogs.com/roy-mustango/p/4221256.html