二叉搜索树的特征
左子树永远比根节点小,右子树永远比根节点大 也是key模型,看某个数据在不在集合里面。
搜索树的添加
key值比根值大,往右边插入,小,往左边插入 key值和根节点值比较,确定插入在根节点的左边还是右边,根节点一定是某个叶子结点。 比如插入 4,一定是在3的右边 下面的x 当作key
template < class K >
struct bstn
{
bstn ( )
{
cout << "单个链表结点的声明初始化" << endl;
}
bstn ( const K& x)
: _left ( nullptr )
, _right ( nullptr )
, _value ( x)
{
}
bstn* _left;
bstn* _right;
K _value;
} ;
template < class K >
bool bst < K> :: Insert ( const K& x)
{
return bst < K> :: _Insert ( x) ;
}
template < class K >
bool bst < K> :: _Insert ( const K& x)
{
if ( _root== nullptr ) / / 空树的处理
{
_root = new Node ( x) ; / / 调用自定义类型并用x初始化
return true ;
}
Node* parent = nullptr ; / / 防止走到空找不到根节点
Node* cur = _root;
while ( cur)
{
/ / 比右边大,就去右子树的右边插入,
if ( x> cur-> _value)
{
parent = cur;
cur = cur-> _right;
}
else if ( x< cur-> _value) / / ,比根值 小去左边插入
{
parent = cur;
cur = cur-> _left;
}
else
{
return false ;
/ / 这个版本的搜索二叉树不支持值相等
}
}
cur = new Node ( x) ; / new 会调用自定义类型的构造函数初始化
if ( parent-> _value < cur-> _value) / 判断插入在根的左边还是右边
{
parent-> _right = cur;
}
else
{
parent-> _left = cur;
}
return true ;
}
搜索树的遍历打印
template < class K >
bool bst < K> :: Ergodic ( )
{
return _Ergodic ( _root) ;
}
template < class K >
bool bst < K> :: _Ergodic ( Node* root)
{
/ 视为一个满二叉树进行遍历,找到我左为空返回,根,右子树为空返回,在返回上一层;以此类推
if ( root == nullptr )
{
return false ;
}
_Ergodic ( root-> _left) ;
cout << root-> _value << " " ;
_Ergodic ( root-> _right) ;
}
搜索树的查找
key值比根值大,往右边找;比根值小,往左边找,比如说找:8
Node* FindR ( const K& key)
{
return _FindR ( _root, key) ;
}
Node* _Find ( const K& x)
{
Node* cur = _root;
while ( cur)
{
if ( x> cur-> _value)
{
cur = cur-> _right;
}
else if ( x< cur-> _value)
{
cur = cur-> _left;
}
else
{
/ / 不小于左边,不大于右边
return cur;
}
}
return nullptr ;
}
搜索二叉树的删除
先找到那个值:key值比根值大,往右边找;比根值小,往左边找, 找到以后两种情况:
(key值)结点的一侧为空 ,父结点连接上不为空的一侧,删除(key值)结点;5,6,8.删除5 (key值)结点的两侧都不为空:找(key值)左右两边的最值替换:找左边最大的或右边最小的替换。 往根的左边走一步,如果右边不为空,然后持续往右走;最大值的右子树必然是空,往右找到空,记录父节点,然后删除最大值节点。 比如删除 2
bool Erase ( const K& key)
{
return _Erase ( _root, key) ;
}
template < class K >
bool bst < K> :: _Erase ( const K& x) / / x -- - 》 key
{
Node* parent = nullptr ;
Node* cur = _root;
while ( cur)
{
if ( cur-> _value < x)
{
parent = cur;
cur = cur-> _right;
}
else if ( cur-> _value> x)
{
parent = cur;
cur = cur-> _left;
}
else / / 上面走完之后 此处 值相等 找到
{
/ / 左子树或右子树为空,双亲结点连接上孩子结点不为空的一侧,删除key值节点
if ( cur-> _left == nullptr )
{
if ( _root == cur)
{
_root = cur-> _right;
}
else
{
if ( cur = parent-> _left)
{
parent-> _left = cur-> _right;
}
else
{
parent-> _right = cur-> _right;
}
}
delete cur;
}
else if ( cur-> _right == nullptr )
{
if ( _root == cur)
{
_root = cur-> _left;
}
else
{
if ( cur = parent-> _left)
{
parent-> _left = cur-> _left;
}
else
{
parent-> _right = cur-> _left;
}
}
delete cur;
}
else / / 两边都不为空 左边的最大值节点和 key节点交换值 , 删除最大值节点
{
Node* maxLeft = cur-> _left;
Node* pmax = cur;
while ( maxLeft-> _right) / / 不为空就往右边走 一个值记录最值的父节点
{
pmax = maxLeft;
maxLeft = maxLeft-> _right;
}
cur-> _value = maxLeft-> _value;
if ( pmax-> _right= maxLeft) / / 此时最大值节点的右边为空,左边还可能有子树比它小的
{
pmax-> _right = maxLeft-> _left; / / 判断最大值节点是父结点的哪一边
}
else / / 让父节点接上最大值节点的左子树
{
pmax-> _left = maxLeft-> _left;
}
delete maxLeft;
}
return true ; / / 删除完成返回
}
}
return false ; / / 走到空说明没有那个值
}
递归版本
递归插入
插入10
bool InsertR ( const K& key)
{
return _InsertR ( _root, key) ;
}
template < class K >
bool bst < K> :: _InsertR ( Node* & root, const K& key)
{
if ( root== nullptr ) / / 是对8 右指针的引用
{
root = new Node ( key) ; / / 8 -> right = . . . . . 接上即可
return true ;
}
else
{
if ( root-> _value < key)
return _InsertR ( root-> _right, key) ;
else if ( root-> _value > key)
return _InsertR ( root-> _left, key) ;
else
return false ;
}
}
递归查找
比如查找:3
Node* FindR ( const K& key)
{
return _FindR ( _root, key) ;
}
template < class K >
bst< K> :: Node* bst < K> :: _FindR ( Node* & root, const K& key) / / 3
{
if ( root == nullptr ) / / 2 的右子树引用 3
{
return nullptr ;
}
if ( root-> _value < key) / / 2
return _FindR ( root-> _right, key) ; / / 不大
else if ( root-> _value > key) / / 5 2 / / 不小
return _FindR ( root-> _left, key) ;
else
return root; / / 相等返回 秒啊
}
递归删除
比如删除:2
bool EraseR ( const K& key)
{
return _EraseR ( _root, key) ;
}
template < class K >
bool bst < K> :: _EraseR ( Node* & root, const K& key)
{
if ( root == nullptr )
{
return false ;
}
if ( root-> _value< key)
{
return _EraseR ( root-> _right, key) ;
}
else if ( root-> _value> 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 / / 有 1 3
{
Node* maxLeft = root-> _left;
while ( maxLeft-> _right)
{
maxLeft = maxLeft-> _right;
}
root-> _value = maxLeft-> _value;
return _Erase ( root-> _left, maxLeft-> key) ;
}
delete del;
return true ;
}
}
接口总览
template < class K >
class bst
{
public :
typedef bstn< K> Node;
bst ( )
{
cout << "搜索二叉树的节点" << endl;
}
bool Insert ( const K& x) ;
bool Ergodic ( ) ;
Node* Find ( const K& x)
{
return _Find ( x) ;
}
bool Erase ( const K& x)
{
return _Erase ( x) ;
}
bool InsertR ( const K& key)
{
return _InsertR ( _root, key) ;
}
Node* FindR ( const K& key)
{
return _FindR ( _root, key) ;
}
bool EraseR ( const K& key)
{
return _EraseR ( _root, key) ;
}
private :
bool _Insert ( const K& x) ; / / 隐藏实现细节
bool _Ergodic ( Node* root) ;
bool _Erase ( const K& x) ;
Node* _Find ( const K& x)
{
Node* cur = _root;
while ( cur)
{
if ( x> cur-> _value)
{
cur = cur-> _right;
}
else if ( x< cur-> _value)
{
cur = cur-> _left;
}
else
{
/ / 不小于左边,不大于右边
return cur;
}
}
return nullptr ;
}
bool _InsertR ( Node* & root, const K& key) ;
Node* _FindR ( Node* & root, const K& key) ;
bool _EraseR ( Node* & root, const K& key) ;
Node* _root;
} ;
key-Value 模型
场景:字典翻译,统计单词出现的次数; 刷身份证进站。 是对Key模型的改造:
添加一个V模板参数即可,添加时多添加一个参数 找到Key就能删除Value
基建
namespace KEY_VALUE
{
template < class K , class V >
struct BSTreeNode
{
BSTreeNode< K, V> * _left;
BSTreeNode< K, V> * _right;
K _key;
V _value;
BSTreeNode ( const K& key, const V& value)
: _left ( nullptr )
, _right ( nullptr )
, _key ( key)
, _value ( value)
{ }
} ;
template < class K , class V >
class BSTree
{
typedef BSTreeNode< K, V> Node;
public :
. . . . .
private :
Node* _root = nullptr ;
}
key-Value的添加
bool _InsertR ( Node* & root, const K& key, const V& value)
{
if ( root== nullptr )
{
root = new Node ( key, value) ;
return true ;
}
else
{
if ( root-> _key < key)
return _InsertR ( root-> _right, key) ;
else if ( root-> _key > key)
return _InsertR ( root-> _left, key) ;
else
return false ;
}
}
key-Value的遍历打印
bool _Ergodic ( Node* root)
{
if ( root == nullptr )
{
return false ;
}
_Ergodic ( root-> _left) ;
cout << root-> _key << " " << root-> _value<< endl;
_Ergodic ( root-> _right) ;
}
key-Value的查找
Node* _FindR ( const K& key)
{
Node* cur = _root;
while ( cur)
{
if ( key> cur-> _key)
{
cur = cur-> _right;
}
else if ( key< cur-> _key)
{
cur = cur-> _left;
}
else
{
return cur;
}
}
return nullptr ;
}
key-Value的删除
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* maxLeft = root-> _left;
while ( maxLeft-> _right)
{
maxLeft = maxLeft-> _right;
}
root-> _key = maxLeft-> _key;
root-> _value = maxLeft-> _value;
return _Erase ( root-> _left, maxLeft-> _key) ;
}
delete del;
return true ;
}
}
简单字典
void TestDict ( )
{
KEY_VALUE:: BSTree< string, string> dict;
dict. InsertR ( "crash" , "崩溃" ) ;
dict. InsertR ( "priority" , "优先级" ) ;
string str;
while ( cin >> str)
{
if ( str == "Q" )
{
break ;
}
else
{
auto ret = dict. FindR ( str) ;
if ( ret == nullptr )
{
cout << "This word is not available in the dictionary, please re-enter it" << endl;
}
else
{
cout << ret-> _key << "->" << ret-> _value << endl;
}
}
}
}
统计单词(字符串)出现次数
void TestCWord ( )
{
string str[ ] = { "i" , "dont" , "have" , "a" , "dream" , "when" , "i" , "was" , "a" , "child" } ;
KEY_VALUE:: BSTree< string, int > countree;
for ( auto & i : str)
{
auto ret = countree. _FindR ( i) ;
if ( ret== nullptr )
{
countree. _InsertR ( i, 1 ) ;
}
else
{
ret-> _value++ ;
}
}
countree. _Ergodic ( ) ;
}
结束
按时吃饭,不要熬夜,太累了就睡觉…