一、二叉搜索树
1.1 定义
若左子树不为空,那么左子树上的所有节点的值都小于根节点的值。
若右子树不为空,那么右子树上的所有节点的值都大于根节点的值。
其左右子树也是二叉搜索树。
1.2 意义
有了这样的条件以后,可以非常方便且十分高效的进行数据查找。如果我们要哦查找1元素,首先和根节点5进行比较,因为比5小所以在5的左子树中进行进一步的查询,又因为1比3小所以再在3的左子树进行查询最后可以很顺利的找到 1 。
普遍上来说二叉搜索树的查询效率为 logN ,但是如果二叉树构建完成后是一条线的话,那么查找起来的效率也是 N 。
二、搜索二叉树的实现
2.1 构造树的节点
树种的节点我们采用模板参数的方式来实现
其中有三个元素:左指针(left)、右指针(right)、存储值(key)。
#include<iostream>
using namespace std;
template<class K>
class BSTreeNode<K>
{
public:
BSTreeNode(const K& key = K())
:left(nullptr)
,right(nullptr)
,_key(key)
{
}
BSTreeNode<k> * left;
BSTreeNode<k> * right;
K _key;
};
2.2 构造二叉搜索树
#include<iostream>
using namespace std;
template<class K>
class BSTreeNode<K>
{
public:
BSTreeNode(const K& key = K())
:left(nullptr)
,right(nullptr)
,_key(key)
{
}
BSTreeNode<k> * left;
BSTreeNode<k> * right;
K _key;
};
template<class K>
class BSTree
{
typedef BSTreeNode<k> Node;
public:
Node* _root = nullptr;
};
2.3 添加插入功能
先判断是不是有一个空树,如果空树就新建一个节点并返回true。
如果不是空树,那就要确定插入的位置,首先和根节点的值进行比较比根节点小那就往左遍历,如果比根节点大那就往右遍历。具体实现如下所示,但是这么写会有一个问题,我们找到了具体应该插入的位置,并且新建了一个节点,但是 cur = new Node(key)这一步并没有真正的把节点插入到树中。
#include<iostream>
using namespace std;
template<class K>
class BSTreeNode<K>
{
public:
BSTreeNode(const K& key = K())
:left(nullptr)
,right(nullptr)
,_key(key)
{
}
BSTreeNode<k> * left;
BSTreeNode<k> * right;
K _key;
};
template<class K>
class BSTree
{
typedef BSTreeNode<k> Node;
bool insert(const k& key)
{
if(_root == nullptr)
{
_root = new Node(key);
return true;
}
else
{
Node * cur = _root;
while(cur)
{
if(cur->_key > key)
{
cur = cur->left;
}
else if(cur->_key < key)
{
cur = cur->right;
}
else
{
return false;
}
}
cur = new Node(key);
return true;
}
}
public:
Node* _root = nullptr;
};
因为没有真正把节点插入到树种,所以我们需要保存一下插入节点位置的父节点,用父节点去指向这个新的位置即可。
#include<iostream>
using namespace std;
template<class K>
class BSTreeNode<K>
{
public:
BSTreeNode(const K& key = K())
:left(nullptr)
,right(nullptr)
,_key(key)
{
}
BSTreeNode<k> * left;
BSTreeNode<k> * right;
K _key;
};
template<class K>
class BSTree
{
typedef BSTreeNode<k> Node;
bool insert(const k& key)
{
if(_root == nullptr)
{
_root = new Node(key);
return true;
}
else
{
Node * cur = _root;
Node * parent = nullptr;
while(cur)
{
parent = cur;
if(cur->_key > key)
{
cur = cur->left;
}
else if(cur->_key < key)
{
cur = cur->right;
}
else
{
return false;
}
}
cur = new Node(key);
if(parent->_key < key)
parent->right = cur;
else
parent->left = cur;
return true;
}
}
public:
Node* _root = nullptr;
};
#include<iostream>
using namespace std;
namespace key
{
template<class k>
struct BSTreeNode
{
BSTreeNode<k>* left;
BSTreeNode<k>* right;
k _key;
BSTreeNode(const k& key)
:left(nullptr)
, right(nullptr)
, _key(key)
{
}
};
template<class k>
class BSTree
{
typedef BSTreeNode<k>Node;
public:
bool Insert(const k& key)
{
if (_root == nullptr)
{
_root = new Node(key);
return true;
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
parent = cur;
if (cur->_key < key)
{
cur = cur->right;
}
else if (cur->_key > key)
{
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 FindR(const k& key)
{
return _FindR(_root, key);
}
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;
}
}
/*bool _InsertR(Node* &root, const k& 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;
}
bool Insert(const k& key)
{
return _Insert(_root, key);
}*/
//bool _EraseR(const k& key)
//{
// return _EraseR(_root, key);
//}
//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
// {
// if (root->left == nullptr)
// {
// Node* del = root;
// root = root->right;
// delete del;
// return true;
// }
// else if (root->right == nullptr)
// {
// Node* del = root;
// root = root->left;
// delete del;
// return true;
// }
// else
// {
// Node* subLeft = cur->right;
// while (subLeft->left)
// {
// parent = subLeft;
// subLeft = subLeft->left;
// }
// swap(cur->_key, subLeft->_key);
// //转换为子树去递归删除
// return _Erase(root->right, key);
// }
// }
//}
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
{
//开始删除
if (cur->left == nullptr)//节点左为空
{
if (cur == _root)
{
_root = cur->right;
}
else
{
if (cur == parent->left)
{
parent->left = cur->right;
}
else
{
parent->right = cur->right;
}
}
}
else if (cur->right == nullptr)//节点右为空
{
if (cur == _root)
{
_root = cur->left;
}
else
{
if (cur == parent->left)
{
parent->left = cur->left;
}
else
{
parent->right = cur->left;
}
}
}//判断左为空或者右为空的情况
else//节点左右都不为空
{
//右树的最小节点(最左节点)
Node* parent = cur;
Node* subLeft = cur->right;
while (subLeft->left)
{
parent = subLeft;
subLeft = subLeft->left;
}
swap(cur->_key, subLeft->_key);
if (subLeft == parent->left)
parent->left = subLeft->right;
else
parent->right = subLeft->right;
}
return true;
}
}
return false;
}
void InOrder()
{
_InOrder(_root);
}
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->left);
cout << root->_key << " ";
_InOrder(root->right);
}
void Destory(Node*& root)
{
if (root == nullptr)
return;
Destory(root->left);
Destory(root->right);
delete root;
root = nullptr;
}
~BSTree()
{
Destory(_root);
}
Node* Copy(Node* root)
{
if (root == nullptr)
{
return nullptr;
}
Node* newRoot = new Node(root->_key);
newRoot->left = Copy(root->left);
newRoot->right = Copy(root->right);
return newRoot;
}
//BSTree()
//{
//}
BSTree() = default;//等于上面的写法,强制生成默认的构造函数
BSTree(const BSTree<k>& t)
{
_root = Copy(t._root);
}
BSTree<k>& operator=(BSTree<k>t)
{
swap(_root, t._root);
return *this;
}
private:
Node* _root = nullptr;
};
}
//namespace kv
//{
// template<class k,class v>
// class BSTreeNode
// {
// public:
// BSTreeNode<k,v>* left;
// BSTreeNode<k,v>* right;
// k _key;
// v _value;
// BSTreeNode(const k& key = k(), const v& value = v())
// :left(nullptr)
// ,right(nullptr)
// ,_key(key)
// ,_value(value)
// {
// /*left = nullptr;
// right = nullptr;
// _key = key;
// _value = value;*/
// }
// };
// template<class k,class v>
// class BSTree
// {
// typedef BSTreeNode<k,v> Node;
// public:
// bool Insert(const k& key,const v& value)
// {
// if (_root == nullptr)
// {
// _root = new Node(key,value);
// return true;
// }
// Node* cur = _root;
// Node* parent = nullptr;
// while (cur)
// {
// parent = cur;
// if (cur->_key < key)
// {
// cur = cur->right;
// }
// else if (cur->_key > key)
// {
// cur = cur->left;
// }
// else
// {
// return false;
// }
// }
// cur = new Node(key,value);
// if (parent->_key < key)
// {
// parent->right = cur;
// }
// else
// {
// parent->left = cur;
// }
// return true;
// }
// Node* 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 cur;
// }
// return nullptr;
// }
//
// 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
// {
// //开始删除
// if (cur->left == nullptr)//节点左为空
// {
// if (cur == _root)
// {
// _root = cur->right;
// }
// else
// {
// if (cur == parent->left)
// {
// parent->left = cur->right;
// }
// else
// {
// parent->right = cur->right;
// }
// }
// }
// else if (cur->right == nullptr)//节点右为空
// {
// if (cur == _root)
// {
// _root = cur->left;
// }
// else
// {
// if (cur == parent->left)
// {
// parent->left = cur->left;
// }
// else
// {
// parent->right = cur->left;
// }
// }
// }//判断左为空或者右为空的情况
//
// else//节点左右都不为空
// {
// //右树的最小节点(最左节点)
// Node* parent = cur;
// Node* subLeft = cur->right;
// while (subLeft->left)
// {
// parent = subLeft;
// subLeft = subLeft->left;
// }
// swap(cur->_key, subLeft->_key);
// if (subLeft == parent->left)
// parent->left = subLeft->right;
// else
// parent->right = subLeft->right;
// }
// return true;
// }
// }
// return false;
// }
// void InOrder()
// {
// _InOrder(_root);
// }
// void _InOrder(Node* root)
// {
// if (root == nullptr)
// {
// return;
// }
// _InOrder(root->left);
// cout << root->_key << ":" << root->_value << endl;
// _InOrder(root->right);
// }
// void Destory(Node*& root)
// {
// if (root == nullptr)
// return;
// Destory(root->left);
// Destory(root->right);
// delete root;
// root = nullptr;
// }
// ~BSTree()
// {
// Destory(_root);
// }
// Node* Copy(Node* root)
// {
// if (root == nullptr)
// {
// return nullptr;
// }
// Node* newRoot = new Node(root->_key);
// newRoot->left = Copy(root->left);
// newRoot->right = Copy(root->right);
// return newRoot;
// }
// BSTree() = default;//等于上面的写法,强制生成默认的构造函数
//
// private:
// Node* _root = nullptr;
// };
//}
2.4 删除功能
2.4.1 删除的几种情况
其中情况D在删除一个节点时,如果这个节点不是叶子结点,那我们就要进行替换法进行删除。
可替换的节点有两个。
其一是左子树的最大节点(为左子树的最右节点,右子树为空)
其二是右子树的最小节点(为右子树的最左节点,左子树为空)
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
{
//开始删除
if (cur->left == nullptr)//节点左为空
{
if (cur == _root)
{
_root = cur->right;
}
else
{
if (cur == parent->left)
{
parent->left = cur->right;
}
else
{
parent->right = cur->right;
}
}
}
else if (cur->right == nullptr)//节点右为空
{
if (cur == _root)
{
_root = cur->left;
}
else
{
if (cur == parent->left)
{
parent->left = cur->left;
}
else
{
parent->right = cur->left;
}
}
}//判断左为空或者右为空的情况
else//节点左右都不为空
{
//右树的最小节点(最左节点)
Node* parent = cur;
Node* subLeft = cur->right;
while (subLeft->left)
{
parent = subLeft;
subLeft = subLeft->left;
}
swap(cur->_key, subLeft->_key);
if (subLeft == parent->left)
parent->left = subLeft->right;
else
parent->right = subLeft->right;
}
return true;
}
}
return false;
}