实现一个简单的二叉查找树,支持常规操作。
代码如下:
#ifndef _BINARYSEARCHTREE_
#define _BINARYSEARCHTREE_
#include <iostream>
#include <stdexcept>
using namespace std;
template <typename T>
class BinarySearchTree
{
private:
struct BinarySearchTreeNode
{
T key;
BinarySearchTreeNode* left;
BinarySearchTreeNode* right;
BinarySearchTreeNode(): left(NULL),right(NULL) {}
BinarySearchTreeNode(const T& v, BinarySearchTreeNode* l,BinarySearchTreeNode* r): key(v),left(l),right(r) {}
};
public:
BinarySearchTree(): root(NULL) {}
~BinarySearchTree() { Clear(); }
BinarySearchTree( const BinarySearchTree& rhs) : root(NULL) { operator=(rhs); }
const BinarySearchTree& operator= ( const BinarySearchTree& rhs)
{
if( this != &rhs )
{
this->Clear();
this->Copy(root,rhs.root);
}
return *this;
}
bool Contains( const T& v) const
{
return Contains(root,v);
}
bool IsEmpty() const { return root == NULL; }
void PrintTree() const { PrintTree(root); }
const T& FindMin() const
{
if(IsEmpty())
throw logic_error("Tree is empty");
BinarySearchTreeNode* targetNode = FindMin(root);
return targetNode->key;
}
const T& FindMax() const
{
if(IsEmpty())
throw logic_error("Tree is empty");
BinarySearchTreeNode* targetNode = FindMax(root);
return targetNode->key;
}
void Clear()
{
Clear(root);
root= NULL;
}
void Insert(const T& v)
{
Insert(root,v);
}
void Remove(const T& v)
{
Remove(root,v);
}
private:
void Clear(BinarySearchTreeNode* subroot);
void Copy(BinarySearchTreeNode* &subroot,BinarySearchTreeNode* source);
void Insert(BinarySearchTreeNode* & subroot,const T& v);
void Remove(BinarySearchTreeNode* & subroot, const T& v);
BinarySearchTreeNode* FindMin(BinarySearchTreeNode* subroot) const
{
if( subroot == NULL )
return NULL;
while( subroot->left != NULL)
subroot = subroot->left;
return subroot;
}
BinarySearchTreeNode* FindMax(BinarySearchTreeNode* subroot) const
{
if( subroot == NULL )
return NULL;
while( subroot->right != NULL )
subroot = subroot->right;
return subroot;
}
void PrintTree(BinarySearchTreeNode* subroot) const;
bool Contains(BinarySearchTreeNode* subroot,const T& v) const;
private:
BinarySearchTreeNode* root;
};
template <typename T>
void BinarySearchTree<T>::Copy(BinarySearchTreeNode* &subroot,BinarySearchTreeNode* source)
{
if(source != NULL)
{
subroot = new BinarySearchTreeNode(source->key,NULL,NULL);
Copy(subroot->left,source->left);
Copy(subroot->right,source->right);
}
}
template <typename T>
void BinarySearchTree<T>::Clear(BinarySearchTreeNode* subroot)
{
if(subroot != NULL )
{
Clear(subroot->left);
Clear(subroot->right);
delete subroot;
}
}
template <typename T>
void BinarySearchTree<T>::PrintTree(BinarySearchTreeNode* subroot) const
{
if( subroot != NULL )
{
PrintTree(subroot->left);
cout << subroot->key << ",";
PrintTree(subroot->right);
}
}
template <typename T>
bool BinarySearchTree<T>::Contains(BinarySearchTreeNode* subroot,const T& v) const
{
if( subroot == NULL )
return false;
else if ( v < subroot->key )
return Contains(subroot->left,v);
else if ( subroot->key < v)
return Contains(subroot->right,v);
else
return true;
}
template <typename T>
void BinarySearchTree<T>::Insert(BinarySearchTreeNode* & subroot,const T& v)
{
if( subroot == NULL )
subroot = new BinarySearchTreeNode(v,NULL,NULL);
else if ( v < subroot->key )
Insert(subroot->left,v);
else if( subroot->key < v)
Insert(subroot->right,v);
else
// Don't handle duplicate key at here
// Because duplicate key will increase the overall tree height obviously
// So it is not a good way to save same keys in one single binary search tree
// we can keep a list to store all values related same key in somewhere else
throw logic_error("Duplicate key");
}
template <typename T>
void BinarySearchTree<T>::Remove(BinarySearchTreeNode* & subroot, const T& v)
{
if( subroot == NULL )
return;
else if( v < subroot->key )
return Remove(subroot->left,v);
else if( subroot->key < v)
return Remove(subroot->right,v);
else if( subroot->left != NULL && subroot->right != NULL )
{
BinarySearchTreeNode* successor = FindMin(subroot->right);
subroot->key = successor->key;
Remove(subroot->right,successor->key);
}
else
{
BinarySearchTreeNode* oldNode = subroot;
if( subroot->left != NULL )
subroot = subroot->left;
else
subroot = subroot->right;
delete oldNode;
}
}
#endif
这里的公共函数,基本都是通过调用内部的私有递归函数来实现的。
注意Insert和Remove方法都是采用的指向节点指针的引用,这样可以达到在递归调用里面直接修改主调函数中的指针值的目的。Insert很直观,找到对应的空节点,然后创建一个新的节点挂接上去。
Remove要麻烦一点,需要区分几种情况,比如要被删除的目标节点 (1)无子节点 (2) 仅有左子结点 (3) 仅有右子结点 (4) 有左右子节点,前三种情况都很好处理,删除该节点,然后把对应的子节点挂接到它的父节点对应的位置。最后一种情况要复杂点,一般的做法是,找到目标节点的后继节点(也就是它的右子树中的最小节点),然后交换目标节点和后继节点的值,最后再删除后继节点,因为这个后继节点肯定是没有左子节点的,所以删除后继节点必然是情况1或者2.
测试代码如下:
void BinarySearchTreeTest1()
{
BinarySearchTree<int> bst;
bst.Insert(10);
bst.Insert(6);
bst.Insert(18);
bst.Insert(13);
bst.Insert(15);
bst.Insert(8);
bst.Insert(3);
bst.PrintTree();
cout << endl;
cout << "Contains 15 is " << bst.Contains(15) << endl;
cout << "Contains 11 is " << bst.Contains(11) << endl;
cout << "Min is " << bst.FindMin() << endl;
cout << "Max is " << bst.FindMax() << endl;
bst.Remove(19);
bst.PrintTree();
cout << endl;
bst.Remove(18);
bst.PrintTree();
cout << endl;
bst.Remove(10);
bst.PrintTree();
cout << endl;
bst.Remove(3);
bst.PrintTree();
cout << endl;
}