二叉树进阶-创新互联
一、二叉搜索树
分享文章:二叉树进阶-创新互联
浏览地址:http://myzitong.com/article/dhjhsd.html
1.2 二叉树的操作 1.2.1 二叉搜索树的查找二叉搜索树性质:
创新互联公司是一家专注于网站制作、网站建设与策划设计,汶上网站建设哪家好?创新互联公司做网站,专注于网站建设10余年,网设计领域的专业建站公司;建站业务涵盖:汶上等地区。汶上做网站价格咨询:18980820575
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
- 它的左、右子树也分别为二叉搜索树
具体步骤:
- 从根 root 开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。
- 最多查找高度次,走到到空 nullptr ,还没找到,则这个值不存在。
bool Find(const K& key)
{
Node* cur = _root;
while(cur)
{
if (cur->_key< key)
{
cur = cur->_right;
}
else if(cur->_key >key)
{
cur = cur->_left;
}
else
{
return true;
}
}
return false;
}
1.2.2 二叉搜索树的插入具体步骤:
- 树为空,则直接新增节点,赋值给root指针
- 树不空,按二叉搜索树性质查找插入位置,插入新节点
bool Insert(const K& key)
{
if (_root == nullptr)
{
_root = new Node(key);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_key< key)
{
parent = cur;
cur = cur->_right;
}
else if(cur->_key >key)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(key);
if (parent->_key< key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
return true;
}
1.2.3 二叉搜索树的删除首先查找元素是否在树中,如果不存在则返回, 否则要删除的结点可能分下面四种情况:看起来删除节点有3种情况,实际上 情况1 可以与 情况2 合并,因此真正的删除过程如下:
- 要删除的结点无孩子结点
- 要删除的结点只有左孩子结点(或者只有右孩子结点)
- 要删除的结点有左、右孩子结点
- 情况1、2:删除该结点,且使被删除节点的双亲结点指向被删除节点的左孩子(或右孩子)结点 -- 直接删除法 -- 没有一个孩子或者只有一个孩子,可以直接删除,孩子托管给父亲
- 情况3:在它的右子树中寻找最小值节点(或者在它的左子树寻找大值节点),用它的值填补到被删除节点中,再来处理该结点的删除问题-- 替换法 -- 两个孩子没办法给父亲,父亲养不了。找个人替代我养孩子。
bool Erase(const K& key)
{
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_key< key)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key >key)
{
parent = cur;
cur = cur->_left;
}
else
{
//两种情况:
//1.
//直接删除,孩子托管给父亲
//没有孩子
//一个孩子 -- 左为空or右为空
//2.
//用替换法,找个人替换
//两个孩子
//找左子树的大值节点,或者右子树的最小值节点
if (cur->_left == nullptr)
{
//if(parent == nullptr)
//即要删除的是根,但是根的左子树为空的状态
if (cur == _root)
{
_root = cur->_right;
}
else
{
if (cur == parent->_left)
{
//parent->_left = cur --->parent->_left = cur->_right
//cur->_left为空,原来cur的位置由cur->_right替代
parent->_left = cur->_right;
}
else
{
// parent->_right = cur--->parent->_left = cur->_
//cur->_left为空,原来cur的位置由cur->_right替代
parent->_right = cur->_right;
}
}
delete cur;
}
else if (cur->_right == nullptr)
{
//if(parent == nullptr)
//即要删除的是根,但是根的右子树为空的状态
if (cur == _root)
{
_root == cur->_left;
}
else
{
if (cur == parent->_right)
{
parent->_right = cur->_left;
}
else
{
parent->_left = cur->_left;
}
delete cur;
}
}
else //两个孩子都不空
{
//右子树的最小节点替代
Node* minParent = cur;
Node* minRight = cur->_right;
while (minRight->_left )
{
minParent = minRight;
minRight = minRight->_left;
}
//交换两者的值,删掉minRight
swap(minRight->_key, cur->_key);
if (minParent->_left == minRight)
{
minParent->_left = minRight->_right;
}
else
{
minParent->_right = minRight->_right;
}
delete minRight;
}
}
return true;
}
return false;
}
1.3 二叉搜索树的实现 templatestruct BSTreeNode
{
BSTreeNode* _left;
BSTreeNode* _right;
K _key;
BSTreeNode(const K& key)
:_left(nullptr)
,_right(nullptr)
,_key(key)
{}
};
templateclass BSTree
{
typedef BSTreeNodeNode;
private:
void DestoryTree(Node* root)
{
if (root == nullptr)
return;
DestoryTree(root->_left);
DestoryTree(root->_right);
delete root;
}
Node* CopyTree(Node* root)
{
if (root == nullptr)
return nullptr;
Node* copyNode = new Node(root->_key );
copyNode->_left = CopyTree(root->_left);
copyNode->_right = CopyTree(root->_right);
return copyNode;
}
public:
//强制编译器自己生成构造
BSTree() = default;
BSTree(const BSTree& t)
{
_root = CopyTree(t._root);
}
BSTree& operator=(BSTreet)
{
swap(_root, t._root);
return *this;
}
~BSTree()
{
DestoryTree(_root);
_root = nullptr;
}
bool Insert(const K& key)
{
if (_root == nullptr)
{
_root = new Node(key);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_key< key)
{
parent = cur;
cur = cur->_right;
}
else if(cur->_key >key)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(key);
if (parent->_key< key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
return true;
}
bool Find(const K& key)
{
Node* cur = _root;
while(cur)
{
if (cur->_key< key)
{
cur = cur->_right;
}
else if(cur->_key >key)
{
cur = cur->_left;
}
else
{
return true;
}
}
return false;
}
bool Erase(const K& key)
{
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_key< key)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key >key)
{
parent = cur;
cur = cur->_left;
}
else
{
//两种情况:
//1.
//直接删除,孩子托管给父亲
//没有孩子
//一个孩子 -- 左为空or右为空
//2.
//用替换法,找个人替换
//两个孩子
//找左子树的大值节点,或者右子树的最小值节点
if (cur->_left == nullptr)
{
//if(parent == nullptr)
//即要删除的是根,但是根的左子树为空的状态
if (cur == _root)
{
_root = cur->_right;
}
else
{
if (cur == parent->_left)
{
//parent->_left = cur --->parent->_left = cur->_right
//cur->_left为空,原来cur的位置由cur->_right替代
parent->_left = cur->_right;
}
else
{
// parent->_right = cur--->parent->_left = cur->_
//cur->_left为空,原来cur的位置由cur->_right替代
parent->_right = cur->_right;
}
}
delete cur;
}
else if (cur->_right == nullptr)
{
//if(parent == nullptr)
//即要删除的是根,但是根的右子树为空的状态
if (cur == _root)
{
_root == cur->_left;
}
else
{
if (cur == parent->_right)
{
parent->_right = cur->_left;
}
else
{
parent->_left = cur->_left;
}
delete cur;
}
}
else //两个孩子都不空
{
//右子树的最小节点替代
Node* minParent = cur;
Node* minRight = cur->_right;
while (minRight->_left )
{
minParent = minRight;
minRight = minRight->_left;
}
//交换两者的值,删掉minRight
swap(minRight->_key, cur->_key);
if (minParent->_left == minRight)
{
minParent->_left = minRight->_right;
}
else
{
minParent->_right = minRight->_right;
}
delete minRight;
}
}
return true;
}
return false;
}
//递归
void InOrder()
{
_InOrder(_root);
cout<< endl;
}
bool FindR(const K& key)
{
return _FindR(_root, key);
}
bool InsertR(const K& key)
{
return _InsertR(_root, key);
}
bool EraseR(const K& key)
{
return _EraseR(_root, key);
}
private:
//递归
//root是上一个传下来的别名(root->_left or root->_right)
//修改root等于修改root->_left / root->_right
bool _EraseR(Node*& root, const K& key)
{
if (root == nullptr)
return false;
if (root->_key< key)
{
return _EraseR(root->_right, key);
}
else if (root->_key >key)
{
return _EraseR(root->_left, key);
}
else
{
Node* del = root;
//删除
if (root->_left == nullptr)
{
root = root->_right;
}
else if (root->_right == nullptr)
{
root = root->_left;
}
else
{
Node* minRight = root->_right;
while (minRight->_left)
{
minRight = minRight->_left;
}
swap(minRight->_key , root->_key );
return _EraseR(root->_right, key);
}
delete del;
return true;
}
}
bool _InsertR(Node*& root, const K& key)
{
if (root == nullptr)
{
root = new Node(key);
return true;
}
if (root->_key< key)
{
return _InsertR(root->_right, key);
}
else if (root->_key >key)
{
return _InsertR(root->_left, key);
}
else
{
return false;
}
}
bool _FindR(Node* root, const K& key)
{
if (root == nullptr)
return false;
if (root->_key< key)
{
return _FindR(root->_right, key);
}
else if (root->_key >key)
{
return _FindR(root->_left, key);
}
else
{
return true;
}
}
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout<< root->_key<< " ";
_InOrder(root->_right);
}
private:
Node* _root = nullptr;
};
1.4 二叉搜索树的应用
1.4.1 K模型K模型:只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。 比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:1.4.2 KV模型
- 以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树
- 在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。
KV模型:每一个关键码key,都有与之对应的值Value,即的键值对。该种方 式在现实生活中非常常见:
- 比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<中国, china>就构成一种键值对
- 再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出 现次数就是
就构成一种键值对
namespace key_value
{
#pragma once
templatestruct BSTreeNode
{
BSTreeNode* _left;
BSTreeNode* _right;
const K _key;
V _value;
BSTreeNode(const K& key, const V& value)
:_left(nullptr)
, _right(nullptr)
, _key(key)
, _value(value)
{}
};
templateclass BSTree
{
typedef BSTreeNodeNode;
public:
void InOrder()
{
_InOrder(_root);
cout<< endl;
}
Node* FindR(const K& key)
{
return _FindR(_root, key);
}
bool InsertR(const K& key, const V& value)
{
return _InsertR(_root, key, value);
}
bool EraseR(const K& key)
{
return _EraseR(_root, key);
}
private:
bool _EraseR(Node*& root, const K& key)
{
if (root == nullptr)
return false;
if (root->_key< key)
{
return _EraseR(root->_right, key);
}
else if (root->_key >key)
{
return _EraseR(root->_left, key);
}
else
{
Node* del = root;
// 删除
if (root->_left == nullptr)
{
root = root->_right;
}
else if (root->_right == nullptr)
{
root = root->_left;
}
else
{
Node* minRight = root->_right;
while (minRight->_left)
{
minRight = minRight->_left;
}
swap(root->_key, minRight->_key);
return _EraseR(root->_right, key);
}
delete del;
return true;
}
}
bool _InsertR(Node*& root, const K& key, const V& value)
{
if (root == nullptr)
{
root = new Node(key, value);
return true;
}
if (root->_key< key)
{
return _InsertR(root->_right, key, value);
}
else if (root->_key >key)
{
return _InsertR(root->_left, key, value);
}
else
{
return false;
}
}
Node* _FindR(Node* root, const K& key)
{
if (root == nullptr)
return nullptr;
if (root->_key< key)
{
return _FindR(root->_right, key);
}
else if (root->_key >key)
{
return _FindR(root->_left, key);
}
else
{
return root;
}
}
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout<< root->_key<< ":"<< root->_value<< endl;
_InOrder(root->_right);
}
private:
Node* _root = nullptr;
};
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
分享文章:二叉树进阶-创新互联
浏览地址:http://myzitong.com/article/dhjhsd.html