Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

294 lines
8.5 KiB

/*++
Copyright (c) 1998, Microsoft Corporation
Module Name:
sort.c
Abstract:
This module contains routines used for efficiently sorting information.
Author:
Abolade Gbadegesin (aboladeg) 18-Feb-1998
Based on version written for user-mode RAS user-interface.
(net\routing\ras\ui\common\nouiutil\noui.c).
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
NTSTATUS
ShellSort(
VOID* pItemTable,
ULONG dwItemSize,
ULONG dwItemCount,
PCOMPARE_CALLBACK CompareCallback,
VOID* pDestinationTable OPTIONAL
)
/* Sort an array of items in-place using shell-sort.
** This function calls ShellSortIndirect to sort a table of pointers
** to table items. We then move the items into place by copying.
** This algorithm allows us to guarantee that the number
** of copies necessary in the worst case is N + 1.
**
** Note that if the caller merely needs to know the sorted order
** of the array, ShellSortIndirect should be called since that function
** avoids moving items altogether, and instead fills an array with pointers
** to the array items in the correct order. The array items can then
** be accessed through the array of pointers.
*/
{
VOID** ppItemTable;
LONG N;
LONG i;
UCHAR *a, **p, *t = NULL;
if (!dwItemCount) { return STATUS_SUCCESS; }
/* allocate space for the table of pointers.
*/
ppItemTable =
ExAllocatePoolWithTag(
NonPagedPool,
dwItemCount * sizeof(VOID*),
NAT_TAG_SORT
);
if (!ppItemTable) { return STATUS_NO_MEMORY; }
/* call ShellSortIndirect to fill our table of pointers
** with the sorted positions for each table element.
*/
ShellSortIndirect(
pItemTable, ppItemTable, dwItemSize, dwItemCount, CompareCallback );
/* now that we know the sort order, move each table item into place.
** This is easy if we are sorting to a different array.
*/
if (pDestinationTable) {
for (i = 0; i < (LONG)dwItemCount; i++)
{
RtlCopyMemory(
(PUCHAR)pDestinationTable + i * dwItemSize,
ppItemTable[i],
dwItemSize
);
}
ExFreePool(ppItemTable);
return STATUS_SUCCESS;
}
/* We are sorting in-place, which is a little more involved.
** This involves going through the table of pointers making sure
** that the item which should be in 'i' is in fact in 'i', moving
** things around if necessary to achieve this condition.
*/
a = (UCHAR*)pItemTable;
p = (UCHAR**)ppItemTable;
N = (LONG)dwItemCount;
for (i = 0; i < N; i++)
{
LONG j, k;
UCHAR* ai = (a + i * dwItemSize), *ak, *aj;
/* see if item 'i' is not in-place
*/
if (p[i] != ai)
{
/* item 'i' isn't in-place, so we'll have to move it.
** if we've delayed allocating a temporary buffer so far,
** we'll need one now.
*/
if (!t) {
t =
ExAllocatePoolWithTag(
NonPagedPool,
dwItemSize,
NAT_TAG_SORT
);
if (!t) {
ExFreePool(ppItemTable);
return STATUS_NO_MEMORY;
}
}
/* save a copy of the item to be overwritten
*/
RtlCopyMemory(t, ai, dwItemSize);
k = i;
ak = ai;
/* Now move whatever item is occupying the space where it should be.
** This may involve moving the item occupying the space where
** it should be, etc.
*/
do
{
/* copy the item which should be in position 'j'
** over the item which is currently in position 'j'.
*/
j = k;
aj = ak;
RtlCopyMemory(aj, p[j], dwItemSize);
/* set 'k' to the position from which we copied
** into position 'j'; this is where we will copy
** the next out-of-place item in the array.
*/
ak = p[j];
k = (ULONG)(ak - a) / dwItemSize;
/* keep the array of position pointers up-to-date;
** the contents of 'aj' are now in their sorted position.
*/
p[j] = aj;
} while (ak != ai);
/* now write the item which we first overwrote.
*/
RtlCopyMemory(aj, t, dwItemSize);
}
}
if (t) { ExFreePool(t); }
ExFreePool(ppItemTable);
return STATUS_SUCCESS;
}
VOID
ShellSortIndirect(
VOID* pItemTable,
VOID** ppItemTable,
ULONG dwItemSize,
ULONG dwItemCount,
PCOMPARE_CALLBACK CompareCallback
)
/* Sorts an array of items indirectly using shell-sort.
** 'pItemTable' points to the table of items, 'dwItemCount' is the number
** of items in the table, and 'CompareCallback' is a function called
** to compare items.
**
** Rather than sort the items by moving them around,
** we sort them by initializing the table of pointers 'ppItemTable'
** with pointers such that 'ppItemTable[i]' contains a pointer
** into 'pItemTable' for the item which would be in position 'i'
** if 'pItemTable' were sorted.
**
** For instance, given an array pItemTable of 5 strings as follows
**
** pItemTable[0]: "xyz"
** pItemTable[1]: "abc"
** pItemTable[2]: "mno"
** pItemTable[3]: "qrs"
** pItemTable[4]: "def"
**
** on output ppItemTable contains the following pointers
**
** ppItemTable[0]: &pItemTable[1] ("abc")
** ppItemTable[1]: &pItemTable[4] ("def")
** ppItemTable[2]: &pItemTable[2] ("mno")
** ppItemTable[3]: &pItemTable[3] ("qrs")
** ppItemTable[4]: &pItemTable[0] ("xyz")
**
** and the contents of pItemTable are untouched.
** And the caller can print out the array in sorted order using
** for (i = 0; i < 4; i++) {
** printf("%s\n", (char *)*ppItemTable[i]);
** }
*/
{
/* The following algorithm is derived from Sedgewick's Shellsort,
** as given in "Algorithms in C++".
**
** The Shellsort algorithm sorts the table by viewing it as
** a number of interleaved arrays, each of whose elements are 'h'
** spaces apart for some 'h'. Each array is sorted separately,
** starting with the array whose elements are farthest apart and
** ending with the array whose elements are closest together.
** Since the 'last' such array always has elements next to each other,
** this degenerates to Insertion sort, but by the time we get down
** to the 'last' array, the table is pretty much sorted.
**
** The sequence of values chosen below for 'h' is 1, 4, 13, 40, 121, ...
** and the worst-case running time for the sequence is N^(3/2), where
** the running time is measured in number of comparisons.
*/
ULONG dwErr;
LONG i, j, h, N;
UCHAR* a, *v, **p;
a = (UCHAR*)pItemTable;
p = (UCHAR**)ppItemTable;
N = (LONG)dwItemCount;
/* Initialize the table of position pointers.
*/
for (i = 0; i < N; i++) { p[i] = (a + i * dwItemSize); }
/* Move 'h' to the largest increment in our series
*/
for (h = 1; h < N/9; h = 3 * h + 1) { }
/* For each increment in our series, sort the 'array' for that increment
*/
for ( ; h > 0; h /= 3)
{
/* For each element in the 'array', get the pointer to its
** sorted position.
*/
for (i = h; i < N; i++)
{
/* save the pointer to be inserted
*/
v = p[i]; j = i;
/* Move all the larger elements to the right
*/
while (j >= h && CompareCallback(p[j - h], v) > 0)
{
p[j] = p[j - h]; j -= h;
}
/* put the saved pointer in the position where we stopped.
*/
p[j] = v;
}
}
}