二叉查找树又称为二叉排序树,他要么是一颗空树,要么满足以下性质:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉查找树;
值得注意两点:
对于同一个序列,二叉查找树并不唯一,这使得二叉查找树基本操作的最坏情况运行时间在O(logN)到O(N)(当选择最小或最大值作为根节点且构成线性链时)之间,对于随机构造的二叉查找树,其期望高度为O(logN),从而基本操作的平均时间为O(logN)。
即便是对于随机构造的二叉查找树,经过多次插入,删除后,该树的高度也有可能接近O(N),因此二叉查找树实际应用中性能并不一定会很理想,这就引申出红黑树,简而言之,红黑树即采用了一系列手段保证高度接近O(logN)的一种二叉查找树,红黑树在标准C++的STL中应用广泛。
如果要求找出二叉查找树中序遍历顺序下一个节点的后继,则对于任一节点来说,其后继要么不存在,要么是大于该节点关键值中最小的一个,亦即,如果该节点有右子树的话,找到他的右子树中的最小值即可,如果没有呢?
查询一个节点后继的C++代码:
Node *Min(Node *root)
{
while(root->leftChild!=NULL)
root=root->leftChild;
return root;
}
//查找节点node的后继
Node *Successor(Node *node)
{
//右子树不为空的情况,直接返回右子树的最小值
if(node->rightChild!=NULL)
{
return Min(node->rightChild);
}
//右子树为空
Node *parent=node->parent;
while(parent!=NULL&&node==parent->rightChild)
{
node=parent;
parent=parent->parent;
}
return parent;
}
二叉查找树的构造即节点的插入过程.
二叉查找树中,新插入的节点一定是叶子节点,同样的一组元素,不同的插入顺序将会生成不同的二叉查找树,最坏情况是当输入完全有序时,二叉查找树变成单链。
代码如下:
//二叉排序树的插入
void Insert(Node *root,Node *newNode)
{
Node *parent=0;
Node *tempNode=root;
while(tempNode!=NULL)
{
if(newNode->data<tempNode->data)
{
tempNode=tempNode->leftChild;
}
else
{
tempNode=tempNode->rightChild;
}
parent=tempNode->parent;
}
if(parent==NULL)
{
root->data=newNode->data;
}
else
{
if(newNode->data<parent->data)
{
parent->leftChild=newNode;
}
else
{
parent->rightChild=newNode;
}
newNode->parent=parent;
}
}
二叉查找树的删除过程则略显复杂一些,假如要删除节点z,一共有三种情况:
1、z无子女,则直接将z父节点对应的指针域置为NULL即可。
2、z有一个子女,这个也比较简单,用z的子女代替z的位置即可。
3、z有两个子女,此时应该找到z的后继,将z的后继中的值赋给z,然后删除z的后继,这里又分为此后继有无右子女两种情况(该后继肯定没有左子女)。
代码如下:
//在根节点*root的二叉查找树中删除node
Node *DeleteNode1(Node **root,Node *node)
{
Node *delNode=0;
Node *childNode;
//delNode为真正要删除的节点
if(node->leftChild==NULL||node->rightChild==NULL)
{
delNode=node;
}
else
{
delNode=Successor(node);
}
//确定delNode的非NULL子女(如果有的话)
if(delNode->leftChild!=NULL)
{
childNode=delNode->leftChild;
}
else
{
childNode=delNode->rightChild;
}
//判断delNode的子女是否为null
if(childNode!=NULL)
{
childNode->parent=delNode->parent;
}
//判断delNode是否为根节点
if(delNode->parent==NULL)
{
*root=childNode;
}
//简单的二叉树删除后的连接
if(delNode==delNode->parent->leftChild)
{
delNode->parent->leftChild=childNode;
}
if(delNode==delNode->parent->rightChild)
{
delNode->parent->rightChild=childNode;
}
if(delNode!=node)
{
node->data=delNode->data;
}
return delNode;
}
当然,除此之外,二叉查找树的前中后序遍历与普通二叉树并无二致。