[   ^ to index...   |   <-- previous   |   next -->   ]

Generalizing traversal

Writing traversals all the time is irritating. We would like to write traversal code once, and reuse it for many purposes. How can we do so? Here's one way (iterators are another):

// VISITOR INTERFACE class Visitor { public: virtual void visit(TreeNode* node) = 0; }; // TREE INTERFACE class BinaryTree { public: // ... as before, then: void visit_inorder(Visitor* v); void visit_preorder(Visitor* v); void visit_postorder(Visitor* v); }; // ONE TRAVERSAL IMPLEMENTATION void BinaryTree::visit_inorder(Visitor* v) { inorder_helper(v, root); } void inorder_helper(Visitor* v, TreeNode* node) { if (node != NULL) { inorder_helper(node->left); v->visit(node); inorder_helper(node->right); } } // SAMPLE VISITOR CLASSES class PrintVisitor : public Visitor { public: virtual void visit(TreeNode* node) { cout << node->value << endl; } }; class CumulativeSumVisitor : public Visitor { private: int sum; public: CumulativeSumVisitor() : sum(0) {} virtual void visit(TreeNode* node) sum += node->value; node->value = sum; } }; // SAMPLE CLIENT CODE void foo() { BinaryTree b; b.insert(22); b.insert(5); b.insert(12); b.insert(19); PrintVisitor p; b.visit_inorder(&p); // Prints items inorder b.visit_preorder(&p); // Prints items preorder CumulativeSumVisitor c; b.visit_inorder(&c); // Stores cumulative inorder sums }

We can use templates to eliminate the virtual function call overhead. I leave that as an exercise to the reader.


Last modified: Tue Aug 15 13:51:04 PDT 2000