2018-11-20更新
若是按照17号所改,则会出现新的问题,当不满足前两个条件且要删除的结点没有右子树时就无法正确求解。
17号改条件的原因是:教材中提到,假设左子树的最大值为G,如果左子树的其他结点也有值G,那么选择G作为根结点就会导致一颗二叉树的左子树中具有与子树根结点值G相同的结点,不满足二叉树的性质。
因此将删除操作修改为:
- 需要删除的结点没有右儿子,那么就将左儿子提上去。
- 需要删除的结点的右儿子没有左儿子,那么就将右儿子提上去。
- 以上两种情况都不满足的话,就把右儿子的子孙中最小的结点提到需要删除的结点上。
-----------------------------------------------------------------------------------------------------------------------------------------------------------
2018-11-17更新
remove操作第3种情况将“以上两种情况都不满足的话,就把左儿子的子孙中最大的结点提到需要删除的结点上。”更改为
以上两种情况都不满足的话,就把左儿子的子孙中最大的结点提到需要删除的结点上或者右儿子的子孙中最小的结点提到需要删除的结点上(如果二叉树中有重复值,那么应该选右儿子的子孙中最小的结点)
remove函数中可作出相应改变。
-----------------------------------------------------------------------------------------------------------------------------------------------------------
- 说明
- 基于二叉链表实现的二叉搜索树
- 参考资料
一、说明:
insert实现BST的插入操作,find实现BST的查找操作,remove实现BST的删除操作,时间复杂度平均都为O(logn)
insert函数和find函数实现较简单,remove较为麻烦:
- 需要删除的结点没有左儿子,那么就将右儿子提上去。
- 需要删除的结点的左儿子没有右儿子,那么就将左儿子提上去。
- 以上两种情况都不满足的话,就把左儿子的子孙中最大的结点提到需要删除的结点上。
以下代码仅供参考
二、基于二叉链表实现的二叉搜索树
1、BSTNode.h
#include<iostream>
using namespace std;
#ifndef _BSTNode
#define _BSTNode
namespace wangzhe
{
template<typename E>
class BSTNode
{
private:
E it;
BSTNode* lc;
BSTNode* rc;
public:
BSTNode()
{
lc=rc=NULL;
}
BSTNode(E e,BSTNode* l=NULL,BSTNode* r=NULL)
{
it=e;lc=l;rc=r;
}
E& element()
{
return it;
}
void setElement(const E& e)
{
it=e;
}
inline BSTNode* left() const
{
return lc;
}
void setLeft(BSTNode<E>* b)
{
lc=b;
}
inline BSTNode* right() const
{
return rc;
}
void setRight(BSTNode<E>* b)
{
rc=b;
}
bool isleaf()
{
return (lc==NULL)&&(rc==NULL);
}
};
}
#endif
2、BST.h
#include<iostream>
using namespace std;
#include"BSTNode.h"
#ifndef _BST
#define _BST
namespace wangzhe
{
template<typename E>
class BST
{
private:
BSTNode<E>* root;//树根
public:
BST();//构造函数
void setRoot(BSTNode<E>* b);//设置根结点
BSTNode<E>* insert(BSTNode<E>* b,int val);//插入结点
int find(BSTNode<E>* b,int val,int count);//查找值并返回第一次找到该值时的比较次数
BSTNode<E>* remove(BSTNode<E>* b,int val);//删除第一个值是val的结点
void inorder(BSTNode<E>* b);//中序遍历
void preorder(BSTNode<E>* b);//前序遍历
};
}
#endif
3、BST.cpp
#include<iostream>
using namespace std;
#include"BST.h"
namespace wangzhe
{
template<typename E>
BST<E>::BST()
{
root=NULL;
}
template<typename E>
void BST<E>::setRoot(BSTNode<E>* b)
{
root=b;
}
template<typename E>
BSTNode<E>* BST<E>::insert(BSTNode<E>* b,int val)
{
if(b==NULL)
{
BSTNode<E>* temp=new BSTNode<E>(val);
return temp;
}
else
{
if(val<b->element()) b->setLeft(insert(b->left(),val));//小于往左边插入元素
else b->setRight(insert(b->right(),val));//大于等于往右边插入元素
return b;
}
}
template<typename E>
BSTNode<E>* BST<E>::remove(BSTNode<E>* b,int val)
{
if(b==NULL) return NULL;
else if(val<b->element()) b->setLeft(remove(b->left(),val));//小于往左边
else if(val>b->element()) b->setRight(remove(b->right(),val));//大于往右边
//找着要删除的元素了
else if(b->right()==NULL)//需要删除的结点没有右儿子,把左儿子提上去
{
BSTNode<E>* t=b->left();
delete b;
return t;
}
else if(b->right()->left()==NULL)//需要删除的结点的右儿子没有左儿子,把右儿子提上去
{
BSTNode<E>* t=b->right();
t->setLeft(b->left());//别忘记将左儿子补上
delete b;
return t;
}
else //其他情况,将右儿子的子孙中最小的结点提到需要删除的结点上
{
BSTNode<E>* q=b->right();
for(;q->left()->left()!=NULL;q=q->left());
BSTNode<E>* l=q->left();//右儿子中最小的结点
q->setLeft(l->right());
l->setLeft(b->left());
l->setRight(b->right());
delete b;
return l;
}
return b;
}
template<typename E>
int BST<E>::find(BSTNode<E>* b,int val,int count)
{
if(b==NULL) return -1;
else if(val==b->element()) return count;
else if(val<b->element()) return find(b->left(),val,count+1);
else return find(b->right(),val,count+1);
}
template<typename E>
void BST<E>::inorder(BSTNode<E>* b)
{
if(b==NULL) return ;
inorder(b->left());
cout<<b->element()<<' ';
inorder(b->right());
}
template<typename E>
void BST<E>::preorder(BSTNode<E>* b)
{
if(b==NULL) return ;
cout<<b->element()<<' ';
preorder(b->left());
preorder(b->right());
}
}
4、main.cpp
#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
#include"BST.h"
#include"BST.cpp"
using namespace wangzhe;
int main(int argc, char** argv)
{
for(int i=1;i<=50;i++) cout<<'*';
cout<<"\n实验四:特殊二叉树的应用(基于BST实现的静态查找表)\n";
for(int i=1;i<=50;i++) cout<<'*';
cout<<endl;
BST<int> Tree;
BSTNode<int>* rt=NULL;
Tree.setRoot(rt);
cout<<"请输入BST中的结点个数:\n";
int n,m;cin>>n;
cout<<"请依次输入"<<n<<"个结点的值:\n";
for(int i=1;i<=n;i++)//测试insert函数
{
cin>>m;
if(i==1) rt=Tree.insert(rt,m);
else Tree.insert(rt,m);
}
cout<<"这颗BST的中序遍历为:(从小到大排列)\n";
Tree.inorder(rt);//测试二叉树是否构建成功
cout<<"\n请输入要查找值的个数:\n";
cin>>n;
for(int i=1;i<=n;i++)//测试find函数
{
cout<<"第"<<i<<"次查询,请输入要查找的值:\n";
cin>>m;
int ans=Tree.find(rt,m,1);
if(ans==-1)
cout<<"查找失败,元素"<<m<<"不存在\n";
else
cout<<"查找成功,比较次数为:"<<ans<<endl;
}
cout<<"\n请输入要删除的值:\n";
cin>>m;
if(Tree.find(rt,m,1)==-1)
cout<<"该值不存在,操作失败!\n";
else
{
cout<<"\n删除该值前的前序遍历:\n";
Tree.preorder(rt);//测试preorder函数
cout<<"\n删除该值后的前序遍历:\n";
rt=Tree.remove(rt,m);//测试remove函数
Tree.preorder(rt);
cout<<"\n删除该值后的中序遍历:\n";
Tree.inorder(rt);
}
return 0;
}
三、参考文献
[1] 秋叶拓哉,巫泽俊.挑战程序设计竞赛(第二版)[M].北京.人民邮电出版社,2013:77-81.
[2]https://www.cnblogs.com/gaochundong/p/binary_search_tree.html