二叉搜索树(BinarySearchTree):
二叉搜索树性质:
1. 每个节点都有一个作为搜索依据的关键码(key),所有节点的关键码互不相同。
2. 左子树上所有节点的关键码(key)都小于根节点的关键码(key)。
3. 右子树上所有节点的关键码(key)都大于根节点的关键码(key)。
4. 左右子树都是二叉搜索树。
如图:是一个二叉搜索树
本文将实现二叉搜索树的插入删除查找
我们先定义一个二叉搜索树的结点结构体
template<class K>
struct BinarySearchTreeNode
{
BinarySearchTreeNode<K>* _left;
BinarySearchTreeNode<K>* _right;
K _key;
BinarySearchTreeNode(const K& key)
:_left(NULL)
, _right(NULL)
, _key(key)
{}
};
插入
插入的返回类型为bool,因为有可能会插入失败
搜索二叉树还有一个特点就是不能有重复的数,因为有重复的数会导致冗余
思想(非递归):我们完成插入的函数需要定义两个结点,cur和parent,我们需要用parent来记录cur的父亲,进入函数首先判断这棵树是否为空,若为空,直接新建结点,并且返回值为true,我们将_root给cur,我们首先要遍历一下这棵树,比根小的向左边走,比根大的向右边走,在这里每次走之前都要先将cur的值给parent,如果相等则返回false(二叉搜索树不能有重复的结点,会冗余),
找到key放的位置后,我们要判断key在parent的左边还是右边,如果在左边,则让parent->_left等于存放key值的结点,反之让parent->_right等于存放key的结点。最后返回true,这样我们的非递归插入就实现好了。(注意:在这里的插入不能用我们下面实现的Find()函数,因为Find()函数只能返回当前结点,而当前节点的parent找不到。没有parent我们Insert()就无法判断结点放左边还是右边)
bool Insert(const K& key)
{
if (_root == NULL)
{
_root = new Node(key);
return true;
}
Node* parent = NULL;
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;
}
}
if (parent->_key > key)
{
Node* tmp = new Node(key);
parent->_left = tmp;
}
else
{
Node* tmp = new Node(key);
parent->_right = tmp;
}
return true;
}
插入(递归实现)思想:
插入的递归实现主要是利用了root的引用,在这里root有两层含义,一个是当前的值,一个是上一层的值也就是当前值的parent。递归实现代码相对简单,但是不太容易理解。
bool _InsertR(Node* &root, const K& key)
{
if (root == NULL)
{
root = new Node(key);
return true;
}
if (root->_key > key)
{
_InsertR(root->_left,key);
}
else if (root->_key < key)
{
_InsertR(root->_right,key);
}
else
{
return false;
}
}
查找
思想:查找的函数思想就很简单了,只要cur为真就进入循环:比根小的向左边走,比根大的向右边走等于根就返回cur.
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_key < key)
{
cur = cur->_right;
}
else if (cur->_key > key)
{
cur = cur->_right;
}
else
{
return cur;
}
}
return NULL;
}
删除
二叉搜索树的删除是在这里最重要的
删除可以分为三种情况:
1,左为空
2,右为空
3,两边都不为空。
删除的非递归思想:
我们先遍历一下这棵树,找到要删除的结点,我们把当前要删除的结点给del,先看左为空,
先判断当前要删除的结点是不是根,是根的话就把根给根的右孩子。
不是根的话,我们需要判断的是cur在parent的左边还是右边
用一幅图来讲解
右为空的情况跟作左为空是相似的,就还是用图直白的解释一下