4
3/17/2014 April | 2010 | B³ http://t3nsor.wordpress.com/2010/04/ 1/4 Archive for April, 2010 C++: inheritance from a template parameter April 8, 2010 I looked at my life one day and realized that most of what I do in my spare time is CS contest preparation. Then I realized that I will soon become ineligible for most of the CS contests I currently do, since most such contests are for high school students. But ACM-style problem archives, like SPOJ, UVa, SGU, etc., will always be open, as will TopCoder (fingers crossed…). So it made sense for me to start developing a code library. (Yes, you can paste in arbitrary amounts of pre-written code as long as it is your own, the only restriction being — in TopCoder’s case — the Unused Code Rule.) I thought I’d start with the algorithm or data structure I had most often wished for after finding the standard C++ libraries inadequate, and this must surely be an ordered set that supports query by rank. That is, given n, can we determine the n th  smallest element in the set? Or the reverse: can we determine how many elements in the set are smaller than a given element? (Once these two operations are supported, it becomes trivial to make the set’s iterator a random-access one.) When all elements are known in advance, we can sidestep this limitation of std::set by sorting them and using a binary indexed tree instead. (See this SPOJ problem (http://www.spoj.pl/problems/ORDERSET/) for a problem of this type). However, we do not always know them in advance; suppose that that SPOJ problem were online instead, for example. Then, the most reasonable choice might be the red-black tree. (You probably have no idea what this has to do with the title so far, unless you found this page by searching for a solution to the problem this page actually solves, in which case you are probably desperately hoping that the problem this page solves is actually the same as your problem.) So off I went, starting to code the red-black tree. But one day I read the landmark 1983 paper by Daniel Sleator and Robert Tarjan, A Data Structure for Dynamic Trees (http://www.cs.cmu.edu/~sleator/papers/dynamic-trees.pdf). The link/cut tree, as it is now called, is implemented over the splay tree (which, unsurprisingly, was also discovered by Sleator and Tarjan). Nice. That meant I had to code a splay tree too at some point. (Ahh. Are you starting to see where this is heading? The crux of the idea is yet to crystallize, however.)

April _ 2010 _ B3

Embed Size (px)

Citation preview

Page 1: April _ 2010 _ B3

8/12/2019 April _ 2010 _ B3

http://slidepdf.com/reader/full/april-2010-b3 1/4

3/17/2014 April | 2010 | B³

http://t3nsor.wordpress.com/2010/04/ 1/4

Archive for April, 2010

C++: inheritance from a template parameter

April 8, 2010I looked at my life one day and realized that most of what I do in my spare time is CS contest preparation.Then I realized that I will soon become ineligible for most of the CS contests I currently do, since mostsuch contests are for high school students.

But ACM-style problem archives, like SPOJ, UVa, SGU, etc. , will always be open, as will TopCoder(fingers crossed…). So it made sense for me to start developing a code library . (Yes, you can paste inarbitrary amounts of pre-written code as long as it is your own, the only restriction being — in TopCoder’scase — the Unused Code Rule.)

I thought I’d start with the algorithm or data structure I had most often wished for after finding the standardC++ libraries inadequate, and this must surely be an ordered set that supports query by rank. That is, givenn , can we determine the n th smallest element in the set? Or the reverse: can we determine how manyelements in the set are smaller than a given element? (Once these two operations are supported, it becomestrivial to make the set’s iterator a random-access one.)

