算法看起来不错。在下面的 C++ 程序的帮助下,我已经对其进行了多次测试。函数 Tree::remove()
删除一个节点,函数Tree::rebalance_del()
在删除后重新平衡树。在这个程序中,任何节点的删除都被简化为一个子节点/叶节点的删除(通过将节点的内容复制到其直接前任中)。该程序graphviz
用于树可视化并在 Linux 中运行。
#include<iostream>
#include<cstdlib>
#include<deque>
#include<vector>
#include<iterator>
#include<fstream>
#include<algorithm>
#include<set>
using namespace std;
template <typename elemType>
class Tree;
template <typename elemType>
class Node{
friend class Tree<elemType>;
public:
Node(elemType val): _val(val), _lchild(0), _rchild(0){ }
elemType val() const { return _val; }
elemType &val(){ return _val; }
Node *lchild() const { return _lchild;}
Node *&lchild() { return _lchild;}
Node *rchild() const { return _rchild;}
Node *&rchild() { return _rchild;}
void insert(Node *temp);
void graph(string filename);
Node *find(elemType val);
Node *find_parent(elemType val);
private:
elemType _val;
Node *_lchild;
Node *_rchild;
};
template <typename elemType>
class Tree{
public:
Tree(): _root(0){}
Tree(elemType *start, elemType *end);
void insert(elemType val);
int height(Node<elemType> *node);
int balance_factor(Node<elemType> *node);
bool rotate(Node<elemType> *parent, Node<elemType> *child);
bool rotate_root();
Node<elemType> *root(){ return _root;}
void graph(string filename);
Node<elemType> * find(elemType val);
Node<elemType> * find_parent(elemType val);
Node<elemType> * find_predsor(Node<elemType> *node);
void remove(elemType val);
void rebalance_del(Node<elemType> *node);
void rotate_right(Node<elemType> *parent, Node<elemType> *node);
void rotate_left(Node<elemType> *parent, Node<elemType> *node);
private:
Node<elemType> *_root;
};
template <typename elemType>
void Node<elemType>::insert(Node *temp)
{
if (_val > temp->val() )
{
if (_lchild)
_lchild->insert(temp);
else
{
_lchild = temp;
}
}
else
{
if (_rchild)
_rchild->insert(temp);
else
{
_rchild = temp;
}
}
}
template <typename elemType>
void Node<elemType>::graph(string filename)
{
ofstream out_file(filename.c_str(),ios_base::app);
if (_lchild)
{
out_file << _val << "->" << _lchild->val() << ";" << endl;
_lchild->graph(filename);
}
if (_rchild)
{
out_file << _val << "->" << _rchild->val() << ";" << endl;
_rchild->graph(filename);
}
}
template <typename elemType>
Node<elemType> *Node<elemType>::find(elemType val)
{
if (_val == val)
return this;
else if (_val > val)
{
if (_lchild)
return _lchild->find(val);
}
else
{
if (_rchild)
return _rchild->find(val);
}
return 0;
}
template <typename elemType>
Node<elemType> *Node<elemType>::find_parent(elemType val)
{
if ( (_lchild && _lchild->val() == val) || (_rchild && _rchild->val() == val) )
return this;
else if (_val > val)
{
if (_lchild)
return _lchild->find_parent(val);
}
else
{
if (_rchild)
return _rchild->find_parent(val);
}
return 0;
}
template <typename elemType>
Tree<elemType>::Tree(elemType *start, elemType *end): _root(0)
{
while(start != end)
{
insert(*start);
++start;
}
}
template <typename elemType>
void Tree<elemType>::insert(elemType val)
{
Node<elemType> *temp = new Node<elemType>(val);
if (!_root)
{
_root = temp;
return;
}
else
_root->insert(temp);
Node<elemType> *child = find_parent(val);
while (child != _root)
{
Node<elemType> *parent = find_parent(child->val());
rotate(parent, child);
child = parent;
}
rotate_root();
}
template <typename elemType>
int Tree<elemType>::height(Node<elemType> *node)
{
if (!node)
return 0;
return max( height(node->lchild()), height(node->rchild()) ) + 1;
}
template <typename elemType>
int Tree<elemType>::balance_factor(Node<elemType> *node)
{
if (!node)
return 0;
return height( node->rchild() ) - height( node->lchild() );
}
template <typename elemType>
bool Tree<elemType>::rotate(Node<elemType> *parent, Node<elemType> *child)
{
if (!parent || !child)
return false;
bool to_right;
int bf = balance_factor(child);
if (bf < -1 )
to_right = true;
else if (bf > 1 )
to_right = false;
else
return false;
if(to_right)
{
Node<elemType> *gchild = child->lchild();
if ( balance_factor (gchild) > 0 )
rotate_left(child,gchild);
rotate_right(parent,child);
}
else
{
Node<elemType> *gchild = child->rchild();
if ( balance_factor (gchild) < 0 )
rotate_right(child,gchild);
rotate_left(parent,child);
}
}
template <typename elemType>
bool Tree<elemType>::rotate_root()
{
if (!_root)
return false;
bool to_right;
int bf = balance_factor(_root);
if (bf < -1 )
to_right = true;
else if ( bf > 1 )
to_right = false;
else
return false;
if(to_right)
rotate_right(0,_root);
else
rotate_left(0,_root);
return true;
}
template <typename elemType>
void Tree<elemType>::graph(string filename)
{
ofstream out_file(filename.c_str(),ios_base::out);
out_file << "digraph G{\n graph [ordering=\"out\"];" << endl;
out_file.close();
if (!_root)
return;
_root->graph(filename);
out_file.open(filename.c_str(),ios_base::app);
out_file << "}";
}
template <typename elemType>
Node<elemType> * Tree<elemType>::find(elemType val)
{
if (!_root)
return 0;
return _root->find(val);
}
template <typename elemType>
Node<elemType> * Tree<elemType>::find_parent(elemType val)
{
if (!_root)
return 0;
return _root->find_parent(val);
}
template <typename elemType>
Node<elemType> *Tree<elemType>::find_predsor(Node<elemType> *node)
{
if (!node || !node->lchild())
return 0;
Node<elemType> *temp = node->lchild();
while(temp && temp->rchild())
temp = temp->rchild();
return temp;
}
template <typename elemType>
void Tree<elemType>::remove(elemType val)
{
if (!_root)
return;
Node<elemType> *to_remove;
if ( ! (to_remove = find(val)) )
{
cout << val << " is not present" << endl;
return;
}
Node<elemType> *node = find_parent(val);
Node<elemType> *predsor = find_predsor(to_remove);
if ( to_remove->lchild() && to_remove->rchild() )
{
node = find_parent(predsor->val());
elemType temp = to_remove->val();
to_remove->val() = predsor->val();
predsor->val() = temp;
to_remove = predsor;
}
if ( node->rchild() == to_remove )
if (to_remove->lchild())
node->rchild() = to_remove->lchild();
else
node->rchild() = 0;
else
if (to_remove->lchild())
node->lchild() = to_remove->lchild();
else
node->lchild() = 0;
delete to_remove;
cout << "Node " << val << " was removed" << endl;
rebalance_del(node);
}
template <typename elemType>
void Tree<elemType>::rebalance_del(Node<elemType> *node)
{
while (node)
{
Node<elemType> *parent = find_parent(node->val());
int bfp = balance_factor(node);
if (bfp > 1)
{
int bfq = balance_factor(node->rchild());
if (bfq > -1)
rotate_left(parent,node);
else
{
rotate_right(node,node->rchild());
rotate_left(parent,node);
}
}
else if (bfp < -1)
{
int bfq = balance_factor(node->lchild());
if (bfq < 1)
rotate_right(parent,node);
else
{
rotate_left(node,node->lchild());
rotate_right(parent,node);
}
}
node = parent;
}
}
template <typename elemType>
void Tree<elemType>::rotate_right(Node<elemType> *parent, Node<elemType> *node)
{
if (!node)
return;
Node<elemType> *temp = 0;
if( node->_lchild)
{
temp = node->_lchild->_rchild;
node->_lchild->_rchild = node;
}
node = node->_lchild;
if (node && node->_rchild)
{
node->_rchild->_lchild = temp;
}
if (parent)
{
if (node && parent->_rchild == node->_rchild)
parent->_rchild = node;
else if (node && parent->_lchild == node->_rchild)
parent->_lchild = node;
else;
}
else
_root = node;
}
template <typename elemType>
void Tree<elemType>::rotate_left(Node<elemType> *parent, Node<elemType> *node)
{
if (!node)
return;
Node<elemType> *temp = 0;
if( node->_rchild)
{
temp = node->_rchild->_lchild;
node->_rchild->_lchild = node;
}
node = node->_rchild;
if (node && node->_lchild)
{
node->_lchild->_rchild = temp;
}
if (parent)
{
if (node && parent->_lchild == node->_lchild)
parent->_lchild = node;
else if (node && parent->_rchild == node->_lchild)
parent->_rchild = node;
else;
}
else
_root = node;
}
int main(int argc,char *argv[])
{
typedef int elemType;
set<elemType> elems;
srand(time(NULL));
Tree<elemType> tree;
//tree generation
ofstream out_file("tree.dat");
for (int ix = 0; ix < 10000; ++ix)
{
elemType val = rand() % 100;
if (elems.count(val))
continue;
tree.insert( val );
out_file << val << ' ';
elems.insert(val);
}
//print tree to file
tree.graph("tree_before.dot");
system("dot -Tpng tree_before.dot > tree_before.png");
//delete node with to_del key
int to_del = 33;
tree.remove(to_del);
//print rebalanced tree without node to_del
tree.graph("tree_after.dot");
system("dot -Tpng tree_after.dot > tree_after.png");
}