数值规定:
节点左边的比节点值小,右边的比节点大
特点:
1.中序遍历有序。(整体是有序的左边的树一定都比节点小,右边的一定比节点大。因为插入时通过遍历按照此规则找到位置新增节点)
2.搜索最多找高度次。
3.不能修改,修改后需重新排序,只能增删方便
#include<iostream>
using namespace std;
template <class T>
class BSTNode
{
public:
BSTNode<T> * _left;//记得加<T>
BSTNode<T> * _right;
T _key;
//传参允许const允许传临时变量,用引用避免拷贝传参,缺省值给临时变量可以外部省去传参,直接构成数组,直接new
BSTNode(const T&key = T() )//BSTNode(T key)
:_key(key), _left(nullptr), _right(nullptr)
{}
};
template<class T>//用模板类要有参数列表
class BSTree
{
typedef BSTNode<T> Node;
Node* root = nullptr;
static void InOrderFind(Node* pcur)
{
if (pcur == nullptr)
return;
InOrderFind(pcur->_left);
cout << pcur->_key << " ";
InOrderFind(pcur->_right);
}
public:
bool Insert(T 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;
}
if (parent->_key>key)
{
parent->_left = new Node(key);
}
else
{
parent->_right = new Node(key);
}
}
}
void InOrderFind()//缺省参数只能缺省常量或全局变量
{
InOrderFind(root);
}
bool Erase(T key)
{
if (root == nullptr)
return false;
Node* cur = root;
Node* parent = nullptr;
while (cur)//最多找到空,找到就删掉返回true结束
{
if (cur->_key > key)
{
parent = cur;//父节点更新在子节点更新前
cur = cur->_left;
}
else if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else
{
//删掉的有0,1个子节点
if (cur->_left == nullptr)
{
if (parent == nullptr)//删只有0,1子节点的根节点,没有父节点
{
Node* delnode = root;
root = root->_right;
delete delnode;
return true;
}
//他的位置在左还是右
if (parent->_left == cur)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
delete cur;
}
else if (cur->_right == nullptr)
{
if (parent == nullptr)
{
Node* delnode = root;
root = root->_left;
delete delnode;
return true;
}
if (parent->_left == cur)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
delete cur;
}
else//两个节点位置
{
//找比节点右边小比左边大的
//找右边最小或左边最大
Node* dparent = cur;
Node* dnode = cur->_right;
while (dnode->_left)
{
dparent = dnode;
dnode = dnode->_left;
}
//右边最小就是节点右边
if (dnode == dparent->_right)
{
cur->_key = dnode->_key;
dparent->_right = dnode->_right;
delete dnode;
}
else
{
cur->_key = dnode->_key;
dparent->_left = dnode->_right;
delete dnode;
}
}
return true;
}
}
return false;
}
};
int main()
{
int a[10] = { 1,4,2,7,3,1,45,7,3,8 };
typedef BSTree<int> BSTreeI;
BSTreeI bstree;
for (auto e : a)
{
bstree.Insert(e);
}
for (auto e : a)
{
bstree.Erase(e);
bstree.InOrderFind();
cout << endl;
}
return 0;
}
构成:同链表,先创建子节点的模板类,记录值和左右子节点,再创建二叉搜索树,包含根节点,至少提供增加和删除和中序遍历。
增加:因为其有序,直接循环遍历,比值大走有,小走左,遍历到空节点插入,额外提前检查是不是空树。
查找 a、从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。 b、最多查找高度次,走到到空,还没找到,这个值不存在。
删除:首先查找元素是否在二叉搜索树中,如果不存在,则返回,找到其位置
删除要记录对应节点位置前的父节点,以便让父节点对下面节点操作:分为
1.要删除节点是含0,1子节点的,判断是不是根节点(根节点没有找到的父节点)是删除返回,父节点直接接入有的那一节点
2.要删除节点含2个子节点,删除这个节点并保持大致结构不变思路是:找到比此节点左子树大,右子树小的节点,即左子树的最右(最大),右子树的最左(最小)节点。同样找到后要删除这个节点,所以要记录其父节点,找到后因为其是最左/最有节点,一定只含0/1个子节点,父节点连接应有的子节点,原要删除节点获取值并删除找到的最节点即可。
补充:
记录并保持其父节点关键是一开始就将父节点变量设为此节点的父,没有设nullptr,然后在每次此节点变化代码前父节点获取此节点的值。