When all elements are known in advance, we can sidestep this limitation of std::set by sorting themand using a binary indexed tree instead. (See this SPOJ problem

(http://www.spoj.pl/problems/ORDERSET/) for a problem of this type). However, we do not alwaysknow them in advance; suppose that that SPOJ problem were online instead, for example. Then, the mostreasonable choice might be the red-black tree.

(You probably have no idea what this has to do with the title so far, unless you found this page bysearching for a solution to the problem this page actually solves, in which case you are probablydesperately hoping that the problem this page solves is actually the same as your problem.)

So off I went, starting to code the red-black tree. But one day I read the landmark 1983 paper by DanielSleator and Robert Tarjan, A Data Structure for Dynamic Trees(http://www.cs.cmu.edu/~sleator/papers/dynamic-trees.pdf). The link/cut tree, as it is now called, isimplemented over the splay tree (which, unsurprisingly, was also discovered by Sleator and Tarjan). Nice.That meant I had to code a splay tree too at some point. (Ahh. Are you starting to see where this isheading? The crux of the idea is yet to crystallize, however.)

Page 2: April _ 2010 _ B3

8/12/2019 April _ 2010 _ B3

http://slidepdf.com/reader/full/april-2010-b3 2/4

3/17/2014 April | 2010 | B³

http://t3nsor.wordpress.com/2010/04/ 2/4

The red-black tree and the splay tree have much in common. As much as I often hate object-orienteddesign, this was surely the perfect time to use inheritance to my advantage, allowing me to reuse commonBST code between the two?

So I decided to move this common code out of rbtree.h and into bst_utils.h . Then it struck me.I could not think of a solution to my problem, and I was so crestfallen that I abandoned the project for afew months.

Here’s the problem. To write a binary search tree data structure, we first write a struct that contains, atminimum:

template <class Key>struct BST_node{ BST_node* l; BST_node* r; Key key;};

(I have shown a minimalist implementation, as cluttering up this post with constructors, destructors, accessspecifiers, etc. is undesirable.)The node of a red-black tree would then look something like

template <class Key>struct RBTree_node : BST_node{

enum {red,black} rbtree_color;};

Now, both red-black trees and splay trees (not to mention AVL and randomized trees) rely on rotations tokeep themselves balanced. So it makes sense to put the rotation code in BST_node , perhaps as a memberfunction. When rotating at a specific node, we must traverse that node’s pointers to its children. Theproblem is that, when we derive RBTree_node from BST_node , the two child pointers stay asBST_node* and not RBTree_node* .

Hence, suppose we do a left rotation at this . Then we have to set pointer r to r->l . But since r is oftype BST_node , not RBTree_node , when r is dereferenced, the offset added to it to retrieve memberl is the offset of l in BST_node , which is allowed to differ from that in RBTree_node .

Mechanistically, the solution is simple: just cast these pointers to RBTree_node* before dereferencingthem. However, that would force me to rewrite the rotation functions with almost exactly the same code,which really shouldn’t happen — and overriding them would require adding an entry to the virtual methodtable which would bloat each node by the size of a pointer. Clearly, this is not a very satisfying solution.

Luckily C++ provides a way out, and here it is. Add a second template parameter and derive from it, so

now we have

template <class Key,class Hack>struct BST_node : public Hack{

Page 3: April _ 2010 _ B3

8/12/2019 April _ 2010 _ B3

http://slidepdf.com/reader/full/april-2010-b3 3/4

3/17/2014 April | 2010 | B³

http://t3nsor.wordpress.com/2010/04/ 3/4

BST_node* l; BST_node* r; Key key;};

Leave all the common code either as member functions of this template struct or as templated non-memberfunctions. And any node features specific to one type of tree (such as the color field, for red-black trees) go

as members into the struct that’s supplied as the second template argument; by inheritance, these are“imported” as members of the templated BST_node struct. And the beauty of this is that it works outperfectly.

Thus:

struct empty_struct{};struct RBTree_node_aux{ enum {red,black} rbtree_color;};struct AVLTree_node_aux{ int height;};BST_node<int,empty_struct> p; //plain BST nodeBST_node<int,RBTree_node_aux> r; //RB-tree nodeBST_node<int,AVLTree_node_aux> a; //AVL-tree node

and the appropriate types are inserted by template magic into the pertinent functions at compile-time.

(Where is the inheritance of the red-black tree node from the plain BST node now? We could derive it thatway if we wanted, but we wouldn’t inherit anything since the base struct is empty. It would of course stillbe important to do so if we needed polymorphism, but templates have taken care of that for us.)

Now I have to wonder how they did it in C…

Posted in Uncategorized | 1 Comment »

The Kubrick Theme Blog at WordPress.com.Entries (RSS) and Comments (RSS).

Follow

Follow “B³”

Page 4: April _ 2010 _ B3

8/12/2019 April _ 2010 _ B3

http://slidepdf.com/reader/full/april-2010-b3 4/4

3/17/2014 April | 2010 | B³

http://t3nsor.wordpress.com/2010/04/ 4/4

Powered by WordPress.com