Advertisement
rplantiko

Enumerate Expression Trees

Oct 6th, 2011
906
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.36 KB | None | 0 0
  1. // An algorithm to determine all binary expression trees
  2. // Uses C99 features: compile with -std=c99.
  3.  
  4. #include <stdio.h>
  5. #include <assert.h>
  6. #include <stdbool.h>
  7. #include <time.h>
  8.  
  9. typedef struct node {
  10.   bool isLeaf;
  11.   struct node* left;
  12.   struct node* right;
  13.   } node;
  14.  
  15. typedef void(*visitor)(node*);
  16.  
  17. // A node initially is a leaf  
  18. const node initialNode = { .isLeaf = true, .left=0, .right=0 };
  19.  
  20. // Constants for child's position
  21. typedef enum { LEFT, RIGHT } childPos;
  22.  
  23. void doNode( node* current, int stackSize,
  24.              node* stack[], node* root, visitor f);
  25.  
  26. void addNodeWithTwoLeaves(node* current, int stackSize, node* stack[], node* root, visitor f);
  27. void addNodeWithOneLeaf(childPos side,node* current, int stackSize, node* stack[], node* root, visitor f);
  28. void addNodeWithNoLeaves(node* current, int stackSize, node* stack[], node* root, visitor f);
  29.  
  30.  
  31. void printNode( node*);
  32.  
  33.                        
  34. void getExpressions(int size, visitor f) {
  35.    
  36.   node nodes[2*size+1]; // Allocate the complete tree as an array
  37.   node* stack[size];    // Maximum # of stacked nodes = # of operations
  38.  
  39.   node* current = nodes + 2*size+ 1; // = behind the last element
  40.    
  41.   doNode( current, 0, stack, nodes, f );  
  42.  
  43. }
  44.  
  45.  
  46. void doNode( node* current, int stackSize,
  47.              node* stack[], node* root, visitor f ) {
  48.              
  49.   int currentIndex = current - root;              
  50.              
  51. // Stack too large - it will not be possible to connect all references
  52.   if (stackSize > currentIndex + 1) return;
  53.  
  54.   if (currentIndex > 0) {
  55.    
  56.     current--;
  57.  
  58. // First option: Go on with a node with 2 leaves
  59.     if (currentIndex >= 2) {
  60.       addNodeWithTwoLeaves( current, stackSize, stack, root, f );
  61.       }
  62.  
  63. // If there is (at least) one usable reference node with 1 leaf, 1 ref
  64.     if (currentIndex >= 1 && stackSize >= 1) {
  65.       addNodeWithOneLeaf( LEFT,  current, stackSize, stack, root, f );
  66.       addNodeWithOneLeaf( RIGHT, current, stackSize, stack, root, f );
  67.       }  
  68.  
  69. // If there are two node references available: use them in the current node
  70.     if (stackSize >= 2) {
  71.       addNodeWithNoLeaves( current, stackSize, stack, root, f );
  72.       }
  73.    
  74.   }
  75.  
  76.   else {
  77.  
  78. // Terminal point: Do something with the expression
  79.     f( root );
  80.      
  81.     }  
  82.  
  83.   }              
  84.  
  85. void addNodeWithTwoLeaves( node* current, int stackSize,
  86.                            node* lastStack[], node* root, visitor f ) {
  87.  
  88.   node *stack[stackSize];  
  89.   for (int i=stackSize-1;i>=0;i--) stack[i] = lastStack[i];
  90.  
  91. // Build 2 leaves
  92.   *current = initialNode;
  93.   current--;
  94.   *current = initialNode;
  95.   current--;
  96.                  
  97. // Now build the op code                  
  98.   *current = initialNode;
  99.   current->isLeaf = false;  // tag as operation
  100.  
  101.   current->left  = current+1;
  102.   current->right = current+2;
  103.    
  104. // Push current node on stack  
  105.   stack[stackSize] = current;
  106.   stackSize++;
  107.  
  108.   doNode( current, stackSize, stack, root, f );
  109.  
  110.   }
  111.  
  112. void addNodeWithOneLeaf( childPos side, node* current,
  113.                          int stackSize, node* lastStack[], node* root, visitor f ) {
  114.  
  115.   node *stack[stackSize];  
  116.   for (int i=stackSize-1;i>=0;i--) stack[i] = lastStack[i];
  117.  
  118. // Build one leaf
  119.   *current = initialNode;
  120.   current--;
  121.                        
  122.   *current = initialNode;
  123.   current->isLeaf = false;  // tag as operation
  124.  
  125. // Make one of the child nodes point to the next free op    
  126.   switch (side) {
  127.     case LEFT:
  128.       current->left  = stack[stackSize-1];
  129.       current->right = current+1;
  130.       break;
  131.     case RIGHT:
  132.       current->right = stack[stackSize-1];
  133.       current->left  = current+1;
  134.       break;
  135.     default:
  136.       assert( false ); // Not allowed
  137.     }
  138.  
  139. // Replace top of stack by new node
  140.   stack[stackSize-1] = current;  
  141.    
  142.   doNode( current, stackSize, stack, root, f );
  143.  
  144.   }
  145.  
  146. void addNodeWithNoLeaves(node* current, int stackSize,
  147.                          node* lastStack[], node* root, visitor f ) {
  148.  
  149.   node *stack[stackSize];  
  150.   for (int i=stackSize-1;i>=0;i--) stack[i] = lastStack[i];
  151.  
  152.   *current = initialNode;
  153.   current->isLeaf = false;  // tag as operation
  154.  
  155. // Make the child nodes point to the topmost free op's
  156.   current->left  = stack[stackSize-1];    
  157.   current->right = stack[stackSize-2];
  158.    
  159. // pop 2, push 1 gives: pop 1  
  160.   stackSize--;  
  161.   stack[stackSize-1] = current;
  162.    
  163.   doNode( current, stackSize, stack, root, f );
  164.      
  165.   }
  166.  
  167. void printNode( node* current) {
  168.   static int n = 0;
  169.   static int j = 0;
  170.   if (current) {
  171.     j++;
  172.     if (current->isLeaf)
  173.       printf( "num" );
  174.     else {
  175.       printf( "[op,");
  176.       printNode( current->left );
  177.       printf( "," );
  178.       printNode( current->right );
  179.       printf( "]" );  
  180.       }
  181.     j--;
  182.     if (j == 0) {
  183.       n++;
  184.       printf( "\n");
  185.       }
  186.     }
  187.   else {
  188.     printf( "\nTotal: %d expression trees\n", n);
  189.     }      
  190.   }  
  191.  
  192. int main(int argc, char** argv) {
  193.  
  194.   int size;  /* How many expressions */
  195.  
  196.   if (argc < 2 || sscanf( argv[1], "%d", &size) == 0) size = 6;
  197.  
  198.   clock_t t_before = clock();  
  199.  
  200.   getExpressions( size, printNode );
  201.   printNode(0); // Print accumulated number of entries
  202.  
  203.   clock_t t_after = clock();  
  204.  
  205.   printf( "\n%ld msec execution time\n", (t_after - t_before)*1000/CLOCKS_PER_SEC );
  206.  
  207.   }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement