【C++】2.3 二叉搜索树的实现
代码语言:javascriptAI代码解释K _key;
·
二叉搜索树
左子树<=根,右子树>=根
根据需求不同,等于的元素可能会被去重也可能会被留下
这样查找一个数就可以只遍历一次,数大选哪个右走,小往左走
查找效率:ologn~on
改进:AVL树,红黑树,B树系列,查找效率:ologn
模拟实现(不多插入相同元素)
一.Key结构
1. 节点的定义
代码语言:javascript
AI代码解释
template<class K>
struct bsnode
{
K _key;
bsnode* _left;
bsnode* _right;
bsnode(const K& key)
:_key(key)
,_left(nullptr)
,_right(nullptr)
{}
};
2. 成员
代码语言:javascript
AI代码解释
typedef bsnode<K> node;
node* _root = nullptr;
代码语言:javascript
AI代码解释
这样,可以不用写构造函数
3. 二叉树的插入
代码语言:javascript
AI代码解释
bool insert(const K& key)
{
if (_root == nullptr)
{
_root = new node(key);
return 1;
}
node* cur = _root;
node* par = nullptr;
while (cur != nullptr)
{
if (cur->_key < key)
{
par = cur;
cur = cur->_right;
}
else if (cur->_key > key)
{
par = cur;
cur = cur->_left;
}
else
{
return 0;
}
}
node* newnode = new node(key);
if (par->_key < key)
{
par->_right = newnode;
}
else
{
par->_left = newnode;
}
return 1;
}
方案:定一个cur的指针,当根节点小于插入元素,向右走,大于则向左走
如果已经有这个数了,则返回false
如果cur为空,则构造一个节点,和cur最后一次经过的节点连接,返回true
那么,cur已经指向空了,怎么才能知道cur最后一次经过的节点?
在额外弄一个par指针尾随cur即可
4. 树排序
二叉搜索树的中序遍历(左->中->右)的特点:为从小到大的数组
因此,可以中序遍历得到有序数组,叫做树排序
代码语言:javascript
AI代码解释
void inorder()
{
_inorder(_root);
}
void _inorder(node* root)
{
if (root == nullptr)return;
_inorder(root->_left);
std::cout << root->_key << " ";
_inorder(root->_right);
}
5. 查找
和插入同理,但是要找的值大于节点向右走,小于往左走
代码语言:javascript
AI代码解释
bool find(const K& _key)
{
node* cur = _root;
while (cur)
{
if (_key < cur->_key)
{
cur = cur->_left;
}
else if (_key > cur->_key)
{
cur = cur->_right;
}
else
{
return 1;
}
}
return 0;
}
6. 删除(重要)
删除的集中情况(设删除节点的名称为M)
- M子节点左右均空:直接删除即可
- M子节点一个为空:M父节点指向M的一个子节点,再删除M
- M左右节点都为空: 替换删除法:将M节点用下面的节点交换,再删除下面的数字节点 那么和哪个节点交换既可以做到快速删除又可以做到保持左子树<=根,右子树>=根的性质呢 和左子树的最右节点(最大节点)或右子树的最左节点(最小节点) (1)删除快速:由于两个情况都是最左或最右节点,因此一定满足删除方案1或2,因此删除简单 (2)由于两个情况要么是小的最大,要么是大的最小,因此性质也是满足的 下面用右边最左来演示
代码语言:javascript
AI代码解释
bool erase(const K& _key)
{
node* par = nullptr;
node* cur = _root;
while (cur)
{
if (cur->_key < key)
{
par = cur;
cur = cur->_right;
}
else if (cur->_key > key)
{
par = cur;
cur = cur->_left;
}
else
{
if (cur->_left == nullptr)
{
if (cur == _root)
{
_root = cur->_right;
}
else
{
if (par->_left == cur)
{
par->_left = cur->_right;
}
else
{
par->_right = cur->_right;
}
}
delete cur;
}
else if (cur->_right == nullptr)
{
if (cur == _root)
{
_root = cur->_left;
}
else
{
if (par->_left == cur)
{
par->_left = cur->_left;
}
else
{
par->_right = cur->_left;
}
}
delete cur;
}
else
{
node* rp = cur;
node* r = cur->_right;
while (r->_left)
{
rp = r;
r = r->_left;
}
cur->_key = r->_key;
if (rp->_left == r)
{
rp->_left = r->_right;
}
else
{
rp->_right = r->_right;
}
delete r;
}
return 1;
}
}
return 0;
}
代码逻辑
- 先找值为val的节点(找不到返回0),设找到的节点为M
- 节点M左为空: (1)节点M为根节点:直接将右节点设为根节点(有没有右节点都无所谓) (2)M不为根节点: A.M为左节点:M根节点连接M右节点,删M
更多推荐


所有评论(0)