[SKIPLIST]
authorColin Finck <colin@reactos.org>
Thu, 25 Jun 2015 13:12:01 +0000 (13:12 +0000)
committerColin Finck <colin@reactos.org>
Thu, 25 Jun 2015 13:12:01 +0000 (13:12 +0000)
- Add a LookupNodeByIndexSkiplist function and a small test for it in skiplist_test.
- Remove a redundant double-set in LookupElementSkiplist.

Yes, we now have one lookup function that accepts search criteria and returns an element and another one that accepts an index and returns a SKIPLIST_NODE.
It's simply because I have exactly these two cases :)
You're free to implement the two missing functions or refactor this code another way.

svn path=/branches/colins-printing-for-freedom/; revision=68262

reactos/lib/skiplist/skiplist.c
reactos/lib/skiplist/skiplist.h
reactos/lib/skiplist/skiplist_test.c

index 929453d..b4d7fd2 100644 (file)
@@ -366,8 +366,6 @@ LookupElementSkiplist(PSKIPLIST Skiplist, PVOID Element, PDWORD ElementIndex)
     //    * Walk through all nodes on this level that come before the node we're looking for.
     //    * When we have reached such a node, go down a level and continue there.
     //    * Repeat these steps till we're in level 0, right in front of the node we're looking for.
-    pNode = &Skiplist->Head;
-
     for (i = Skiplist->MaximumLevel + 1; --i >= 0;)
     {
         while (pNode->Next[i] && pNode->Next[i] != pLastComparedNode && Skiplist->CompareRoutine(pNode->Next[i]->Element, Element) < 0)
@@ -395,3 +393,48 @@ LookupElementSkiplist(PSKIPLIST Skiplist, PVOID Element, PDWORD ElementIndex)
     // Return the stored element of the found node.
     return pNode->Element;
 }
+
+/**
+ * @name LookupNodeByIndexSkiplist
+ *
+ * Looks up a node in the Skiplist at the given position. The efficiency of this operation is O(log N) on average.
+ *
+ * @param Skiplist
+ * Pointer to the SKIPLIST structure to operate on.
+ *
+ * @param ElementIndex
+ * Zero-based position of the node in the Skiplist.
+ *
+ * @return
+ * Returns the found node or NULL if the position is invalid.
+ */
+PSKIPLIST_NODE
+LookupNodeByIndexSkiplist(PSKIPLIST Skiplist, DWORD ElementIndex)
+{
+    CHAR i;
+    DWORD dwIndex = 0;
+    PSKIPLIST_NODE pNode = &Skiplist->Head;
+
+    // The only way the node can't be found is when the index is out of range.
+    if (ElementIndex >= Skiplist->NodeCount)
+        return NULL;
+
+    // Do the efficient lookup in Skiplists:
+    //    * Start from the maximum level.
+    //    * Walk through all nodes on this level that come before the node we're looking for.
+    //    * When we have reached such a node, go down a level and continue there.
+    //    * Repeat these steps till we're in level 0, right in front of the node we're looking for.
+    for (i = Skiplist->MaximumLevel + 1; --i >= 0;)
+    {
+        // We compare with <= instead of < here, because the added distances make up a 1-based index while ElementIndex is zero-based,
+        // so we have to jump one node further.
+        while (pNode->Next[i] && dwIndex + pNode->Distance[i] <= ElementIndex)
+        {
+            dwIndex += pNode->Distance[i];
+            pNode = pNode->Next[i];
+        }
+    }
+
+    // We are right in front of the node we're looking for now.
+    return pNode->Next[0];
+}
index 0e66839..6fb4761 100644 (file)
@@ -49,5 +49,6 @@ BOOL InsertElementSkiplist(PSKIPLIST Skiplist, PVOID Element);
 BOOL InsertTailElementSkiplist(PSKIPLIST Skiplist, PVOID Element);
 PVOID DeleteElementSkiplist(PSKIPLIST Skiplist, PVOID Element);
 PVOID LookupElementSkiplist(PSKIPLIST Skiplist, PVOID Element, PDWORD ElementIndex);
+PSKIPLIST_NODE LookupNodeByIndexSkiplist(PSKIPLIST Skiplist, DWORD ElementIndex);
 
 #endif
index 66996be..9586562 100644 (file)
@@ -67,6 +67,7 @@ main()
     DWORD ElementIndex;
     DWORD i;
     SKIPLIST Skiplist;
+    PSKIPLIST_NODE pNode;
 
     system("mode con cols=300");
     InitializeSkiplist(&Skiplist, MyAlloc, MyCompare, MyFree);
@@ -83,6 +84,10 @@ main()
     for (i = 0; i < 40; i++)
         InsertElementSkiplist(&Skiplist, (PVOID)(rand() % 100));
 
+    // Output the third element (with zero-based index 2).
+    pNode = LookupNodeByIndexSkiplist(&Skiplist, 2);
+    printf("Element = %lu for index 2\n", (DWORD)pNode->Element);
+
     // Check if an element with number 44 is in the list and output its index.
     Element = (DWORD)LookupElementSkiplist(&Skiplist, (PVOID)44, &ElementIndex);
     printf("Element = %lu, ElementIndex = %lu\n\n", Element, ElementIndex);