二叉查找树概念
二叉树中有一种特殊的二叉树--二叉查找树,它最大的特点就是支持动态数据集合的快速插入、删除、查找操作。二叉查找树要求在树中的任意一个节点,其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值。如下图所示

二叉查找树操作
查找
想查找某个值时从根节点出发,如果正好是要找的数据那就直接返回;如果根节点比要找的数据小那就遍历右子树寻找;如果根节点比要找的树大那就遍历左子树寻找。
插入
插入某个值时我们还是从根节点出发,如果要插入的数据比节点的数据大,并且节点的右子树为空,就将新数据直接插到右子节点的位置;如果不为空,就再递归遍历右子树,查找插入位置。同理,如果要插入的数据比节点数值小,并且节点的左子树为空,就将新数据插入到左子节点的位置;如果不为空,就再递归遍历左子树,查找插入位置。
删除
删除时需要分三种情况分析。
- 要删除的值没有子节点。只需要将父节点指向该值得指针置null即可。
- 要删除的值只有一个子节点。只需要更新父节点中,指向要删除节点的指针,让它指向要删除节点的子节点就可以了。
- 要删除的值包含两个子节点。我们需要找到这个节点的右子树中的最小节点,把它替换到要删除的节点上,然后再删除掉这个最小节点。
伪代码实现(PHP)
class Node
{
public $value;
public $left;
public $right;
}
class Tree
{
/**
* 查找数据
* @param [type] $data [数据]
* @return [type] [description]
*/
public function find($data)
{
if ($this->head == null) {
return null;
}
$node = $this->head;
while ($node != null) {
if ($node->data == $data) {
return $node;
} elseif ($data > $node->data) {
$node = $node->right;
} else {
$node = $node->left;
}
}
return null;
}
/**
* 插入数据
* @param [type] $data [数据]
* @return [type] [description]
*/
public function insert($data)
{
if ($this->head == null) {
$this->head = new TreeNode($data);
return true;
}
$node = $this->head;
while ($node != null) {
if ($data > $node->data) {
if ($node->right == null) {
$node->right = new TreeNode($data);
return true;
}
$node = $node->right;
} else {
if ($node->left == null) {
$node->left = new TreeNode($data);
return true;
}
$node = $node->left;
}
}
}
/**
* 删除节点
* @param [type] $data [节点]
* @return [type] [description]
*/
public function delete($data)
{
// 找到需要删除节点
$node = $this->head;
$pnode = null;
while ($node != null) {
if ($node->data == $data) {
break;
} elseif ($data > $node->data) {
$pnode = $node;
$node = $node->right;
} else {
$pnode = $node;
$node = $node->left;
}
}
if ($node == null) {
return false;
}
// 要删除的节点有两个子节点
// 查找右子树中最小节点
if ($node->left != null && $node->right != null) {
$minPP = $node;
$minP = $node->right;
while ($minP->left != null) {
$minPP = $minP;
$minP = $minP->left;
}
$node->data = $minP->data;
$node = $minP;
// 删除掉右子树中的最小节点
$minPP->left = null;
}
if ($node->left != null) {
$child = $node->left;
} elseif ($node->right != null) {
$child = $node->right;
} else {
$child = null;
}
if ($pnode == null) {
// 删除的是根节点
$node = $child;
} elseif ($pnode->left == $node) {
$pnode->left = $child;
} else {
$pnode->right = $child;
}
}
}