//建立集合 templatestruct SET { KEY key; OTHER other; }; //建立动态查找表的类 template class dynamicSearchTable { public: virtual SET *find(const KEY&x)const=0; virtual void insert(const SET &x)=0; virtual void remove(const KEY&x)=0; virtual ~dynamicSearchTable(){}; }; template class BinarySearchTree:public dynamicSearchTable { private: struct binaryNode { SET data; binaryNode*left; binaryNode*right; binaryNode(const SET &data1,binaryNode*left1=NULL,binaryNode*right1=NULL):data(data1),left(left1),right(right1){} ~binaryNode(){} }; binaryNode*root; public: BinarySearchTree(){root=NULL;}; ~BinarySearchTree(){makeEmpty(root);}; SET *find(const KEY&x)const{find(x,root);};//const在结尾表示这个函数不改变这个类 void insert(const SET &x){insert(x,root);}; void remove(const KEY&x){remove(x,root);}; private: SET *find(const KEY&x,binaryNode*t)const; void insert(const SET &x,binaryNode*&t); void remove(const KEY&x,binaryNode*&t); void makeEmpty(const binaryNode*&t); };
注意区分引用&与取地址*
2 二叉查找树功能实现 2.1 find函数的实现 2.1.1 递归方法template2.1.2 非递归方法SET * BinarySearchTree :://注意所属于类后如果有模板,也要带上 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 *,但t指向的是一个SET结构体 //因此要强制类型转换,如return (SET *)t else { if(t->data left); else return find(x,t->right); } }
templateSET * BinarySearchTree :: 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 left; else p=p->right; } return NULL; }
注意非递归结尾没有找到时中止标志,到叶子会自动退出,要自己输入NULL,递归在判断结点是否为空时,就已经可以输出NULL表示结束没有找到了
2.2 insert函数大体理论是任何被插入的结点最后一定可以成为叶子结点
从上到下比较
templatevoid BinarySearchTree ::insert(const SET &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构建可知,左子树的最大值小于右子树的根结点值
右子树的最小值大于左子树的根结点值
void BinarySearchTree::remove(const KEY&x,binaryNode*&t) { //先进行查找 if(t==NULL) return; if(t->data.key 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平衡二叉树,改变二叉树结构,避免退化成单链表情况



