_TEMPLATES IN C++_ by Nicholas Wilt [LISTING ONE] // select.h -- Template-based C++ implementation of the randomized // selection algorithm from _Introduction to Algorithms_ by Cormen, // Leiserson and Rivest (pg. 187). Copyright (C) 1992 by Nicholas Wilt. // All rights reserved. template T Select(T *base, const int n, int inx) { int left = 0; int right = n; // This while loop terminates when base[left..right] // defines a 1-element array. while (right != left + 1) { // Partition about the q'th element of the array int q = left + rand() % (right - left); T t = base[q]; base[q] = base[left]; base[left] = t; // Partition about base[left]; all elements less than // base[left] get swapped into the left-hand side of // the array. int i = left - 1; int j = right; while (j >= i) { while (j > 0 && t < base[--j]); while (i < (right-1) && base[++i] < t); if (i < j) { T t = base[i]; base[i] = base[j]; base[j] = t; } } // Now focus attention on the partition containing // the order statistic we're interested in. if (inx <= j - left) // Throw away the right-hand partition; we know it // doesn't contain the i'th order statistic. right = j + 1; else { // Throw away the left-hand partition; we know it // doesn't contain the i'th order statistic. // Now we're looking for the inx - j - left + 1'th // order statistic of the right-hand partition. inx -= j - left + 1; left = j + 1; } } // base[left] is the element we want, return it. return base[left]; } [LISTING TWO] // select.cpp -- Demonstrates the use of the Select function template on // arrays of integers and Point2D's. It generates a random of array of // integers, then enumerates the order statistics from 0..n-1. This will // print out the members of the array in sorted order. This isn't a // suggestion for how to use Select (obviously it's more efficient to sort // the array if you want to print out the members in sorted order!) but it's // good to enumerate them all to verify that algorithm is working properly. // The other class the program deals with is a used-defined Point2D class. // This is a two-dimensional point defined by two floating-point numbers. // The ordering chosen, defined by the operator< for the class, is a // standard topological ordering from computational geometry. // Copyright (C) 1992 by Nicholas Wilt. All rights reserved. #include #include #include #include "select.h" // Just for fun, here's a signum template function. Returns -1 if a < b; 1 if // b < a; 0 if they're equal. I've ensured only operator< is used for // comparisons, so operator> isn't defined for a user-defined class. template int Signum(T a, T b) { if (a < b) return -1; else if (b < a) return 1; else return 0; } class Point2D { double x, y; public: Point2D() { } Point2D(double X, double Y): x(X), y(Y) { } // operator< makes our points sorted in topological order: increasing order // in x, and increasing order in y if there is a tie in x. friend int operator<(const Point2D& x, const Point2D& y) { int ret = Signum(x.x, y.x); return (ret) ? ret < 0 : Signum(x.y, y.y) < 0; } friend ostream& operator<< (ostream& a, Point2D& b) { a << "(" << b.x << ", " << b.y << ")"; return a; } }; // Number of elements to allocate in the test arrays const int NumInts = 10; const int NumPts = 5; int main() { int *x = new int[NumInts]; int i; for (i = 0; i < NumInts; i++) { x[i] = rand() % 100; cout << x[i] << ' '; } cout << '\n'; for (i = 0; i < NumInts; i++) { cout << Select(x, NumInts, i) << ' '; } cout << '\n'; delete x; Point2D *y = new Point2D[NumPts]; cout << setprecision(2); for (i = 0; i < NumPts; i++) { y[i] = Point2D( (double) rand() * 10.0 / RAND_MAX, (double) rand() * 10.0 / RAND_MAX); cout << y[i] << ' '; } cout << '\n'; for (i = 0; i < NumPts; i++) { cout << Select(y, NumPts, i) << ' '; } cout << '\n'; return 0; } [LISTING THREE] // bintree.h -- Header file for simple binary tree class template. // Copyright (C) 1992 by Nicholas Wilt. All rights reserved. // BinaryNode is a helper class template for the BinaryTree class template. It // should be needed only rarely by the end user of the BinaryTree class, if // ever. BinaryTree is BinaryNode's friend. The only other classes that // can access BinaryNode's data are classes for which it is a base class. template class BinaryNode { protected: T x; BinaryNode *left, *right; public: BinaryNode(const T& X): x(X) { left = right = 0; } BinaryNode(const T& X, BinaryNode *l, BinaryNode *r): x(X) { left = l; right = r; } friend class BinaryTree; } // BinaryTree manipulates binary trees described by pointers to BinaryNode. template class BinaryTree { protected: // Pointer to the root node of the binary tree. BinaryNode *root; // Various functions to manipulate collections of binary // tree nodes. These are the functions that do the real work. static BinaryNode *InsertNode(BinaryNode *r, T x); static BinaryNode *DupNode(BinaryNode *r); static void PostOrderDeletion(BinaryNode *r); static T *QueryNode(BinaryNode *r, const T& x); static void PreOrderNode(BinaryNode *r, void (*f)(T *)); static void InOrderNode(BinaryNode *r, void (*f)(T *)); static void PostOrderNode(BinaryNode *r, void (*f)(T *)); public: // Constructors and assignment operator BinaryTree() { root = 0; } // Copy constructor duplicates all the nodes in the tree. BinaryTree(BinaryTree& x) { root = DupNode(x.root); } // Assignment operator deletes nodes already there, then // copies the ones in the tree to be copied. BinaryTree& operator=(const BinaryTree& x) { PostOrderDeletion(root); root = DupNode(x.root); return *this; } // Destructor frees all the nodes in the binary tree. ~BinaryTree() { PostOrderDeletion(root); } // Inserts a node containing x into the binary tree. void Insert(const T& x) { root = InsertNode(root, x); } // Returns a pointer to node equal to x, if in tree. // If none found Query returns 0. T *Query(const T& x) { return QueryNode(root, x); } // Various traversal functions perform the traversal // in the order given and call f with a pointer to the // node contents when visiting. void PreOrder(void (*f)(T *)) { PreOrderNode(root, f); } void InOrder(void (*f)(T *)) { InOrderNode(root, f); } void PostOrder(void (*f)(T *)) { PostOrderNode(root, f); } }; // The following function declarations give examples of how to // write function templates for member functions. // Deletes the tree pointed to by r. template void BinaryTree::PostOrderDeletion(BinaryNode *r) { if (r) { PostOrderDeletion(r->left); PostOrderDeletion(r->right); delete r; } } // Inserts a node with key x into the binary tree with the // root given, and returns the new root. template BinaryNode * BinaryTree::InsertNode(BinaryNode *r, T x) { if (r) { if (x < r->x) r->left = InsertNode(r->left, x); else r->right = InsertNode(r->right, x); } else r = new BinaryNode(x); return r; } // Duplicates the binary tree given and returns pointer to the new root. template BinaryNode * BinaryTree::DupNode(BinaryNode *r) { if (r) return new BinaryNode(r->x, DupNode(r->left), DupNode(r->right)); else return 0; } // Returns pointer to key given, if found in binary tree. Otherwise returns 0. template T * BinaryTree::QueryNode(BinaryNode *r, const T& x) { if (r) { if (x == r->x) return &r->x; if (x < r->x) return QueryNode(r->left, x); else return QueryNode(r->right, x); } else return 0; } // Traversal functions. These three functions traverse the tree and call the // pointer to function on the node contents when it's time to visit the node. template void BinaryTree::PreOrderNode(BinaryNode *r, void (*f)(T *)) { if (r) { (*f)(&r->x); PreOrderNode(r->left, f); PreOrderNode(r->right, f); } } template void BinaryTree::InOrderNode(BinaryNode *r, void (*f)(T *)) { if (r) { InOrderNode(r->left, f); (*f)(&r->x); InOrderNode(r->right, f); } } template void BinaryTree::PostOrderNode(BinaryNode *r, void (*f)(T *)) { if (r) { PostOrderNode(r->left, f); PostOrderNode(r->right, f); (*f)(&r->x); } } [LISTING FOUR] // bintree.cpp -- Demonstration program for BinaryTree class template. Inserts // 10 random numbers into a BinaryTree, prints them out and then prints // out the pre-, in- and post-order traversals of the resulting binary tree. // Copyright (C) 1992 by Nicholas Wilt. All rights reserved. #include #include #include #include "bintree.h" // Passed to BinaryTree traversal functions. This gets called with a // pointer to the node contents (int in this case, since it's a // BinaryTree) whenever it's time to visit a node in the tree. void PrintInt(int *x) { cout << *x << ' '; } int main() { int i; BinaryTree tree; cout << "Insertion:\t"; for (i = 0; i < 10; i++) { int insertme = rand() % 100; tree.Insert(insertme); cout << insertme << ' '; } cout << '\n'; cout << "Pre-order:\t"; tree.PreOrder(PrintInt); cout << '\n'; cout << "In-order:\t"; tree.InOrder(PrintInt); cout << '\n'; cout << "Post-order:\t"; tree.PostOrder(PrintInt); cout << '\n'; return 0; } Example 1: Declaring a function template template