Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on May 25th, 2012  |  syntax: None  |  size: 4.94 KB  |  hits: 12  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. /******************************************************************************
  2.  *
  3.  * This module implements a function to create an SVG drawing of your Red-Black
  4.  * tree. It should be relatively easily-integrated in your own code.
  5.  *
  6.  * Data structures (themselves are pointers to structs):
  7.  * 1. rb_tree contains (at least) a pointer to the `root' of your tree, and a
  8.  * pointer to a `nil' element.
  9.  * 2. rb_node contains (at least) a pointer to its left child, `lchild', a
  10.  * pointer to its right child, `rchild', a character `color' which is either
  11.  * b or r, and an int `key'.
  12.  *
  13.  * You should probably have some data structures which are relatively similar,
  14.  * and can easily substitute your own. If you're using C++, it should be easy to
  15.  * integrate, as well: just change all the static methods to private member
  16.  * methods, and twiddle all the arguments around to your calling conventions.
  17.  *
  18.  * To call the method, you just call `RBdraw(your_tree, a_file_name)'. If your
  19.  * tree has no nodes in it, the method just returns, and if it cannot open the
  20.  * specified file, it prints an error method and returns.
  21.  *
  22.  * The drawing looks best when the keys have between 1 and 3 digits, and if
  23.  * there's too many nodes, it'll look pretty squished (in order to not be like
  24.  * 100k pixels wide).
  25.  *
  26.  *
  27.  *
  28.  * -- Louis Wilson, Nov 2011
  29.  *
  30.  ******************************************************************************/
  31.  
  32.  
  33.  
  34.  
  35.  
  36.  
  37. #include "RB_SVG.h"
  38. #include "RBtree.h
  39. /* Draws a subtree rooted at a node n */
  40. static void rb_draw_subtree(FILE *fp, rb_tree tree, rb_node n, double x, double y,
  41.                 int h, int rowpos, double factor);
  42. /* Calculates x position of circle exp rows from the top, at position rowpos in
  43.  * its row. factor corrects for an image which would be greater than MAXWIDTH. */
  44. static double calcpos(int exp, int rowpos, double factor);
  45. /* Computes height of the tree rooted at node n. */
  46. static int rb_height(rb_tree tree, rb_node n);
  47.  
  48.  
  49.  
  50.  
  51. /* Draws an SVG picture of the tree in the specified file. */
  52. void RBdraw(rb_tree tree, char *fname) {
  53.         FILE *fp; /* file to print to */
  54.         int height = rb_height(tree, tree->root); /* height of the tree */
  55.         int width; /* width of the image */
  56.         int adjwidth; /* adjusted width of the image in px */
  57.         double factor; /* adjust factor for the node positions based on width and adjwidth */
  58.         if (height == 0) return;
  59.         if ((fp = fopen(fname, "w")) == NULL) {
  60.                 fprintf(stderr, "Error: couldn't open %s for writing.\n", fname);
  61.                 return;
  62.         }
  63.         /* Calculate width of drawing, and distance factor for nodes. */
  64.         width = (1<<(height-1)) * (2*RADIUS + PADDING) - PADDING + 2*IMGBORDER;
  65.         adjwidth = (width > MAXWIDTH) ? MAXWIDTH : width;
  66.         factor = (height == 1) ? 1.0 : (adjwidth-2*(RADIUS+IMGBORDER)) / (width-2*(RADIUS+IMGBORDER));
  67.         /* Print out the SVG header */
  68.         fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
  69.                 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"
  70.                 "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"%dpx\" height=\"%dpx\" "
  71.                 "style=\"background-color:white\">\n",
  72.                 adjwidth, (int)(height * (2*RADIUS + PADDING) - PADDING + 2*IMGBORDER));
  73.         /* Draw the tree */
  74.         rb_draw_subtree(fp, tree, tree->root, calcpos(height-1, 0, factor), RADIUS+IMGBORDER, height-1, 0, factor);
  75.         /* SVG footer */
  76.         fputs("</svg>\n", fp);
  77.         fclose(fp);
  78. }
  79. static void rb_draw_subtree(FILE *fp, rb_tree tree, rb_node n, double x, double y,
  80.                 int h, int rowpos, double factor) {
  81.         char *col = (n->color == 'b') ? "black" : "red";
  82.         /* pixel y position for next row */
  83.         double ny = y + 2*RADIUS + PADDING;
  84.  
  85.         /* Draw left subtree */
  86.         if (n->lchild != tree->nil) {
  87.                 /* pixel x position of left child */
  88.                 double nx = calcpos(h-1, 2*rowpos, factor);
  89.                 fprintf(fp, "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" "
  90.                         "style=\"stroke:black;stroke-width:1\"/>\n",
  91.                         x, y, nx, ny);
  92.                 rb_draw_subtree(fp, tree, n->lchild, nx, ny, h-1, 2*rowpos, factor);
  93.         }
  94.         /* Draw right subtree */
  95.         if (n->rchild != tree->nil) {
  96.                 /* pixel x position of right child */
  97.                 double nx = calcpos(h-1, 2*rowpos+1, factor);
  98.                 fprintf(fp, "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" "
  99.                         "style=\"stroke:black;stroke-width:1\"/>\n",
  100.                         x, y, nx, ny);
  101.                 rb_draw_subtree(fp, tree, n->rchild, nx, ny, h-1, 2*rowpos+1, factor);
  102.         }
  103.         /* Draw the node itself */
  104.         fprintf(fp, "<circle cx=\"%f\" cy=\"%f\" r=\"%f\" stroke=\"black\" "
  105.                 "stroke-width=\"1\" fill=\"%s\"/>\n", x, y, RADIUS, col);
  106.         /* And write the node key */
  107.         fprintf(fp, "<text x=\"%f\" y=\"%f\" fill=\"white\" text-anchor=\"middle\" "
  108.                 "dy=\"0.5ex\">%d</text>\n", x, y, n->key);
  109. }
  110. static double calcpos(int exp, int rowpos, double factor) {
  111.         /* This equation took quite a bit of diagramming on paper to come up with. */
  112.         return ((1<<exp) * (2*rowpos+1) - 1) * (RADIUS + PADDING/2) * factor + RADIUS + IMGBORDER;
  113. }
  114. static int rb_height(rb_tree tree, rb_node n) {
  115.         int l, r;
  116.         if (n == tree->nil) return 0;
  117.         l = rb_height(tree, n->lchild);
  118.         r = rb_height(tree, n->rchild);
  119.         return 1 + ((l > r) ? l : r);
  120. }