二叉搜索树
二叉搜索树
二叉搜索树是一个高效的数据结构,查找、插入、删除的平均时间复杂度都是
对应树中的一个节点
u
满足:
- 如果
u
存在左子树,那么左子树中所有点的 key 都小于(大于)u
的 key- 如果
u
存在右子树,那么右子树中所有点的 key 都大于(小于)u
的 key二叉搜索树的缺点:
如果按照优先级(从大到小、从小到大)的顺序插入元素,那么二叉搜索树退化为一个链表。查找、插入、删除的时间复杂度退化为 。后面的平衡树、红黑树等都是为了解决二叉搜索树的这个缺点。
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
的实现 (偷懒了) :时间复杂度 ,空间复杂度
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
的实现:平均时间复杂度 ,最坏时间复杂度
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
的实现:平均时间复杂度 ,最坏时间复杂度- 如果存在 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
的实现:平均时间复杂度 ,最坏时间复杂度- 如果节点
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;
}
分类:
数据结构
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)