detect/sigorder: make merge sort stable

Merge sort by default is a stable sorting algorithm which means that the
relative order of all elements must be preserved in the final list.
However, the implementation in SCSigOrder, instead of breaking each of
the arrays into halves and going about the usual divide and conquer,
ends up doing two things that make it unstable:
1. each array has a reversed order
2. the two halves at any point are created as by picking one item from
   the main array and putting it in the first half followed by picking
   second item from the main array and putting it in the second half.

Fix this by first finding the midpoint of the main array in the current
recursive call and breaking the array there. The midpoint is found using
the Tortoise and Hare algorithm. The heads of each of the divided arrays
point to the beginning.

This guarantees the relative order among the elements to be stable.
This becomes a bug when the final order is not to be messed with as done
in the solution for

Bug 7638
Bug 7771
Bug 1399
pull/16172/head
Shivani Bhardwaj 6 months ago
parent 84995ea753
commit 1d77925a04

@ -570,38 +570,50 @@ static SCSigSignatureWrapper *SCSigOrder(SCSigSignatureWrapper *sw,
{
DEBUG_VALIDATE_BUG_ON(sw == NULL);
if (sw->next == NULL) {
/* only one element in the list */
return sw;
}
SCSigSignatureWrapper *subA = NULL;
SCSigSignatureWrapper *subB = NULL;
SCSigSignatureWrapper *first;
SCSigSignatureWrapper *second;
SCSigSignatureWrapper *result = NULL;
SCSigSignatureWrapper *last = NULL;
SCSigSignatureWrapper *new = NULL;
/* Divide input list into two sub-lists. */
while (sw != NULL) {
first = sw;
sw = sw->next;
/* Push the first element onto sub-list A */
first->next = subA;
subA = first;
if (sw == NULL)
break;
second = sw;
sw = sw->next;
/* Push the second element onto sub-list B */
second->next = subB;
subB = second;
}
if (subB == NULL) {
/* Only zero or one element on the list. */
return subA;
/* Divide input list into two sub-lists using Tortoise and Hare algorithm */
SCSigSignatureWrapper *slow = sw;
SCSigSignatureWrapper *fast = sw; /* 2x faster pointer */
SCSigSignatureWrapper *prev = NULL;
while (fast != NULL && fast->next != NULL) {
prev = slow;
slow = slow->next;
fast = fast->next->next;
}
prev->next = NULL; /* Cut the first half */
subA = sw; /* First half */
subB = slow; /* Second half */
SCLogDebug("subA is: %d; subB is: %d", subA->sig->id, subB->sig->id);
DEBUG_VALIDATE_BUG_ON(subA == NULL);
DEBUG_VALIDATE_BUG_ON(subB == NULL);
/* Now sort each list */
#ifdef DEBUG
SCLogDebug("subA:");
for (SCSigSignatureWrapper *sigw = subA; sigw != NULL; sigw = sigw->next) {
SCLogDebug("sig_id: %d", sigw->sig->id);
}
#endif
subA = SCSigOrder(subA, cmp_func_list);
#ifdef DEBUG
SCLogDebug("subB:");
for (SCSigSignatureWrapper *sigw = subB; sigw != NULL; sigw = sigw->next) {
SCLogDebug("sig_id: %d", sigw->sig->id);
}
#endif
subB = SCSigOrder(subB, cmp_func_list);
DEBUG_VALIDATE_BUG_ON(subA == NULL);
DEBUG_VALIDATE_BUG_ON(subB == NULL);

Loading…
Cancel
Save