Przeglądaj źródła

CAvl: add option to assume the keys are the indices of nodes, suitable for implementation of IndexedList

ambrop7 13 lat temu
rodzic
commit
d89417a560
4 zmienionych plików z 94 dodań i 1 usunięć
  1. 8 0
      structure/CAvl_decl.h
  2. 3 0
      structure/CAvl_footer.h
  3. 10 1
      structure/CAvl_header.h
  4. 73 0
      structure/CAvl_impl.h

+ 8 - 0
structure/CAvl_decl.h

@@ -42,10 +42,14 @@ static const CAvlLink CAvlNullLink = CAVL_PARAM_NULL;
 
 static void CAvl_Init (CAvl *o);
 static CAvlNode CAvl_Deref (CAvlArg arg, CAvlLink link);
+#if !CAVL_PARAM_KEYS_ARE_INDICES
 static int CAvl_Insert (CAvl *o, CAvlArg arg, CAvlNode node, CAvlNode *out_ref);
+#endif
 static void CAvl_Remove (CAvl *o, CAvlArg arg, CAvlNode node);
+#if !CAVL_PARAM_KEYS_ARE_INDICES
 static CAvlNode CAvl_Lookup (const CAvl *o, CAvlArg arg, CAvlKey key);
 static CAvlNode CAvl_LookupExact (const CAvl *o, CAvlArg arg, CAvlKey key);
+#endif
 static CAvlNode CAvl_GetFirst (const CAvl *o, CAvlArg arg);
 static CAvlNode CAvl_GetLast (const CAvl *o, CAvlArg arg);
 static CAvlNode CAvl_GetNext (const CAvl *o, CAvlArg arg, CAvlNode node);
@@ -59,4 +63,8 @@ static CAvlCount CAvl_IndexOf (const CAvl *o, CAvlArg arg, CAvlNode node);
 static CAvlNode CAvl_GetAt (const CAvl *o, CAvlArg arg, CAvlCount index);
 #endif
 
+#if CAVL_PARAM_KEYS_ARE_INDICES
+static void CAvl_InsertAt (CAvl *o, CAvlArg arg, CAvlNode node, CAvlCount index);
+#endif
+
 #include "CAvl_footer.h"

+ 3 - 0
structure/CAvl_footer.h

@@ -43,6 +43,7 @@
 #undef CAVL_PARAM_NODE_BALANCE
 #undef CAVL_PARAM_NODE_PARENT
 #undef CAVL_PARAM_NODE_COUNT
+#undef CAVL_PARAM_KEYS_ARE_INDICES
 
 #undef CAvl
 #undef CAvlEntry
@@ -69,6 +70,7 @@
 #undef CAvl_Count
 #undef CAvl_IndexOf
 #undef CAvl_GetAt
+#undef CAvl_InsertAt
 
 #undef CAvl_link
 #undef CAvl_balance
@@ -87,5 +89,6 @@
 #undef CAvl_replace_subtree_fix_counts
 #undef CAvl_swap_nodes
 #undef CAvl_rebalance
+#undef CAvl_child_count
 #undef CAvl_MAX
 #undef CAvl_OPTNEG

+ 10 - 1
structure/CAvl_header.h

@@ -32,7 +32,7 @@
 // CAVL_PARAM_NAME - name of this data structure
 // CAVL_PARAM_ENTRY - type of entry
 // CAVL_PARAM_LINK - type of node link (usually pointer)
-// CAVL_PARAM_KEY - type of key
+// CAVL_PARAM_KEY - type of key (unused if CAVL_PARAM_KEYS_ARE_INDICES=1) 
 // CAVL_PARAM_ARG - type of argument pass through to comparisons
 // CAVL_PARAM_COUNT - type of count
 // CAVL_PARAM_COUNT_MAX - maximum value of count
@@ -44,6 +44,13 @@
 // CAVL_PARAM_NODE_BALANCE - balance member in node
 // CAVL_PARAM_NODE_PARENT - parent member in node
 // CAVL_PARAM_NODE_COUNT - count member in node (if CAVL_PARAM_USE_COUNTS)
