二叉搜索树
二叉搜索树
二叉搜索树是一个高效的数据结构,查找、插入、删除的平均时间复杂度都是 \(O(log_2n)\)
对应树中的一个节点
u满足:
- 如果
u存在左子树,那么左子树中所有点的 key 都小于(大于)u的 key- 如果
u存在右子树,那么右子树中所有点的 key 都大于(小于)u的 key二叉搜索树的缺点:
如果按照优先级(从大到小、从小到大)的顺序插入元素,那么二叉搜索树退化为一个链表。查找、插入、删除的时间复杂度退化为 \(O(n)\)。后面的平衡树、红黑树等都是为了解决二叉搜索树的这个缺点。

treeNode的实现:
template <class T>
struct treeNode
{
T value;
treeNode* left, * right; // 标准的二叉树
treeNode() { left = right = nullptr; }
treeNode(const T& theValue) : value(theValue) { left = right = nullptr; }
treeNode(const T& theValue, treeNode* theLeft, treeNode* theRight) : value(theValue)
{
left = theLeft;
right = theRight;
}
};
binarySearchTree的实现:
// less 满足节点的左子树中所有的点都小于根,右子树都大于根,greater 相反
template <class K, class E, class Compare=less<K>>
class binarySearchTree
{
public:
binarySearchTree()
{
root = nullptr;
_size = 0;
}
explicit binarySearchTree(const Compare& x) : cmp(x) { binarySearchTree(); }
~binarySearchTree(); // 内存释放
int size() const { return _size; }
pair<const K, E>* find(const K& theKey);
treeNode<pair<const K, E>>* insert(const pair<const K, E>& thePair);
bool erase(const K& theKey);
// 按照优先级打印全部元素
void display() const { display(root); }
void display(const treeNode<pair<const K, E>>* node)
{
if (node == nullptr) return;
display(node->left);
cout << "{" << node->value.fist << ":" << node->value.second << "}" << endl;
display(node->right);
}
private:
treeNode<pair<const K, E>>* root;
int _size;
Compare cmp;
};
~binaryTreeNode的实现 (偷懒了) :时间复杂度 \(O(n)\),空间复杂度 \(O(n)\)
template<class K, class E, class Compare>
binarySearchTree<K, E, Compare>::~binarySearchTree()
{
// 懒得写 dfs
stack<treeNode<pair<const K, E>>*> stk;
if (root) stk.push(root);
while (!stk.empty())
{
auto t = stk.top();
stk.pop();
if (t->left) stk.push(t->left);
if (t->right) stk.push(t->right);
delete t;
}
}
find的实现:平均时间复杂度 \(O(log_2n)\),最坏时间复杂度 \(O(n)\)
template<class K, class E, class Compare>
pair<const K, E>* binarySearchTree<K, E, Compare>::find(const K& theKey)
{
auto cur = root;
while (cur != nullptr)
{
if (cur->value.first == theKey) return &(cur->value);
else if (cmp(cur->value.first, theKey)) cur = cur->right;
else cur = cur->left;
}
return nullptr;
}
insert的实现:平均时间复杂度 \(O(log_2n)\),最坏时间复杂度 \(O(n)\)- 如果存在 key,则修改其元素的值
- 否则,在空节点处插入新节点
template<class K, class E, class Compare>
treeNode<pair<const K, E>>* binarySearchTree<K, E, Compare>::insert(const pair<const K, E>& thePair)
{
// pre 记录 cur 的父节点
treeNode<pair<const K, E>>* cur = root, *pre = nullptr;
while (cur)
{
pre = cur;
if (cur->value.first == thePair.first) // 如果 key 存在,则修改其 value
{
cur->value.second = thePair.second;
return cur;
}
else if (cmp(cur->value.first, thePair.first)) cur = cur->right;
else cur = cur->left;
}
// key 不存在时,pre 是最后一个节点,在 pre 后插入
auto newNode = new treeNode<pair<const K, E>>(thePair);
if (root != nullptr)
{
if (cmp(pre->value.first, thePair.first)) pre->right = newNode;
else pre->left = newNode;
}
else root = newNode;
_size++;
return newNode;
}
-
erase的实现:平均时间复杂度 \(O(log_2n)\),最坏时间复杂度 \(O(n)\)- 如果节点
u不存在,插入失败 - 删除根节点的情况需要特殊处理
- 节点
u存在:u的两个子树都存在:在左子树中寻找最大点son,将son放置到u处,然后按照只存在一颗或者不存在子树的情况删除son为根的子树。u只有一个或者没有子树:类似于链表删除元素即可

- 如果节点
template<class K, class E, class Compare>
bool binarySearchTree<K, E, Compare>::erase(const K& theKey)
{
treeNode<pair<const K, E>>* cur = root, *pre = nullptr;
while (cur)
{
if (cur->value.first == theKey) break;
else
{
pre = cur;
if (cmp(cur->value.first, theKey)) cur = cur->right;
else cur = cur->left;
}
}
// 不存在该 key 则删除失败
if (cur == nullptr) return false;
// 讨论删除点的两个子树都存在的情况
if (cur->left && cur->right)
{
treeNode<pair<const K, E>>* son = cur->left, *parent = cur;
// 寻找左子树中最大的值,也就是沿着最右路径寻找
// 也可以寻找右子树中最小的值,沿着右子树的最左路径即可
while (son->right != nullptr)
{
parent = son;
son = son->right;
}
auto newNode = new treeNode<pair<const K, E>>(son->value, cur->left, cur->right);
// 删除的是根节点直接替换根节点即可
if (pre == nullptr) root = newNode;
else if (cur == pre->left) pre->left = newNode;
else pre->right = newNode;
// 如果左子树不含右子树,那么左子树的最大值为其根节点
if (parent == cur)
pre = newNode;
else pre = parent;
delete cur;
// 下面删除左子树中的最大节点
cur = son;
}
// 只有一个子树或者没有子树的情况
treeNode<pair<const K, E>>* node = nullptr;
if (cur->left)
node = cur->left;
else
node = cur->right;
if (cur == root)
root = node;
else
{
if (cur == pre->left)
pre->left = node;
else
pre->right = node;
}
_size--;
delete cur;
return true;
}

浙公网安备 33010602011771号