扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
二叉搜索树是一颗排序树,或者是一颗空树如图:
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
它的左右子树也分别为二叉搜索树,并且它可以去重
templatestruct BSTreeNode
{BSTreeNode* _left;
BSTreeNode* _right;
T _key;
BSTreeNode(const T& key)
:_left(nullptr)
,_right(nullptr)
,_key(key)
{}
};
templateclass BSTree
{typedef BSTreeNodeNode;
public:
BSTree()
:_root(nullptr)
{}
private:
Node* _root;
};
二叉搜索树的插入例如插入6和10
bool insert(const T& key)
{if (_root == nullptr)
{_root = new Node(key);
return true;
}
Node* cur = _root;
Node* parent = cur;
while (cur)
{if (cur->_key >key)
{ parent = cur;
cur = cur->_left;
}
else if (cur->_key< key)
{ parent = cur;
cur = cur->_right;
}
else
return false;
}
cur = new Node(key);
if (parent->_key >key)
parent->_left = cur;
else
parent->_right = cur;
return true;
}
注意:会有树为空的情况需要判断
二叉搜索树的查找查找的代码和插入非常类似,大于根去右边,小于根去左边,最多查找高度次
代码如下:
//Node* find(const T& key)
bool find(const T& key)
{if (_root == nullptr)
return false;
//return nullptr;
Node* cur = _root;
while (cur)
{if (cur->_key >key)
cur = cur->_left;
else if (cur->_key< key)
cur = cur->_right;
else
return true;
//return cur;
}
return false;
//return nullptr;
}
二叉搜索树的删除这里的删除相对于插入和查找来说是比较难的,最重要的是不能改变二叉搜索树的结构,所以这里主要分为两种情况考虑
先找到要删除的节点,代码如下:
bool erase(const T& key)
{if (_root == nullptr)
return false;
Node* cur = _root;
Node* parent = cur;
while (cur)
{if (cur->_key >key)
{ parent = cur;
cur = cur->_left;
}
else if (cur->_key< key)
{ parent = cur;
cur = cur->_right;
}
else
{ 删除部分的代码........
}
}
return false;
}
1. 删除只有一个子节点或没有子节点
(1)删除叶子节点(删除9举例)
(2)删除只存在一个子节点的节点(删除8举例)
情况1的删除代码:
else
{if (cur->_left == nullptr)
{if (cur == parent->_left)
parent->_left = cur->_right;
else
parent->_right = cur->_right;
}
else if (cur->_right == nullptr)
{if (cur == parent->_left)
parent->_left = cur->_left;
else
parent->_right = cur->_left;
}
else
{情况2部分的代码.......}
delete cur;
}
除上述代码删除的示例外,另外三种情况
所以这里需要仔细处理链接,否则会破坏搜索树的结构
2.删除左右节点都存在的节点
(1)删除根节点
(2)删除其他存在左右子节点的节点
找到的右子树最小节点一定没有左节点,且它的父节点一定不为空;所以在交换或覆盖完数值后,剩下的步骤和情况一一样,并且这里不用单独判断删除的节点存在哪边的子节点(右子树的最小节点一定没有左节点,所以只可能存在右节点)
情况2的删除代码:
else
{Node* min_parent = cur;
Node* min = cur->_right;
while (min->_left)
{min_parent = min;
min = min->_left;
}
cur->_key = min->_key;
if (min == min_parent->_left)
min_parent->_left = min->_right;
else
min_parent->_right = min->_right;
swap(min,cur);
}
以上就是删除主要步骤,但还有个问题就是要考虑只有一个节点,需要操作根节点。
if (_root->_key == key )
{if (_root->_left == nullptr)
_root = _root->_right;
else
_root = _root->_left;
}
总体代码
bool erase(const T& key)
{if (_root == nullptr)
return false;
Node* cur = _root;
Node* parent = cur;
while (cur)
{if (cur->_key >key)
{ parent = cur;
cur = cur->_left;
}
else if (cur->_key< key)
{ parent = cur;
cur = cur->_right;
}
else
{ if (_root->_key == key )
{ if (_root->_left == nullptr)
_root = _root->_right;
else
_root = _root->_left;
}
else if (cur->_left == nullptr)
{ if (cur == parent->_left)
parent->_left = cur->_right;
else
parent->_right = cur->_right;
}
else if (cur->_right == nullptr)
{ if (cur == parent->_left)
parent->_left = cur->_left;
else
parent->_right = cur->_left;
}
else
{ Node* min_parent = cur;
Node* min = cur->_right;
while (min->_left)
{min_parent = min;
min = min->_left;
}
cur->_key = min->_key;
if (min == min_parent->_left)
min_parent->_left = min->_right;
else
min_parent->_right = min->_right;
swap(min,cur);
}
delete cur;
return true;
}
}
return false;
}
整体代码
循环写法bool insert(const T& key)
{if (_root == nullptr)
{ _root = new Node(key);
return true;
}
Node* cur = _root;
Node* parent = cur;
while (cur)
{ if (cur->_key >key)
{ parent = cur;
cur = cur->_left;
}
else if (cur->_key< key)
{ parent = cur;
cur = cur->_right;
}
else
return false;
}
cur = new Node(key);
if (parent->_key >key)
parent->_left = cur;
else
parent->_right = cur;
return true;
}
bool find(const T& key)
{if (_root == nullptr)
return false;
//return nullptr;
Node* cur = _root;
while (cur)
{ if (cur->_key >key)
cur = cur->_left;
else if (cur->_key< key)
cur = cur->_right;
else
return true;
//return cur;
}
return false;
//return nullptr;
}
bool erase(const T& key)
{if (_root == nullptr)
return false;
Node* cur = _root;
Node* parent = cur;
while (cur)
{ if (cur->_key >key)
{ parent = cur;
cur = cur->_left;
}
else if (cur->_key< key)
{ parent = cur;
cur = cur->_right;
}
else
{ if (_root->_key == key )
{if (_root->_left == nullptr)
_root = _root->_right;
else
_root = _root->_left;
}
else if (cur->_left == nullptr)
{if (cur == parent->_left)
parent->_left = cur->_right;
else
parent->_right = cur->_right;
}
else if (cur->_right == nullptr)
{if (cur == parent->_left)
parent->_left = cur->_left;
else
parent->_right = cur->_left;
}
else
{Node* min_parent = cur;
Node* min = cur->_right;
while (min->_left)
{min_parent = min;
min = min->_left;
}
cur->_key = min->_key;
if (min == min_parent->_left)
min_parent->_left = min->_right;
else
min_parent->_right = min->_right;
swap(min,cur);
}
delete cur;
return true;
}
}
return false;
}
//打印搜索树
void print_BSTree()
{_print_BSTree(_root);
cout<< endl;
}
void _print_BSTree(Node* root)
{if (root == nullptr)
return;
_print_BSTree(root->_left);
cout<< root->_key<< " ";
_print_BSTree(root->_right);
}
递归写法1.插入
bool insertR(const T& key)
{return insertR(_root,key)
}
bool _insertR(Node*& root,const T& key)
{if(root == nullptrd)
{root = new Node(key);
return true;
}
if(root->_key >key)
return insertR(root->_left,key);
else if(root->_key< key)
return insertR(root->_right,key);
else
return false;
}
注意,这里可以成功链接上,主要是运用了引用,递的是左右指针的引用
2.查找
Node* findR(const T& key)
{if()
}
bool _insertR(Node*& root, const T& key)
{if (root == nullptr)
{root = new Node(key);
return true;
}
if (root->_key >key)
return _insertR(root->_left, key);
else if (root->_key< key)
return _insertR(root->_right, key);
else
return false;
}
3.删除
bool EarseR(const K& key)
{return EarseR(_root,key);
}
bool _EraseR(Node*& root, const T& key)
{if (root == nullptr)
return false;
if (root->_key >key)
_EraseR(root->_left, key);
else if (root->_key< key)
_EraseR(root->_right, key);
else
{Node* era = root;
if (root->_left == nullptr)
root = root->_right;
else if (root->_right == nullptr)
root = root->_left;
else
{ Node* min = root->_right;
Node* min_parent = root;
while (min->_left)
{ min_parent = min;
min = min->_left;
}
swap(min->_key, root->_key);
return _EraseR(root->_right, key);
}
delete era;
return true;
}
}
这里讲一下删除的思路:
情况一时,操作和递归的插入基本一样,通过使用引用就可直接令要删除节点的父节点与子节点直接相连,也不用再去判断删除节点是父节点的左边还是右边
情况二时,先找到右子树最小节点,再与要删除的节点交换数值,最后递归传递的节点是,要删除节点的左子树(情况二再交换完数值后就可以按照情况一去处理了)
注意:要提前记录一下找到的要删除的节点,中间过程会改变root的值,所以最后删除的是提前记录好的节点
总体代码
bool insertR(const T& key)
{return _insertR(_root,key);
}
Node* findR(const T& key)
{return _findR(_root,key);
}
bool EraseR(const T& key)
{return _EraseR(_root, key);
}
private:
bool _insertR(Node*& root, const T& key)
{if (root == nullptr)
{ root = new Node(key);
return true;
}
if (root->_key >key)
return _insertR(root->_left, key);
else if (root->_key< key)
return _insertR(root->_right, key);
else
return false;
}
Node* _findR(Node* root, const T& key)
{if (root == nullptr)
return nullptr;
if (root->_key >key)
return _findR(root->_left, key);
else if (root->_key< key)
return _findR(root->_right, key);
else
return root;
}
bool _EraseR(Node*& root, const T& key)
{if (root == nullptr)
return false;
if (root->_key >key)
_EraseR(root->_left, key);
else if (root->_key< key)
_EraseR(root->_right, key);
else
{ Node* era = root;
if (root->_left == nullptr)
root = root->_right;
else if (root->_right == nullptr)
root = root->_left;
else
{ Node* min = root->_right;
Node* min_parent = root;
while (min->_left)
{min_parent = min;
min = min->_left;
}
swap(min->_key, root->_key);
return _EraseR(root->_right, key);
}
delete era;
return true;
}
}
二叉搜索树的应用c++提供了这种键值对儿的结构,叫做pair
pairp1("one",1);
p1.first就是key
p1.second就是value
make_pair("one",p1); 可以构造一个pair
二叉搜索树的性能分析插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
但是会有极端情况:当插入的值顺着一个方向一直插入(即插入的值一直是最小或大或者接近这种情况),那么二叉树就变成了单树,这时的查找效率就是极低了,即结点越深,则比较次数越多。
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流