+// CAVL_PARAM_KEYS_ARE_INDICES - (0 or 1) whether to assume the keys are node indices
+//                               (number of nodes lesser than given node). If yes,
+//                               CAVL_PARAM_KEY is unused. Requires CAVL_PARAM_USE_COUNTS.
+
+#if CAVL_PARAM_KEYS_ARE_INDICES && !CAVL_PARAM_USE_COUNTS
+#error CAVL_PARAM_KEYS_ARE_INDICES requires CAVL_PARAM_USE_COUNTS
+#endif
 
 // types
 #define CAvl CAVL_PARAM_NAME
@@ -73,6 +80,7 @@
 #define CAvl_Count MERGE(CAvl, _Count)
 #define CAvl_IndexOf MERGE(CAvl, _IndexOf)
 #define CAvl_GetAt MERGE(CAvl, _GetAt)
+#define CAvl_InsertAt MERGE(CAvl, _InsertAt)
 
 // private stuff
 #define CAvl_link(node) ((node).ptr->CAVL_PARAM_NODE_LINK)
@@ -92,5 +100,6 @@
 #define CAvl_replace_subtree_fix_counts MERGE(CAvl, __replace_subtree_fix_counts)
 #define CAvl_swap_nodes MERGE(CAvl, __swap_nodes)
 #define CAvl_rebalance MERGE(CAvl, __rebalance)
+#define CAvl_child_count MERGE(CAvl, __child_count)
 #define CAvl_MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
 #define CAvl_OPTNEG(_a, _neg) ((_neg) ? -(_a) : (_a))

+ 73 - 0
structure/CAvl_impl.h

@@ -37,6 +37,7 @@ static CAvlNode CAvl_nullnode (void)
     return n;
 }
 
+#if !CAVL_PARAM_KEYS_ARE_INDICES
 static int CAvl_compare_nodes (CAvlArg arg, CAvlNode node1, CAvlNode node2)
 {
     int res = CAVL_PARAM_COMPARE_NODES(arg, node1, node2);
@@ -54,6 +55,7 @@ static int CAvl_compare_key_node (CAvlArg arg, CAvlKey key1, CAvlNode node2)
     
     return res;
 }
+#endif
 
 static int CAvl_check_parent (CAvlNode p, CAvlNode c)
 {
@@ -77,7 +79,9 @@ static int CAvl_verify_recurser (CAvlArg arg, CAvlNode n)
         // check parent link
         ASSERT_FORCE(CAvl_parent(CAvl_Deref(arg, CAvl_link(n)[0])) == n.link)
         // check binary search tree
+#if !CAVL_PARAM_KEYS_ARE_INDICES
         ASSERT_FORCE(CAvl_compare_nodes(arg, CAvl_Deref(arg, CAvl_link(n)[0]), n) == -1)
+#endif
         // recursively calculate height
         height_left = CAvl_verify_recurser(arg, CAvl_Deref(arg, CAvl_link(n)[0]));
 #if CAVL_PARAM_USE_COUNTS
@@ -89,8 +93,10 @@ static int CAvl_verify_recurser (CAvlArg arg, CAvlNode n)
     if (CAvl_link(n)[1] != CAvlNullLink) {
         // check parent link
         ASSERT_FORCE(CAvl_parent(CAvl_Deref(arg, CAvl_link(n)[1])) == n.link)
+#if !CAVL_PARAM_KEYS_ARE_INDICES
         // check binary search tree
         ASSERT_FORCE(CAvl_compare_nodes(arg, CAvl_Deref(arg, CAvl_link(n)[1]), n) == 1)
+#endif
         // recursively calculate height
         height_right = CAvl_verify_recurser(arg, CAvl_Deref(arg, CAvl_link(n)[1]));
 #if CAVL_PARAM_USE_COUNTS
@@ -369,6 +375,13 @@ static void CAvl_rebalance (CAvl *o, CAvlArg arg, CAvlNode node, uint8_t side, i
     }
 }
 
+#if CAVL_PARAM_KEYS_ARE_INDICES
+static CAvlCount CAvl_child_count (CAvlArg arg, CAvlNode n, int dir)
+{
+    return (CAvl_link(n)[dir] != CAvlNullLink ? CAvl_count(CAvl_Deref(arg, CAvl_link(n)[dir])) : 0);
+}
+#endif
+
 static void CAvl_Init (CAvl *o)
 {
     o->root = CAvlNullLink;
@@ -389,6 +402,7 @@ static CAvlNode CAvl_Deref (CAvlArg arg, CAvlLink link)
     return n;
 }
 
+#if !CAVL_PARAM_KEYS_ARE_INDICES
 static int CAvl_Insert (CAvl *o, CAvlArg arg, CAvlNode node, CAvlNode *out_ref)
 {
     ASSERT(node.link != CAvlNullLink)
@@ -457,6 +471,7 @@ static int CAvl_Insert (CAvl *o, CAvlArg arg, CAvlNode node, CAvlNode *out_ref)
     }
     return 1;
 }
