二叉搜索树又称二叉排序树,它或者是一棵空树或者是具有以下性质的二叉树:
1.若它的左子树不为空,则左子树上所有节点的值都小于根节点的值。
2.若它的右子树不为空,则右子树上所有节点的值都大于根节点的值。
3.它的左右子树也分别为二叉搜索树。
1. 节点的类
template<class T,class V = int> // 第二个模板可以不使用,用于记录key对应的某个数据
struct Node
{
Node<T,V>* _left;
Node<T,V>* _right;
T _key;
V _value;
Node(const T& key=T(),const V& value=V())
{
_left = nullptr;
_right = nullptr;
_key = key;
_value = value;
}
};
2. 插入函数
bool Insert(const T& key=T(), const V& value=V()) // 全缺省,方便只需要一个模板存储key的时候
{
if (_pnode == nullptr)
{
_pnode = new Node(key,value);
return true;
}
// 找正确的位置,将key插入底层
Node* root = _pnode;
Node* prev = nullptr; // prev记录root的父节点 , 当root为空是,对prev的left或right开辟空间,将key插入
while (root != nullptr)
{
if (root->_key == key)
{
return false; // 不允许重复的数出现
}
if (root->_key > key)
{
prev = root;
root = root->_left;
}
else
{
prev = root;
root = root->_right;
}
}
// root==nullptr结束
if (prev->_key>key)
{
prev->_left = new Node(key,value);
}
else
{
prev->_right = new Node(key,value);
}
return true;
}
3.查找函数
Node* _Find(Node* root, const T& key)
{
if (root == nullptr)
{
return nullptr;
}
if (key == root->_key)
{
return root;
}
else if (key < root->_key)
{
return _Find(root->_left, key);
}
else
{
return _Find(root->_right, key);
}
}
Node* Find(const T& key) // 为什么需要再创建一个函数,因为 this指针是隐藏的,无法在形参里面直接调用this->_pnode
{
return _Find(_pnode, key);
}
4.删除函数
bool Erase(const T& key)
{
if (_pnode == nullptr)
{
return false;
}
//找到key对应的位置
//需要一个prev指针记录key的父节点,这样可以用prev直接连接key的子节点
Node* prev = nullptr;
Node* cur = _pnode;
while (cur != nullptr)
{
if (key == cur->_key)
{
break;
}
else if (key < cur->_key)
{
prev = cur;
cur = cur->_left;
}
else
{
prev = cur;
cur = cur->_right;
}
}
if (cur == nullptr)
{
return false;
}
// cur==_pnode 并且左右至少有一个为空
// 因为当 cur == _ponde prev无法处理,需要单独拿出讨论
if (cur == _pnode)
{
if (cur->_left == nullptr)
{
_pnode = cur->_right;
delete cur;
return true;
}
if (cur->_right == nullptr)
{
_pnode = cur->_left;
delete cur;
return true;
}
}
// cur != _pnode 或 cur== _pnode 且两边均不为nullptr
if (cur->_left == nullptr)
{
if (prev->_left == cur)
{
prev->_left = cur->_right;
}
else
{
prev->_right = cur->_right;
}
delete cur;
return true;
}
if (cur->_right == nullptr)
{
if (prev->_left == cur)
{
prev->_left = cur->_left;
}
else
{
prev->_right = cur->_left;
}
delete cur;
return true;
}
// 当两边都不为空时,这时不需要prev
// 需要找cur左子树的最大只或右子树的最小值去代替cur的key
if (cur->_left != nullptr && cur->_right != nullptr)
{
//找右边的最小值
Node* rightmin = cur->_right;
Node* rightprev = cur;
if (rightmin->_left == nullptr) // cur->right就是右边最小的数
{
rightprev->_right = rightmin->_right;
}
else
{
while (rightmin->_left)
{
rightprev = rightmin;
rightmin = rightmin->_left; // 一直往左移找到最小的数
}
//当rightmin->left=nullptr 时就找到了
cur->_key = rightmin->_key;
}
rightprev->_left = rightmin->_right; // right可能还有右子树
delete rightmin;
return true;
}
}
5.中序遍历
void Pushstack(Node* root,stack<Node*>& s) // 传引用 !!!
{
while (root != nullptr)
{
s.push(root);
root = root->_left;
}
}
void _InOrder(Node* _pnode)
{
stack<Node*> s;
Pushstack(_pnode, s);
while (!s.empty())
{
Node* _top = s.top();
cout << _top->_key << " ";
s.pop();
Pushstack(_top->_right, s);
}
}
void InOrder()
{
this->_InOrder(_pnode);
cout << endl;
}
6.测试
void test1()
{
int arr[] = { 2,4,6,1,32,57,21,23,44,37 };
BSTree<int,int> root;
for (auto a : arr)
{
root.Insert(a);
}
root.InOrder();
root.Erase(6);
root.InOrder();
root.Erase(4);
root.InOrder();
root.Erase(32);
root.InOrder();
root.Erase(57);
root.InOrder();
root.Erase(44);
root.InOrder();
root.Erase(37);
root.InOrder();
root.Erase(23);
root.InOrder();
root.Erase(1);
root.InOrder();
root.Erase(2);
root.InOrder();
root.Erase(21);
root.InOrder();
}
结果:
1 2 4 6 21 23 32 37 44 57
1 2 4 21 23 32 37 44 57
1 2 21 23 32 37 44 57
1 2 21 23 37 44 57
1 2 21 23 37 44
1 2 21 23 37
1 2 21 23
1 2 21
2 21
21
// 需要将中序遍历的cout改一下
cout << _top->_key <<_top->_value << "个" << endl;
//
void test3()
{
string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
"苹果", "香蕉", "苹果", "香蕉" };
BSTree<string, int> counttree;
for (auto a : arr)
{
Node<string, int>* ret = counttree.Find(a);
if (ret)
{
ret->_value++;
}
else
{
counttree.Insert(a, 1);
}
}
counttree.InOrder();
}
结果:
苹果6个
西瓜3个
香蕉2个
void test2()
{
BSTree<string, string> dict;
dict.Insert("string", "字符串");
dict.Insert("tree", "树");
dict.Insert("left", "左边、剩余");
dict.Insert("right", "右边");
dict.Insert("sort", "排序");
// 插入词库中所有单词
string str;
while (cin >> str)
{
Node<string,string>* ret = dict.Find(str);
if (ret == nullptr)
{
cout << "单词拼写错误,词库中没有这个单词:" << str << endl;
}
else
{
cout << str << "中文翻译:" << ret->_value << endl;
}
}
}
结果:
string
string中文翻译:字符串
right
right中文翻译:右边
sort
sort中文翻译:排序
left
left中文翻译:左边、剩余
AMR
单词拼写错误,词库中没有这个单词:AMR
AWM
单词拼写错误,词库中没有这个单词:AWM
2380

被折叠的 条评论
为什么被折叠?



