chemoelectric

Persistent AVL trees (generic)

May 5th, 2026 (edited)
403
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 27.23 KB | Source Code | 0 0
  1. /*
  2.  
  3.   The hiha programming language
  4.  
  5.   Copyright © 2026 Barry Schwartz
  6.  
  7.   This program is free software: you can redistribute it and/or modify
  8.   it under the terms of the GNU General Public License as published by
  9.   the Free Software Foundation, either version 3 of the License, or
  10.   (at your option) any later version.
  11.  
  12.   This program is distributed in the hope that it will be useful,
  13.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.   GNU General Public License for more details.
  16.  
  17.   You should have received a copy of the GNU General Public License
  18.   along with this program.  If not, see <https://www.gnu.org/licenses/>.
  19.  
  20. */
  21.  
  22. #include <stdlib.h>
  23. #include <assert.h>
  24.  
  25. #include <stddef.h>
  26. #define HIHA_AVL_ALLOC(T) malloc(sizeof(T)) /* FIXME */ /* FIXME */ /* FIXME */ /* FIXME */ /* FIXME */ /* FIXME */ /* FIXME */
  27.  
  28. #define HIHA_AVL_HEIGHT_T unsigned short int
  29. #define HIHA_AVL_NODE_DECL(NAME, T)             \
  30.   typedef struct NAME                           \
  31.   {                                             \
  32.     T data;                                     \
  33.     HIHA_AVL_HEIGHT_T height;                   \
  34.     struct NAME *left;                          \
  35.     struct NAME *right;                         \
  36.   } *NAME##_t;
  37.  
  38. #define HIHA_AVL_NODE_BALANCE(NAME, NODE)                               \
  39.   (((NODE) == NULL) ? ((int) 0) :                                       \
  40.    (((int) ((NODE)->left == NULL) ? 0 : (NODE)->left->height)           \
  41.     - ((int) ((NODE)->right == NULL) ? 0 : (NODE)->right->height)))
  42.  
  43. #define HIHA_AVL_MAKE_NODE(NEW_NODE, NAME, DATA, LEFT, RIGHT)           \
  44.   do                                                                    \
  45.     {                                                                   \
  46.       struct NAME *_node__ = HIHA_AVL_ALLOC (struct NAME);              \
  47.       _node__->data = (DATA);                                           \
  48.       _node__->left = (LEFT);                                           \
  49.       _node__->right = (RIGHT);                                         \
  50.       const HIHA_AVL_HEIGHT_T _Lheight =                                \
  51.         (_node__->left == NULL) ? 0 : _node__->left->height;            \
  52.       const HIHA_AVL_HEIGHT_T _Rheight =                                \
  53.         (_node__->right == NULL) ? 0 : _node__->right->height;          \
  54.       _node__->height = /* (the greater of the two heights) + 1 */      \
  55.         ((_Lheight < _Rheight) ? _Rheight : _Lheight) + 1;              \
  56.       NEW_NODE = _node__;                                               \
  57.     }                                                                   \
  58.   while (0)
  59.  
  60. /* Nondestructive rotation. */
  61. #define HIHA_AVL_ROTATE_LEFT(NEW_NODE, NAME, NODE)      \
  62.   do                                                    \
  63.     {                                                   \
  64.       struct NAME *_nd__ = (NODE);                      \
  65.       struct NAME *_nd_R__ = _nd__->right;              \
  66.       struct NAME *_new__;                              \
  67.       HIHA_AVL_MAKE_NODE (_new__, NAME, _nd__->data,    \
  68.                           _nd__->left, _nd_R__->left);  \
  69.       HIHA_AVL_MAKE_NODE (_new__, NAME, _nd_R__->data,  \
  70.                           _new__, _nd_R__->right);      \
  71.       NEW_NODE = _new__;                                \
  72.     }                                                   \
  73.   while (0)
  74.  
  75. /* Nondestructive rotation. */
  76. #define HIHA_AVL_ROTATE_RIGHT(NEW_NODE, NAME, NODE)             \
  77.   do                                                            \
  78.     {                                                           \
  79.       struct NAME *_nd__ = (NODE);                              \
  80.       struct NAME *_nd_L__ = _nd__->left;                       \
  81.       struct NAME *_new__;                                      \
  82.       HIHA_AVL_MAKE_NODE (_new__, NAME, _nd__->data,            \
  83.                           _nd_L__->right, _nd__->right);        \
  84.       HIHA_AVL_MAKE_NODE (_new__, NAME, _nd_L__->data,          \
  85.                           _nd_L__->left, _new__);               \
  86.       NEW_NODE = _new__;                                        \
  87.     }                                                           \
  88.   while (0)
  89.  
  90. /* Verify that a tree is balanced. Return the height if the tree is
  91.    balanced, or -1 if it is not. */
  92. #define HIHA_AVL_VERIFY_DEFN(FUNC, NAME)                \
  93.   int                                                   \
  94.   FUNC (struct NAME *_Node)                             \
  95.   {                                                     \
  96.     int result = -1;                                    \
  97.     if (_Node == NULL)                                  \
  98.       result = 0;                                       \
  99.     else                                                \
  100.       {                                                 \
  101.         int height_L = (FUNC) (_Node->left);            \
  102.         if (height_L != -1)                             \
  103.           {                                             \
  104.             int height_R = (FUNC) (_Node->right);       \
  105.             if (height_R != -1)                         \
  106.               {                                         \
  107.                 int diff = height_L - height_R;         \
  108.                 if (diff == -1 || diff == 0)            \
  109.                   result = height_R + 1;                \
  110.                 else if (diff == 1)                     \
  111.                   result = height_L + 1;                \
  112.               }                                         \
  113.           }                                             \
  114.       }                                                 \
  115.     return result;                                      \
  116.   }
  117.  
  118. /* An in-order walk with callbacks. */
  119. #define HIHA_AVL_INORDER_DEFN(FUNC, NAME)                       \
  120.   void                                                          \
  121.   FUNC (struct NAME *_Node, int _Direction,                     \
  122.         void (*_Do_something) (struct NAME *, void *),          \
  123.         void *_Possibly_some_data)                              \
  124.   {                                                             \
  125.     assert (_Direction == -1 || _Direction == 1);               \
  126.     if (_Node != NULL)                                          \
  127.       {                                                         \
  128.         if (_Direction == -1)                                   \
  129.           {                                                     \
  130.             (FUNC) (_Node->right, _Direction, (_Do_something),  \
  131.                     _Possibly_some_data);                       \
  132.             (_Do_something) (_Node, _Possibly_some_data);       \
  133.             (FUNC) (_Node->left, _Direction, (_Do_something),   \
  134.                     _Possibly_some_data);                       \
  135.           }                                                     \
  136.         else                                                    \
  137.           {                                                     \
  138.             (FUNC) (_Node->left, _Direction, (_Do_something),   \
  139.                     _Possibly_some_data);                       \
  140.             (_Do_something) (_Node, _Possibly_some_data);       \
  141.             (FUNC) (_Node->right, _Direction, (_Do_something),  \
  142.                     _Possibly_some_data);                       \
  143.           }                                                     \
  144.       }                                                         \
  145.   }
  146.  
  147. /* Search for a matching node. */
  148. #define HIHA_AVL_SEARCH_DEFN(FUNC, NAME, T)                     \
  149.   struct NAME *                                                 \
  150.   FUNC (struct NAME *_Node, T _Data,                            \
  151.         int (*_Compare) (const T *, const T *))                 \
  152.   {                                                             \
  153.     struct NAME *_Result = NULL;                                \
  154.     if (_Node != NULL)                                          \
  155.       {                                                         \
  156.         int _Cmp = (_Compare) (&_Data, &_Node->data);           \
  157.         if (_Cmp < 0)                                           \
  158.           _Result = (FUNC) (_Node->left, _Data, (_Compare));    \
  159.         else if (_Cmp == 0)                                     \
  160.           _Result = _Node;                                      \
  161.         else                                                    \
  162.           _Result = (FUNC) (_Node->right, _Data, (_Compare));   \
  163.       }                                                         \
  164.     return _Result;                                             \
  165.   }
  166.  
  167. /* Insert a node, nondestructively. */
  168. #define HIHA_AVL_INSERT_DEFN(FUNC, NAME, T)                             \
  169.   struct NAME *                                                         \
  170.   FUNC (struct NAME *_Node, T _Data,                                    \
  171.         int (*_Compare) (const T *, const T *))                         \
  172.   {                                                                     \
  173.     struct NAME *_Result;                                               \
  174.     if (_Node == NULL)                                                  \
  175.       HIHA_AVL_MAKE_NODE (_Result, NAME, _Data, NULL, NULL);            \
  176.     else                                                                \
  177.       {                                                                 \
  178.         int _Cmp = (_Compare) (&_Data, &_Node->data);                   \
  179.         if (_Cmp == 0)                                                  \
  180.           /* Same key, different value. */                              \
  181.           HIHA_AVL_MAKE_NODE (_Result, NAME, _Data, _Node->left,        \
  182.                               _Node->right);                            \
  183.         else                                                            \
  184.           {                                                             \
  185.             if (_Cmp < 0)                                               \
  186.               HIHA_AVL_MAKE_NODE (_Result, NAME, _Node->data,           \
  187.                                   (FUNC) (_Node->left, _Data,           \
  188.                                           (_Compare)),                  \
  189.                                   _Node->right);                        \
  190.             else                                                        \
  191.               HIHA_AVL_MAKE_NODE (_Result, NAME, _Node->data,           \
  192.                                   _Node->left,                          \
  193.                                   (FUNC) (_Node->right, _Data,          \
  194.                                           (_Compare)));                 \
  195.                                                                         \
  196.             /* Rebalance. */                                            \
  197.             int _Bal = HIHA_AVL_NODE_BALANCE (NAME, _Result);           \
  198.             if (_Bal < -1)                                              \
  199.               {                                                         \
  200.                 _Cmp = (_Compare) (&_Data, &_Result->right->data);      \
  201.                 if (_Cmp < 0)                                           \
  202.                   {                                                     \
  203.                     struct NAME *_nd;                                   \
  204.                     HIHA_AVL_ROTATE_RIGHT (_nd, NAME, _Result->right);  \
  205.                     HIHA_AVL_MAKE_NODE (_nd, NAME, _Result->data,       \
  206.                                         _Result->left, _nd);            \
  207.                     HIHA_AVL_ROTATE_LEFT (_Result, NAME, _nd);          \
  208.                   }                                                     \
  209.                 else if (0 < _Cmp)                                      \
  210.                   HIHA_AVL_ROTATE_LEFT (_Result, NAME, _Result);        \
  211.               }                                                         \
  212.             else if (1 < _Bal)                                          \
  213.               {                                                         \
  214.                 _Cmp = (_Compare) (&_Data, &_Result->left->data);       \
  215.                 if (_Cmp < 0)                                           \
  216.                   HIHA_AVL_ROTATE_RIGHT (_Result, NAME, _Result);       \
  217.                 else if (0 < _Cmp)                                      \
  218.                   {                                                     \
  219.                     struct NAME *_nd;                                   \
  220.                     HIHA_AVL_ROTATE_LEFT (_nd, NAME, _Result->left);    \
  221.                     HIHA_AVL_MAKE_NODE (_nd, NAME, _Result->data,       \
  222.                                         _nd, _Result->right);           \
  223.                     HIHA_AVL_ROTATE_RIGHT (_Result, NAME, _nd);         \
  224.                   }                                                     \
  225.               }                                                         \
  226.           }                                                             \
  227.       }                                                                 \
  228.     return _Result;                                                     \
  229.   }
  230.  
  231. /* Delete a node, nondestructively. */
  232. #define HIHA_AVL_DELETE_DEFN(FUNC, NAME, T)                             \
  233.   struct NAME *                                                         \
  234.   FUNC (struct NAME *_Node, T _Data,                                    \
  235.         int (*_Compare) (const T *, const T *))                         \
  236.   {                                                                     \
  237.     struct NAME *_Result = NULL;                                        \
  238.     if (_Node != NULL)                                                  \
  239.       {                                                                 \
  240.         bool needs_rebalancing = false;                                 \
  241.         int _Cmp = (_Compare) (&_Data, &_Node->data);                   \
  242.         if (_Cmp < 0)                                                   \
  243.           {                                                             \
  244.             HIHA_AVL_MAKE_NODE (_Result, NAME, _Node->data,             \
  245.                                 (FUNC) (_Node->left, _Data,             \
  246.                                         (_Compare)),                    \
  247.                                 _Node->right);                          \
  248.             needs_rebalancing = true;                                   \
  249.           }                                                             \
  250.         else if (0 < _Cmp)                                              \
  251.           {                                                             \
  252.             HIHA_AVL_MAKE_NODE (_Result, NAME, _Node->data,             \
  253.                                 _Node->left,                            \
  254.                                 (FUNC) (_Node->right, _Data,            \
  255.                                         (_Compare)));                   \
  256.             needs_rebalancing = true;                                   \
  257.           }                                                             \
  258.         else                                                            \
  259.           {                                                             \
  260.             /* _Node is the node to be deleted.                    */   \
  261.             if (_Node->left == NULL)                                    \
  262.               /* _Node is a leaf or _Node->right is a leaf.        */   \
  263.               /* The result will be NULL or a leaf.                */   \
  264.               _Result = _Node->right;                                   \
  265.             else if (_Node->right == NULL)                              \
  266.               /* _Node->left is a leaf. The result will be a leaf. */   \
  267.               _Result = _Node->left;                                    \
  268.             else                                                        \
  269.               {                                                         \
  270.                 /* Find the in-order successor to _Node.           */   \
  271.                 struct NAME *_succ = _Node->right;                      \
  272.                 while (_succ->left != NULL)                             \
  273.                   _succ = _succ->left;                                  \
  274.                                                                         \
  275.                 /* Move the successor to where _Node is.           */   \
  276.                 HIHA_AVL_MAKE_NODE (_Result, NAME, _succ->data,         \
  277.                                     _Node->left,                        \
  278.                                     (FUNC) (_Node->right, _succ->data,  \
  279.                                             (_Compare)));               \
  280.                 needs_rebalancing = true;                               \
  281.               }                                                         \
  282.           }                                                             \
  283.         if (_Result != NULL && needs_rebalancing)                       \
  284.           {                                                             \
  285.             int _Bal = HIHA_AVL_NODE_BALANCE (NAME, _Result);           \
  286.             if (_Bal < -1)                                              \
  287.               {                                                         \
  288.                 int _BalR =                                             \
  289.                   HIHA_AVL_NODE_BALANCE (NAME, _Result->right);         \
  290.                 if (_BalR <= 0)                                         \
  291.                   HIHA_AVL_ROTATE_LEFT (_Result, NAME, _Result);        \
  292.                 else                                                    \
  293.                   {                                                     \
  294.                     struct NAME *_nd;                                   \
  295.                     HIHA_AVL_ROTATE_RIGHT (_nd, NAME, _Result->right);  \
  296.                     HIHA_AVL_MAKE_NODE (_nd, NAME, _Result->data,       \
  297.                                         _Result->left, _nd);            \
  298.                     HIHA_AVL_ROTATE_LEFT (_Result, NAME, _nd);          \
  299.                   }                                                     \
  300.               }                                                         \
  301.             else if (1 < _Bal)                                          \
  302.               {                                                         \
  303.                 int _BalL =                                             \
  304.                   HIHA_AVL_NODE_BALANCE (NAME, _Result->left);          \
  305.                 if (0 <= _BalL)                                         \
  306.                   HIHA_AVL_ROTATE_RIGHT (_Result, NAME, _Result);       \
  307.                 else                                                    \
  308.                   {                                                     \
  309.                     struct NAME *_nd;                                   \
  310.                     HIHA_AVL_ROTATE_LEFT (_nd, NAME, _Result->left);    \
  311.                     HIHA_AVL_MAKE_NODE (_nd, NAME, _Result->data,       \
  312.                                         _nd, _Result->right);           \
  313.                     HIHA_AVL_ROTATE_RIGHT (_Result, NAME, _nd);         \
  314.                   }                                                     \
  315.               }                                                         \
  316.           }                                                             \
  317.       }                                                                 \
  318.     return _Result;                                                     \
  319.   }
  320.  
  321. /* A simple test. This test requires GNU C nested functions. */
  322. #define HIHA_AVL_TEST_DEFN(FUNC, BUFSIZE)                               \
  323.   void                                                                  \
  324.   FUNC (void)                                                           \
  325.   {                                                                     \
  326.     static int buf[BUFSIZE];                                            \
  327.                                                                         \
  328.     void fisher_yates (void)                                            \
  329.     {                                                                   \
  330.       for (int i = 0; i != (BUFSIZE); i += 1)                           \
  331.         buf[i] = i;                                                     \
  332.       for (int i = (BUFSIZE) - 1; i != 0; i -= 1)                       \
  333.         {                                                               \
  334.           /* Dividing the big random integer is good enough. */         \
  335.           int j = (int) (random () % ((long) i) + 1);                   \
  336.                                                                         \
  337.           int _tmp = buf[i];                                            \
  338.           buf[i] = buf[j];                                              \
  339.           buf[j] = _tmp;                                                \
  340.         }                                                               \
  341.     }                                                                   \
  342.                                                                         \
  343.     int int_cmp (const int *a, const int *b)                            \
  344.     {                                                                   \
  345.       return (*a < *b) ? -1 : ((*b < *a) ? 1 : 0);                      \
  346.     }                                                                   \
  347.                                                                         \
  348.     HIHA_AVL_NODE_DECL (avl_int_node, int);                             \
  349.     HIHA_AVL_VERIFY_DEFN (avl_int_verify, avl_int_node);                \
  350.     HIHA_AVL_INORDER_DEFN(avl_int_inorder, avl_int_node);               \
  351.     HIHA_AVL_SEARCH_DEFN (avl_int_search, avl_int_node, int);           \
  352.     HIHA_AVL_INSERT_DEFN (avl_int_insert, avl_int_node, int);           \
  353.     HIHA_AVL_DELETE_DEFN (avl_int_delete, avl_int_node, int);           \
  354.                                                                         \
  355.     avl_int_node_t tree;                                                \
  356.     int i;                                                              \
  357.     int j;                                                              \
  358.                                                                         \
  359.     void test_backwards (avl_int_node_t node, void *data)               \
  360.     {                                                                   \
  361.       int *p = (int *) data;                                            \
  362.       *p += -1;                                                         \
  363.       assert (node->data == *p);                                        \
  364.     }                                                                   \
  365.                                                                         \
  366.     void test_forwards (avl_int_node_t node, void *data)                \
  367.     {                                                                   \
  368.       int *p = (int *) data;                                            \
  369.       assert (node->data == *p);                                        \
  370.       *p += 1;                                                          \
  371.     }                                                                   \
  372.                                                                         \
  373.     /* Insert in random order. */                                       \
  374.     fisher_yates ();                                                    \
  375.     tree = NULL;                                                        \
  376.     assert (0 <= (avl_int_verify) (tree));                              \
  377.     for (i = 0; i != (BUFSIZE); i += 1)                                 \
  378.       {                                                                 \
  379.         tree = (avl_int_insert) (tree, buf[i], (int_cmp));              \
  380.         assert (0 <= (avl_int_verify) (tree));                          \
  381.       }                                                                 \
  382.                                                                         \
  383.     /* Search in random order. */                                       \
  384.     fisher_yates ();                                                    \
  385.     for (i = 0; i != (BUFSIZE); i += 1)                                 \
  386.       assert ((avl_int_search) (tree, buf[i], (int_cmp)) != NULL);      \
  387.                                                                         \
  388.     /* In-order walk backwards. */                                      \
  389.     i = BUFSIZE;                                                        \
  390.     (avl_int_inorder) (tree, -1, test_backwards, &i);                   \
  391.                                                                         \
  392.     /* In-order walk forwards. */                                       \
  393.     i = 0;                                                              \
  394.     (avl_int_inorder) (tree, 1, test_forwards, &i);                     \
  395.                                                                         \
  396.     /* Delete in random order. */                                       \
  397.     fisher_yates ();                                                    \
  398.     for (i = 0; i != (BUFSIZE); i += 1)                                 \
  399.       {                                                                 \
  400.         tree = (avl_int_delete) (tree, buf[i], (int_cmp));              \
  401.         assert (0 <= (avl_int_verify) (tree));                          \
  402.       }                                                                 \
  403.     assert (tree == NULL);                                              \
  404.                                                                         \
  405.     /* Insert in random order. */                                       \
  406.     fisher_yates ();                                                    \
  407.     tree = NULL;                                                        \
  408.     assert (0 <= (avl_int_verify) (tree));                              \
  409.     for (i = 0; i != (BUFSIZE); i += 1)                                 \
  410.       {                                                                 \
  411.         tree = (avl_int_insert) (tree, buf[i], (int_cmp));              \
  412.         assert (0 <= (avl_int_verify) (tree));                          \
  413.       }                                                                 \
  414.                                                                         \
  415.     /* Delete in ascending order. */                                    \
  416.     fisher_yates ();                                                    \
  417.     for (i = 0; i != (BUFSIZE); i += 1)                                 \
  418.       {                                                                 \
  419.         tree = (avl_int_delete) (tree, i, (int_cmp));                   \
  420.         assert (0 <= (avl_int_verify) (tree));                          \
  421.         for (j = i + 1; j != (BUFSIZE); j += 1)                         \
  422.           assert ((avl_int_search) (tree, j, (int_cmp)) != NULL);       \
  423.       }                                                                 \
  424.     assert (tree == NULL);                                              \
  425.   }
  426.  
Advertisement
Add Comment
Please, Sign In to add comment