+#endif
 
 static void CAvl_Remove (CAvl *o, CAvlArg arg, CAvlNode node)
 {
@@ -484,6 +499,7 @@ static void CAvl_Remove (CAvl *o, CAvlArg arg, CAvlNode node)
     CAvl_assert_tree(o, arg);
 }
 
+#if !CAVL_PARAM_KEYS_ARE_INDICES
 static CAvlNode CAvl_Lookup (const CAvl *o, CAvlArg arg, CAvlKey key)
 {
     if (o->root == CAvlNullLink) {
@@ -537,6 +553,7 @@ static CAvlNode CAvl_LookupExact (const CAvl *o, CAvlArg arg, CAvlKey key)
         c = CAvl_Deref(arg, CAvl_link(c)[side]);
     }
 }
+#endif
 
 static CAvlNode CAvl_GetFirst (const CAvl *o, CAvlArg arg)
 {
@@ -666,4 +683,60 @@ static CAvlNode CAvl_GetAt (const CAvl *o, CAvlArg arg, CAvlCount index)
 
 #endif
 
+#if CAVL_PARAM_KEYS_ARE_INDICES
+static void CAvl_InsertAt (CAvl *o, CAvlArg arg, CAvlNode node, CAvlCount index)
+{
+    ASSERT(node.link != CAvlNullLink)
+    ASSERT(index <= CAvl_Count(o, arg))
+    
+    // insert to root?
+    if (o->root == CAvlNullLink) {
+        o->root = node.link;
+        CAvl_parent(node) = CAvlNullLink;
+        CAvl_link(node)[0] = CAvlNullLink;
+        CAvl_link(node)[1] = CAvlNullLink;
+        CAvl_balance(node) = 0;
+        CAvl_count(node) = 1;
+        
+        CAvl_assert_tree(o, arg);
+        return;
+    }
+    
+    CAvlNode c = CAvl_Deref(arg, o->root);
+    CAvlCount c_idx = CAvl_child_count(arg, c, 0);
+    int side;
+    while (1) {
+        side = (index > c_idx);
+        
+        if (CAvl_link(c)[side] == CAvlNullLink) {
+            break;
+        }
+        
+        c = CAvl_Deref(arg, CAvl_link(c)[side]);
+        
+        if (side == 0) {
+            c_idx -= 1 + CAvl_child_count(arg, c, 1);
+        } else {
+            c_idx += 1 + CAvl_child_count(arg, c, 0);
+        }
+    }
+    
+    CAvl_link(c)[side] = node.link;
+    CAvl_parent(node) = c.link;
+    CAvl_link(node)[0] = CAvlNullLink;
+    CAvl_link(node)[1] = CAvlNullLink;
+    CAvl_balance(node) = 0;
+    CAvl_count(node) = 1;
+    
+    for (CAvlNode p = c; p.link != CAvlNullLink; p = CAvl_Deref(arg, CAvl_parent(p))) {
+        CAvl_count(p)++;
+    }
+    
+    CAvl_rebalance(o, arg, c, side, 1);
+    
+    CAvl_assert_tree(o, arg);
+    return;
+}
+#endif
+
 #include "CAvl_footer.h"