Binary Search Tree
二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉查找树。
性质
二叉查找树是一个带根的二叉树,内部每个结点都储存一个键,并且都有两个不同的子树。对于树中的每个结点X,他左子树中的所有项都小于X中的项,右子树中所有项的值都大于X中的项。
如图所示为二叉查找树:
树的实现
二叉查找树一般包含如下insert,delete,findMax,findMin,contain等功能,通常递归地编写这些操作。
结点的构造
一个结点包含一个键以及指向左右子树的指针:
template <typename Object>struct BinaryNode{
Object element;
BinaryNode<Object> *left;
BinaryNode<Object> *right;
BinaryNode(const Object& theElement,BinaryNode<Object> *Left,BinaryNode<Object> *Right):
element(theElement),left(Left),right(Right){}
};
插入操作
递归地进行操作,插入后要符合树的定义,即该结点的值比左子树上所有结点大,比右子树上所有结点小。
如果当前结点为空,直接插入;如果当前结点所含项的值比将要插入的结点大,因为要保证右边的一定大于结点,左边的一定小于结点,则应向当前结点的左子树插入,(如果向右子树插入,会造成右子树中有元素小于当前结点,不符合定义);如果当前结点所含项的值比将要插入的结点小,同理,则应向当前结点的右子树插入。
template <typename Object>void BinarySearchTree<Object>::insert(const Object &obj, BinaryNode<Object> *&t) {
if(t==NULL)t=new BinaryNode<Object>(obj,NULL,NULL);
else if(obj<t->element) insert(obj,t->left);
else insert(obj,t->right);
}
查找操作
从根节点遍历,如果当前结点所含项的值等于被查找元素,则找到;如果小于被查找元素,则继续对其左子树遍历;若大于被查找元素,对其右子树遍历。
template <typename Object>bool BinarySearchTree<Object>::contains(const Object &obj, BinaryNode<Object> *t) {
if(t==NULL)return false;
else if(obj<t->element) return contains(obj,t->left);
else if(t->element<obj) return contains(obj,t->right);
else return true;
}
查找最大、最小操作
由树的性质可知,树上的最小元素一定在左结点,最大的元素一定在右结点。直接递归求解即可
template <typename Object>BinaryNode<Object>* BinarySearchTree<Object>::findMax(BinaryNode<Object> *t) {
if(t==NULL) return NULL;
if(t->right==NULL) return t;
return findMax(t->right);
}
template <typename Object>BinaryNode<Object>* BinarySearchTree<Object>::findMin(BinaryNode<Object> *t){
if(t==NULL) return NULL;
if(t->left==NULL) return t;
return findMin(t->left);
}
删除操作
如果被删除的结点是一片树叶,则直接删除即可。如果该结点有一个儿子,则该结点可以在其父亲节点调整它的链以绕过该节点后被删除。复杂的情况是处理具有两个儿子的结点,我们一般的删除策略是用其右子树的最小结点代替该结点,再递归删除那个结点。
template <typename Object>void BinarySearchTree<Object>::remove(const Object &obj, BinaryNode<Object> *&t) {
if(t==NULL) return;
else if(obj<t->element) remove(obj,t->left);
else if(t->element<obj) remove(obj,t->right);
else if(t->right==NULL||t->left==NULL){
BinaryNode<Object>*tmp=t;
t=(t->left!=NULL)?t->left:t->right;
delete tmp;
}
else{
t->element=findMin(t->right)->element;
remove(t->element,t->right);
}
}
完整代码
template <typename Object>struct BinaryNode{
Object element;
BinaryNode<Object> *left;
BinaryNode<Object> *right;
BinaryNode(const Object& theElement,BinaryNode<Object> *Left,BinaryNode<Object> *Right):
element(theElement),left(Left),right(Right){}
};
template <typename Object>class BinarySearchTree{
private:
BinaryNode<Object> *root;
public:
BinarySearchTree();
BinarySearchTree(const BinarySearchTree<Object>&);
~BinarySearchTree();
const Object& findMin();
const Object& findMax();
bool contains(const Object&);
bool empty()const;
void printTree();
void clear();
void insert(const Object&);
void remove(const Object&);
const BinarySearchTree<Object>&operator=(const BinarySearchTree<Object>&);
private:
void insert(const Object&,BinaryNode<Object>* &);
void remove(const Object&,BinaryNode<Object>* &);
BinaryNode<Object>* findMin(BinaryNode<Object>*);
BinaryNode<Object>* findMax(BinaryNode<Object>*);
bool contains(const Object&,BinaryNode<Object>*);
void clear(BinaryNode<Object>*&);
void printTree(BinaryNode<Object>*);
BinaryNode<Object>*clone(BinaryNode<Object> *t)const;
};
template <typename Object>void BinarySearchTree<Object>::insert(const Object &obj, BinaryNode<Object> *&t) {
if(t==NULL)t=new BinaryNode<Object>(obj,NULL,NULL);
else if(obj<t->element) insert(obj,t->left);
else insert(obj,t->right);
}
template <typename Object>bool BinarySearchTree<Object>::contains(const Object &obj, BinaryNode<Object> *t) {
if(t==NULL)return false;
else if(obj<t->element) return contains(obj,t->left);
else if(t->element<obj) return contains(obj,t->right);
else return true;
}
template <typename Object>BinaryNode<Object>* BinarySearchTree<Object>::findMax(BinaryNode<Object> *t) {
if(t==NULL) return NULL;
if(t->right==NULL) return t;
return findMax(t->right);
}
template <typename Object>BinaryNode<Object>* BinarySearchTree<Object>::findMin(BinaryNode<Object> *t){
if(t==NULL) return NULL;
if(t->left==NULL) return t;
return findMin(t->left);
}
template <typename Object>void BinarySearchTree<Object>::remove(const Object &obj, BinaryNode<Object> *&t) {
if(t==NULL) return;
else if(obj<t->element) remove(obj,t->left);
else if(t->element<obj) remove(obj,t->right);
else if(t->right==NULL||t->left==NULL){
BinaryNode<Object>*tmp=t;
t=(t->left!=NULL)?t->left:t->right;
delete tmp;
}
else{
t->element=findMin(t->right)->element;
remove(t->element,t->right);
}
}
template <typename Object>void BinarySearchTree<Object>::clear(BinaryNode<Object>*&t) {
if(t!=NULL){
clear(t->left);
clear(t->right);
delete t;
}
t=NULL;
}
template <typename Object>BinaryNode<Object>* BinarySearchTree<Object>::clone(BinaryNode<Object> *t) const {
if(t==NULL) return NULL;
return new BinaryNode<Object>(t->element,clone(t->left),clone(t->right));
}
template <typename Object>const BinarySearchTree<Object>& BinarySearchTree<Object>::operator=(
const BinarySearchTree<Object> &t) {
if(this!=&t){
clear();
root=clone(t.root);
}
return *this;
}
template <typename Object>void BinarySearchTree<Object>::printTree(BinaryNode<Object> *t) {
if(t){
printTree(t->left);
std::cout<<t->element<<" ";
printTree(t->right);
}
}
template <typename Object>void BinarySearchTree<Object>::remove(const Object &obj) {
remove(obj,root);
}
template <typename Object>bool BinarySearchTree<Object>::contains(const Object &obj) {
return contains(obj,root);
}
template <typename Object>const Object& BinarySearchTree<Object>::findMax(){
return findMax(root)->element;
}
template <typename Object>const Object& BinarySearchTree<Object>::findMin(){
return findMin(root)->element;
}
template <typename Object>bool BinarySearchTree<Object>::empty() const {
return root==NULL;
}
template <typename Object>void BinarySearchTree<Object>::clear() {
clear(root);
}
template <typename Object>void BinarySearchTree<Object>::insert(const Object &obj) {
insert(obj,root);
}
template <typename Object>BinarySearchTree<Object>::~BinarySearchTree() {
clear();
}
template <typename Object>BinarySearchTree<Object>::BinarySearchTree():root(NULL) {}
template <typename Object>BinarySearchTree<Object>::BinarySearchTree(const BinarySearchTree<Object> &obj):root(NULL) {
root=clone(obj.root);
}
template <typename Object>void BinarySearchTree<Object>::printTree() {
printTree(root);
}