前段时间,论坛上几个人很热烈地讨论二叉树里做iterator。还有人专为此给一些C++界的名人写信,俨然很专业的样子。
老实说,我当时看了这个论题,感觉有点无聊,为什么?因为二叉树就是二叉树,它的结构就是:左儿子,右儿子,父节点等。
iterator的结构是线性的前驱,后继。
两者虽然不是风马牛不相及,但也应该是互相独立的概念。
要给二叉树做一个iterator不是不能,只要定义一个遍历规则,把二叉树以iterator的方式来访问完全是可能的。
但是,这种可能就象拿stl可以做Windows programming一样,但stl和Windows programming却又是互相独立的。 谁也不需要依赖谁。你要非在STL里加入windows sdk的东西,然后说:因为windows programming很常用,所以为了方便用户,我把HWND加入stl, 就乱套了。
把iterator和二叉树的实现耦合起来考虑,在我看来,是明显的设计问题。无谓地把简单的东西复杂化。虽然可以做,但是写出来的代码重用性和结构上都有毛病。
好了,毛病挑完了。下面该说说我认为正确的做法:
1。二叉树就是二叉树, 老老实实地把二叉树的功能做好。不要考虑iterator.
2。 如果认为需要iterator, 如前序,中序,后序。别急。可以单独做一个基于二叉树的iterator的adapter. 这个adapter独立于任何的二叉树实现。它做的只是把二叉树映射成线性访问的iterator.
这个adapter自己定义一个二叉树的接口。然后只需要把任何满足这个接口的对象映射成iterator就成了。
3. 对一个二叉树的实现,怎么利用这个iterator的adapter呢?
把这个二叉树先映射到这个adapter要求的接口。然后,把adapter往二叉树上一套,iterator就出来了。这个iterator库就象一个通用转换器,往任何的二叉树上一插,就行了。
这种结构的好处是,iterator不依赖于二叉树的实现,二叉树也不依赖于iterator. 一个二叉树可以选用任何合适的adapter实现。而一个adapter也可以用于任何的一个二叉树的实现。
下面是我刚刚调试的一段两百多行的C++ bidirectional iterator adapter的代码。它可以用在任何的二叉树实现上(当然,你得写一个adapter把那个二叉树映射到我的二叉树接口上来,不要告诉我你不知道怎么做)
namespace trit{
/*
自己定义的协议语法,二叉树的接口就是这样:
template<typename NODE_PTR>
protocol Tree{
NODE_PTR getLeft();
NODE_PTR getRight();
NODE_PTR getParent();
}
这个是生成的iterator接口:
template<typename NODE_PTR>
protocol Iterator{
operator bool();
NODE_PTR deref();
Self next();
Self prev();
}
*/
template<typename NODE_PTR>
class Iterator{
protected:
typedef Iterator<NODE_PTR> It;
public:
NODE_PTR deref()const{
return node;
}
operator bool()const{
return node!=NODE_PTR(0);
}
Iterator(NODE_PTR const n):node(n){}
friend bool operator==(const It& a, const It& b){
return a.deref()==b.deref();
}
friend bool operator!=(const It& a, const It& b){
return !(a==b);
}
It& operator=(const It& other){
this->node = other.node;
return *this;
}
It end(){
return NODE_PTR(0);
}
static NODE_PTR getRoot(NODE_PTR node){
NODE_PTR ret(node);
NODE_PTR tmp(ret->getParent());
for(;tmp!=NODE_PTR(0);ret=tmp, tmp=ret->getParent());
return ret;
}
static NODE_PTR getLeftmost(NODE_PTR node){
NODE_PTR ret(node);
NODE_PTR tmp(ret->getLeft());
for(;!isNull(tmp);ret=tmp, tmp=ret->getLeft());
return ret;
}
static NODE_PTR getLeftDeep(NODE_PTR node){
NODE_PTR ret(node);
for(;;){
NODE_PTR tmpl(ret->getLeft());
if(isNull(tmpl)){
NODE_PTR tmpr(ret->getRight());
if(isNull(tmpr)){
return ret;
}
else{
ret = tmpr;
}
}
else{
ret = tmpl;
}
}
}
static bool isNull(NODE_PTR ptr){
return ptr==NODE_PTR(0);
}
private:
NODE_PTR node;
};
template<typename NODE_PTR>
class Preorder;
template<typename NODE_PTR>
class Postorder;
template<typename NODE_PTR>
class Inorder;
template<typename NODE_PTR>
class Preorder /*supports Iterator<NODE_PTR>*/: public Iterator<NODE_PTR>{
typedef Preorder<NODE_PTR> Self;
public:
Self next()const{
return goLeft(deref());
}
Self prev()const{
typedef RevTree<NODE_PTR> Adapter;
Adapter rt(deref());
Postorder<Adapter> it(rt);
return Self(it.next().deref().getAdaptee());
}
Self begin()const{
return Self(getRoot(deref()));
}
private:
static Self ret(NODE_PTR me, NODE_PTR from){
if(isNull(me)){
return Self(NODE_PTR(0));
}
else if(from==me->getLeft()){
return goRight(me);
}
else{
return goParent(me);
}
}
static Self goLeft(NODE_PTR const node){
NODE_PTR const left(node->getLeft());
if(isNull(left)){
return goRight(node);
}
else{
return Self(left);
}
}
static Self goRight(NODE_PTR const node){
NODE_PTR const right(node->getRight());
if(isNull(right)){
return goParent(node);
}
else{
return Self(right);
}
}
static Self goParent(NODE_PTR const node){
return ret(node->getParent(), node);
}
public:
Preorder(NODE_PTR const n):It(n){}
Self& operator=(const It& other){
return (Self&) It::operator=(other);
}
};
template<typename NODE_PTR>
class Inorder: public Iterator<NODE_PTR>{
typedef Inorder<NODE_PTR> Self;
public:
Self next()const{
return goRight(deref());
}
Self prev()const{
typedef RevTree<NODE_PTR> Adapter;
Adapter rt(deref());
Inorder<Adapter> it(rt);
return Self(it.next().deref().getAdaptee());
}
Self begin()const{
return Self(getLeftmost(deref()));
}
private:
static Self ret(NODE_PTR const me, NODE_PTR const from){
if(isNull(me)){
return Self(NODE_PTR(0));
}
else if(me->getLeft()==from){
return Self(me);
}
else{
return goParent(me);
}
}
static Self goRight(NODE_PTR const node){
NODE_PTR const right(node->getRight());
if(isNull(right)){
return goParent(node);
}
else{
return Self(getLeftmost(right));
}
}
static Self goParent(NODE_PTR const node){
return ret(node->getParent(), node);
}
public:
Inorder(NODE_PTR const n):It(n){}
Self& operator=(const It& other){
return (Self&) It::operator=(other);
}
};
template<typename NODE_PTR>
class Postorder: public Iterator<NODE_PTR>{
typedef Postorder<NODE_PTR> Self;
public:
Self next(){
return goParent(deref());
}
Self prev(){
typedef RevTree<NODE_PTR> Adapter;
Adapter rt(deref());
Preorder<Adapter> it(rt);
return Self(it.next().deref().getAdaptee());
}
Self begin(){
return Self(getLeftDeep(deref()));
}
static Self ret(NODE_PTR const me, NODE_PTR const from){
if(isNull(me)){
return Self(NODE_PTR(0));
}
if(me->getLeft()==from){
return goRight(me);
}
else{
return Self(me);
}
}
private:
static Self goRight(NODE_PTR const node){
NODE_PTR const right(node->getRight());
if(isNull(right)){
return Self(node);
}
else{
return Self(getLeftDeep(right));
}
}
static Self goParent(NODE_PTR const node){
return ret(node->getParent(), node);
}
public:
Postorder(NODE_PTR const n):It(n){}
Self& operator=(const It& other){
return (Self&) It::operator=(other);
}
};
template<typename NODE_PTR>
class RevTree/*supports Tree<NODE_PTR>*/{
typedef RevTree<NODE_PTR> Self;
public:
RevTree(NODE_PTR const t):tr(t){}
Self getLeft()const{
return Self(tr->getRight());
}
Self getRight()const{
return Self(tr->getLeft());
}
Self getParent()const{
return Self(tr->getParent());
}
const Self* operator->()const {return this;}
bool operator == (const Self& b)const{
return this->tr==b.tr;
}
bool operator== (const NODE_PTR b){
return this->tr==b;
}
friend bool operator== (const NODE_PTR a, const Self& b){
return a==b.tr;
}
Self& operator=(const Self& other){
tr = other.tr;
return *this;
}
NODE_PTR getAdaptee()const{return tr;}
private:
NODE_PTR tr;
};
}
下面是测试代码,因为这里的重点不是如何实现二叉树, 它使用了一个非常简易的二叉树。只是为了表示你怎么样给一个任意的二叉树提供iterator服务。
#include <iostream.h>
#include "trit.h"
using namespace trit;
class TreeCons{
public:
TreeCons* getLeft()const{return left;}
TreeCons* getRight()const{return right;}
TreeCons* getParent()const{return parent;}
void setParent(TreeCons* p){this->parent = p;}
const char* get(){return val;}
TreeCons(TreeCons* l, TreeCons* r, const char* v)
:left(l), right(r), parent(0), val(v){}
private:
TreeCons* left;
TreeCons* right;
TreeCons* parent;
const char* val;
};
typedef Preorder<TreeCons*> Pre;
typedef Inorder<TreeCons*> In;
typedef Postorder<TreeCons*> Post;
template<typename IT>
void printIt(IT it){
for(;it; it=it.next()){
cout << it.deref()->get();
}
cout <<endl;
}
template<typename IT>
void printRev(IT it){
for(;it; it=it.prev()){
cout << it.deref()->get();
}
cout <<endl;
}
int main(){
TreeCons* d = new TreeCons(0, 0, "D");
TreeCons* e = new TreeCons(0, 0, "E");
TreeCons* b = new TreeCons(d, e, "B");
d->setParent(b);
e->setParent(b);
TreeCons* f = new TreeCons(0, 0, "F");
TreeCons* c = new TreeCons(0, f, "C");
f->setParent(c);
TreeCons* a = new TreeCons(b, c, "A");
b->setParent(a);
c->setParent(a);
printIt(Pre(a));
printIt(Pre(c).begin());
printIt(In(a));
printIt(In(a).begin());
printIt(Post(a));
printIt(Post(a).begin());
printRev(Post(a));
printRev(In(a));
printRev(Pre(a));
delete a;
delete b;
delete c;
delete d;
delete e;
return 1;
}
也许你会觉得,这个iterator和stl的iterator的接口不大一致。呵呵,这个实现本着最小功能原则,其它的如operator++什么的,自己写个小adapter把接口转换一下应该不难吧?
:〉
另外,我还写了一个Java版本的binary tree -- iterator 的adapter. 利用java的gc功能, 它不需要节点有父指针。