二叉搜索树(Binary Search Tree) 其实就是二叉树加上一个条件:对于二叉树内的每个父节点及其左右子节点,都必须符合左子节点小于父节点,右子节点大于父节点。
typedef struct node *BST;
struct node{
ElementType data;
BST left;
BST right;
};
1.查找元素X:
因为非递归函数执行效率更高,所以我们用迭代函数来实现
BST Find(BST tree,ElementType X)
{
BST tmp=tree;
while(tmp!=NULL){
if(tmp->data==X) return tmp;
else if(tmp->data<X) tmp=tmp->right;
else if(tmp->data>X) tmp=tmp->left;
}
return NULL;
}
2.查找最大、最小元素:
根据二叉搜索树的特点:对于二叉树内的每个父节点及其左右子节点,都必须符合左子节点小于父节点,右子节点大于父节点。我们可以知道 最小的元素一定是最左侧的没有左子节点的节点,而最大的元素一定是最右侧的没有右子节点的节点。 故我们就可以一直向两侧查找:
BST FindMax(BST tree)//用递归实现找最大元素
{
if(!tree) return NULL;
else if(!tree->right) return tree;
else return FindMax(tree->right);
}
BST FindMin(BST tree)//用迭代实现找最小元素
{
BST tmp=tree;
while(!tmp){
if(!tmp->right) return tmp;
else tmp=tmp->right;
}
return NULL;
}
3.插入元素X:
插入一定不能破坏二叉搜索树的特性:左子节点小于父节点,右子节点大于父节点。
BST Insert(BST tree,ElementType X)
{
if(!tree){
tree=new node;
tree->data=X;
tree->left=tree->right=NULL;
}else{
while(!tree){
if(tree->data>X){
tree->right=Insert(tree->right,X);
}else if(tree->data<X){
tree->left=Insert(tree->left,X);
}else{
cout<<"X已经在树中";
break;
}
}
}
return tree;
}
4.建立二叉搜索树:
和二叉树一样,向一个空二叉树插入元素即可
BST Build(ElementType A[],int N)
{
BST tree=new node;
for(int i=0;i<N;i++){
Insert(tree,A[i]);
}
return tree;
}
5.删除元素X:
因为不能破坏二叉搜索树的特点。
显然我们要分三种情况讨论:
(1)删除叶子结点:不会影响二叉搜索树的特点,显然直接delete掉那个空间即可。
(2)删除的结点有一个子节点:直接让指向被删除结点的指针指向它的唯一子节点即可。
(3)删除的结点有两个子节点:
这时我们就要分析一下了:因为左子节点小于父节点,右子节点大于父节点,所以被删除元素左侧的最大元素是左子树中最右侧的没有右子节点的元素,被删除元素右侧的最小元素是右子树中最左侧的没有左子节点的元素,因为不能破坏二叉搜索树的特点,所以要找最接近被删除节点且符合特点的元素,一定是被删除元素左侧的最大元素和被删除元素右侧的最小元素。
BST Delete(BST tree,ElementType X)
{
BST tmp;
if(!tree) return NULL;
//首先要找到X的位置
else if(X<tree->data) tree->left=Delete(tree->left,X);
else if(X>tree->data) tree->right=Delete(tree->right,X);
else{//找到了
if(tree->left&&tree->right){//第三种情况
tmp=FindMin(tree->right);//用右子树中的最小元素代替父节点
tree->data=tmp->data;
tree=Delete(tree->right,tree->data);
}else{//前两种情况,反正最后都是
tmp=tree;
if(!tree->left) //只有右子节点
tree=tree->right;
if(!tree->right) //只有左子节点
tree=tree->left;
delete tmp;
}
}
return tree;
}
如果我们一直删除符合第三种情况的元素,那么会一直用右子树中的最小元素代替,会导致数的平衡性很差,我们可以交替使用左子树的最大元素和右子树的最小元素,或者用我们之前求二叉树高度的函数Heigh:(https://mp.csdn.net/postedit/104188323)(在文尾)
随时记录当前左右子树的高度,谁的高度大用谁的。
特殊性质的应用:
因为二叉搜索树左子节点小于父节点,右子节点大于父节点,也就是左节点<根节点<右节点,那么我们在中序遍历(左根右)二叉搜索树时得到的是有序序列(从小到大),利用这一性质可以根据需求来搞事情。