Reputation:
I've ported to C++ (well, I guess mostly C) this Java 3-Way radix quicksort implementation (page 27):
//Java code from the linked Princeton PDF, page 27...
private static void quicksortX(String a[], int lo, int hi, int d)
{
if (hi - lo <= 0) return;
int i = lo-1, j = hi;
int p = lo-1, q = hi;
char v = a[hi].charAt(d);
while (i < j)
{
while (a[++i].charAt(d) < v) if (i == hi) break;
while (v < a[--j].charAt(d)) if (j == lo) break;
if (i > j) break;
exch(a, i, j);
if (a[i].charAt(d) == v) exch(a, ++p, i);
if (a[j].charAt(d) == v) exch(a, j, --q);
}
if (p == q)
{
if (v != '\0') quicksortX(a, lo, hi, d+1);
return;
}
if (a[i].charAt(d) < v) i++;
for (int k = lo; k <= p; k++) exch(a, k, j--);
for (int k = hi; k >= q; k--) exch(a, k, i++);
quicksortX(a, lo, j, d);
if ((i == hi) && (a[i].charAt(d) == v)) i++;
if (v != '\0') quicksortX(a, j+1, i-1, d+1);
quicksortX(a, i, hi, d);
}
I'm not a C++ programmer but I studied C in the 1980s and am obviously rusty.
I managed to use MS Visual Studio to hack together this port of the above code to make a C/C++ dll to be called from Excel VBA:
void swapPointers(long **a, long **b) {
long *t = *a;
*a = *b;
*b = t;
}
long int __stdcall QuicksortX(LPSAFEARRAY FAR *psaBSTRs, long lo, long hi, long d = 0)
{
if (hi - lo <= 0) return 1;
long i = lo-1, j = hi;
long p = lo-1, q = hi;
if ((*psaBSTRs)->cDims > 0) {
long lb = (*psaBSTRs)->rgsabound[0].lLbound;
long ub = lb + (*psaBSTRs)->rgsabound[0].cElements - 1;
if (lo < lb || lo > ub || lo > hi) {return -2;}
if (hi < lb || hi > ub || hi < lo) {return -3;}
} else {
return -1;
}
BSTR *a = (BSTR*)(*psaBSTRs)->pvData;
short v = LPSTR(a[hi])[d];
while (i < j)
{
while (LPSTR(a[++i])[d] < v) if (i == hi) break;
while (v < LPSTR(a[--j])[d]) if (j == lo) break;
if (i > j) break;
swapPointers((long**)a[i], (long**)a[j]);
if (LPSTR(a[i])[d] == v) swapPointers((long**)a[++p], (long**)a[i]);
if (LPSTR(a[j])[d] == v) swapPointers((long**)a[j], (long**)a[--q]);
}
if (p == q) {
if (v != 0) QuicksortX(psaBSTRs, lo, hi, d+1);
return 0;
}
if (LPSTR(a[i])[d] < v) i++;
for (int k = lo; k <= p; k++) swapPointers((long**)a[k], (long**)a[j--]);
for (int k = hi; k >= q; k--) swapPointers((long**)a[k], (long**)a[i++]);
QuicksortX(psaBSTRs, lo, j, d);
if ((i == hi) && (LPSTR(a[i])[d] == v)) i++;
if (v != 0) QuicksortX(psaBSTRs, j+1, i-1, d+1);
QuicksortX(psaBSTRs, i, hi, d);
}
I call the function in the DLL from Excel VBA like so:
Public Declare Function QuicksortX Lib "StringArraySort" (StringArray$(), Optional ByVal Lo&, Optional ByVal Hi&, Optional ByVal d& = 0) As Long
Sub Test_1()
Dim ret&, a() As String
ReDim a(0 To 9)
a(0) = "Riverside"
a(1) = "Irvine"
a(2) = "Capital"
a(3) = "Kona"
a(4) = "Mayberry"
a(5) = "Winterhaven"
a(6) = "Stillwater"
a(7) = "Dallas"
a(8) = "Roanoke"
a(9) = "Arbor"
ret = QuicksortX(a, LBound(a), UBound(a))
Stop
End Sub
However, the elements get scrambled. After calling the DLL the array looks like this:
a(0) = Arborside
a(1) = Capine
a(2) = Dalltal
a(3) = Irvi
a(4) = Konaerry
a(5) = Mayberhaven
a(6) = Rivelwater
a(7) = Roanas
a(8) = Stiloke
a(9) = Wintr
It looks like the left four characters of each element get sorted, but the rest of the characters remain unsorted.
Can you please help me fix the port so that it works correctly?
Upvotes: 1
Views: 202