1 二叉查找树类的定义
//建立集合
template <class KEY,class OTHER>
struct SET
{
KEY key;
OTHER other;
};
//建立动态查找表的类
template<class KEY,class OTHER>
class dynamicSearchTable
{
public:
virtual SET<OTHER,KEY>*find(const KEY&x)const=0;
virtual void insert(const SET<OTHER,KEY>&x)=0;
virtual void remove(const KEY&x)=0;
virtual ~dynamicSearchTable(){};
};
template<class KEY,class OTHER>
class BinarySearchTree:public dynamicSearchTable<KEY,OTHER>
{
private:
struct binaryNode
{
SET<KEY,OTHER> data;
binaryNode*left;
binaryNode*right;
binaryNode(const SET<KEY,OTHER>&data1,binaryNode*left1=NULL,binaryNode*right1=NULL):data(data1),left(left1),right(right1){}
~binaryNode(){}
};
binaryNode*root;
public:
BinarySearchTree(){root=NULL;};
~BinarySearchTree(){makeEmpty(root);};
SET<KEY,OTHER>*find(const KEY&x)const{find(x,root);};//const在结尾表示这个函数不改变这个类
void insert(const SET<KEY,OTHER>&x){insert(x,root);};
void remove(const KEY&x){remove(x,root);};
private:
SET<KEY,OTHER>*find(const KEY&x,binaryNode*t)const;
void insert(const SET<KEY,OTHER>&x,binaryNode*&t);
void remove(const KEY&x,binaryNode*&t);
void makeEmpty(const binaryNode*&t);
};
注意区分引用&与取地址*
2 二叉查找树功能实现
2.1 find函数的实现
2.1.1 递归方法
template<class KEY,class OTHER>
SET<KEY,OTHER>* BinarySearchTree<KEY,OTHER>:://注意所属于类后如果有模板,也要带上
find(const KEY&x,binaryNode*t)const
{
//无法返回结构体,因此只能返回结构体指针,这样才能通过序号索引到一些对应内容
if(t==NULL) return NULL;
if(t->data==x) return &(t->data);//返回结构体元素的地址,区分t指向节点地址,通过节点地址找到节点,访问节点得到结构体地址
//上一行写return t是不对的,因为t是binaryNode地址
//要返回的是SET<KEY,OTHER>*,但t指向的是一个SET结构体
//因此要强制类型转换,如return (SET<KEY,OTHER>*)t
else
{
if(t->data<x)return find(x,t->left);
else return find(x,t->right);
}
}
2.1.2 非递归方法
template<class KEY,class OTHER>
SET<KEY,OTHER>* BinarySearchTree<KEY,OTHER>::
find(const KEY&x)const
{
//无法返回结构体,因此只能返回结构体指针,这样才能通过序号索引到一些对应内容
if(root==NULL) return NULL;
binaryNode*p=root;
while(p)//二叉树到叶子后面停止
{
if(p->data==x) return &(t->data);//取地址运算符&
if(p->data<x) p=p->left;
else p=p->right;
}
return NULL;
}
注意非递归结尾没有找到时中止标志,到叶子会自动退出,要自己输入NULL,递归在判断结点是否为空时,就已经可以输出NULL表示结束没有找到了
2.2 insert函数
大体理论是任何被插入的结点最后一定可以成为叶子结点
从上到下比较
template<class KEY,class OTHER>
void BinarySearchTree<KEY,OTHER>::insert(const SET<KEY,OTHER>&x,binaryNode*&t)
{
if(t==NULL)
{t=new binaryNode(x);
return;}//为结构体新建一个结点
if(t->data==x.key) return;//已经存在则结束插入,无需调用find
if(x.key>t->data) insert(t->right,x);
else insert(t->left,x);
//注意此处x为结构体,要访问key比大小
}
由insert构建可知,左子树的最大值小于右子树的根结点值
右子树的最小值大于左子树的根结点值
2.3 remove函数
void BinarySearchTree<KEY,OTHER>::remove(const KEY&x,binaryNode*&t)
{
//先进行查找
if(t==NULL) return;
if(t->data.key<x) remove(x,t->left);
else
{
if(t->data.key>x) remove(x,t->right);
else
{
if(t->left&&t->right)
{
binaryNode*tmp=t->left;
while(tmp->right) tmp=tmp->right;//找到左子树中的最大值
t->data=tmp->data;//用左子树最大值替换被删结点
//但这样就很难删掉t,if(tmp->left)tmp=tmp->left;//或者remove(x,tmp->left)
//将替换结点左子树放到替换节点位置
remove(t->data.key,tmp->left);//删除左子树最大值,用下面else删掉,妙!
}
else
{
binaryNode*OldNode=t;//*****
if(t->left) t=t->left;
if(t->right) t=t->right;
delete OldNode;
}
}
}
}
比较巧妙或者易错的有删除操作
*时间复杂度
如果树接近完全二叉树,时间复杂度O(logN)
最差情况是退化为一个单链表,时间复杂度O(n)
由此引入下一章节内容,AVL平衡二叉树,改变二叉树结构,避免退化成单链表情况