二叉搜索树
二叉搜索树简而言之就是右子树值比根节点大,左子树值都比根节点小
二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势;所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作。
二叉搜索树类继承了二叉树类,因此只需要实现普通二叉树不易实现的查找插入删除操作。
二叉树类代码(GitHub):https://github.com/rebelsisyphus/vscode/blob/main/.vscode/data%20structure/Bintree/tree.h
二叉树类(csdn)https://blog.csdn.net/qq_40602655/article/details/114552635
二叉搜索树类
emplate <class T>
class BinSearchTree:public BinTree<T>{
protected:
BinTreeNode<T> * Insertnode(BinTreeNode<T> *subtree,T &x);
BinTreeNode<T> * deletenode(BinTreeNode<T> *subtree,T &x);
BinTreeNode<T> * Maxnode(BinTreeNode<T> *subtree){
BinTreeNode<T> *temp=subtree;
while(temp->rightChild!=NULL){
temp=temp->rightChild;
}
return temp;
}
BinTreeNode<T> * Minnode(BinTreeNode<T> *subtree){
BinTreeNode<T> *temp=subtree;
while(temp->leftChild!=NULL){
temp=temp->leftChild;
}
return temp;
}
public:
/*BinSearchTree(){this->root=NULL;};
BinSearchTree(T x){
this->root=new BinTreeNode<T>(x);
}
~BinSearchTree(){this->deleteall(this->root);}*/
void buildBStree();
BinTreeNode<T> * Findtreenode(const T &X);
void Insertnode(T &x){
this->root=Insertnode(this->root,x);}
void deletenode(T &x){
this->root=deletenode(this->root,x);}
BinTreeNode<T> * Maxnode(){
return Maxnode(this->root);}
BinTreeNode<T> * Minnode(){
return Minnode(this->root);}
};
查找
//在二叉搜索树中查找一个值。返回其所在的树节点
template <class T>
BinTreeNode<T> * BinSearchTree<T>::Findtreenode(const T &x){
BinTreeNode<T> *temp=this->getroot(); //调用基类函数要使用this指针
if(temp==NULL) return NULL;
while(temp!=NULL){
if(x>temp->data) temp=temp->rightChild;
else if(x<temp->data) temp=temp->leftChild;
else return temp;
}
}
插入
使用递归实现,因为形参是指针的值传递,因此需要把函数返回值改成BinTreeNode *指针类型,每次递归修改一次
也可以改为bool Insertnode(BinTreeNode *&subtree,T &x),使用引用传递,则不需要下面的值传递
不使用这两种方法,对二叉树起不到修改作用,测试时发现了问题,就改成这样了,懒得改成引用传递了
//在二叉搜索树中插入一个值,返回插入正确与否
template<class T>
BinTreeNode<T> * BinSearchTree<T>::Insertnode(BinTreeNode<T> *subtree,T &x){
//可以改为 bool Insertnode(BinTreeNode<T> *&subtree,T &x),使用引用传递,则不需要下面的值传递
if(!subtree){
subtree=new BinTreeNode<T>(x);
}
else{
if(x>subtree->data) subtree->rightChild=Insertnode(subtree->rightChild,x); //因为函数形参是树节点指针的值传递,因此需要赋值操作
else if(x<subtree->data) subtree->leftChild=Insertnode(subtree->leftChild,x);
}
return subtree;
}
删除
删除操作的关键在于如何处理删除节点的左右子树,有左右子树需要拿一个节点**(左子树最大或者右子树最小)**替换它,以符合二叉搜索树的结构,两个以下的子树,直接接在它的父节点上即可
//在二叉搜索树中删除一个元素,返回删除正确与否
template<class T>
BinTreeNode<T> * BinSearchTree<T>::deletenode(BinTreeNode<T> *subtree,T &x){
if(!subtree){
cout<<"can't find deletenode"<<endl;} //没找到
else{
if(x>subtree->data) subtree->rightChild=deletenode(subtree->rightChild,x); //左子树递归删除
else if(x<subtree->data) subtree->leftChild=deletenode(subtree->leftChild,x);
else{
//找到删除的树节点
BinTreeNode<T> *temp;
if(subtree->leftChild && subtree->rightChild){
//若删除节点有左右子树
temp=Minnode(subtree->rightChild);
subtree->data=temp->data; //找到右子树中的最小值,递归删除这个节点
subtree->rightChild=deletenode(subtree->rightChild,temp->data);
}
else{
temp=subtree; //删除该节点
if(!subtree->leftChild) subtree=subtree->rightChild;
else subtree=subtree->leftChild;
delete temp;
}
}
}
return subtree;
}
建树
重复使用插入操作,也可以按照插入函数写一个循环,差不多的
template<class T>
void BinSearchTree<T>::buildBStree(){
cout<<"please enter the element of bintree:"<<endl;
BinTreeNode<T>* BT=NULL;
T num;
cin>>num;
while(num!='#'){
BT=Insertnode(BT,num);
cin>>num;
}
this->root=BT;
}