Quicksort (n массивов следует рассматривать как 1 и значения переназначить по мере необходимости)

У меня есть связанный список массивов (структура внизу сообщения)

Каждый массив может иметь значения, подобные приведенному ниже примеру

Array1[] = {6,36,8,23};
Array2[] = {8,23,5,73};
Array3[] = {2,5,1,9};

Мне нужно отсортировать их так, чтобы все 3 массива обрабатывались как один большой массив...

Мне нужно использовать quicksort, чтобы он использовал обработку на месте... Я работаю с очень большими массивами и не могу позволить себе использовать дополнительную память.

Результат должен быть примерно таким

Array1[] = {1,2,5,5};
Array2[] = {6,8,8,9};
Array3[] = {23,23,36,73};

В настоящее время я могу сортировать каждый массив отдельно... но это не совсем то, что мне нужно: (

struct iSection {
    unsigned long     Section_Count; // Total # of points in this block of memory

    int              *Section_Arr;   // Point cloud for current block of memory
    struct iSection  *Next;          // Pointer to next section
} iSection;


struct iDatabase {
    struct iSection     *First_Section;
    struct iSection     *Last_Section;
} iDatabase;

Ответы

Ответ 1

Это не так сложно, скорее проблема сопряжения, а затем проблема с алгоритмикой.

Напишите контейнер-оболочку, предоставляющий интерфейс для доступа к элементам и записи (скажем operator[] в С++), и внутренне он сопоставляет аргумент size_t index правильному массиву. Этот класс-оболочка нуждается в размере каждого массива, чтобы иметь возможность правильно отображать индекс.

Пример псевдокодного оператора []:

int& JointDatabase::operator[](size_t index) {
    // database is an iDatabase
    iSection *cur = database.First_Section;

    while (cur != database.Last_Section && index >= cur->Section_Count) {
        index -= cur->Section_Count;
        cur = cur->Next;
    }

    return cur->Section_Arr[index];
}

Затем используйте этот класс-оболочку, поскольку вы должны использовать обычный контейнер в своем алгоритме Quicksort.

Ответ 2

Если вы можете убедиться, что Array1, Array2, and Array3 объявлены один за другим и в макете непрерывной памяти, вы можете дать Array1 (первый) в sort() и дать объединенный размер всех массивов.

Чтобы проверить непрерывное выравнивание, вы можете использовать следующий трюк.

template<size_t SIZE1, size_t SIZE2, size_t SIZE3>
bool Check(int (&a1)[SIZE1], int (&a2)[SIZE2], int (&a3)[SIZE3])
{
  return (&a3[SIZE3 - 1] - &a1[0]) == (SIZE1 + SIZE2 + SIZE3);
}

Использование

bool aligned = Check(Array1, Array2, Array3);

Это пример для 3 массивов, вы можете сделать это в соответствии с вашими потребностями. И вы можете передать Array1,2,3 или Array3,2,1 в зависимости от вашей машины.

Ответ 3

Протестировано только в моем мозгу:

struct ArrayWrapper {
    int** arrays;
    int* running_sums;
    ArrayWrapper(int **arrays, int *arrays_length, int N) {
        running_sums = new int*[N+1];
        int sum = 0;
        for (int i = 0; i < N; i++) {
            running_sums[i+1] = sum;
            sum += arrays_length[i];
        }
    }
    int& operator[] (int index) {
        int array_start = binary search `running_sum` for the closest number to `index` (round down)
        return arrays[array_start][index - running_sums[array_start]]
    }
}

так что если у вас есть что-то вроде:

array1 = {...} 
array2 = {...}
...
arrayN = {...}

arrays = {array1, array2, ..., arrayN}
arrays_length = {array1_length, array2_length, ..., arrayN_length}

ArrayWrapper wrapper = new ArrayWrapper(arrays, arrays_length, N);
// wrapper then can be treated like normal array:
wrapper[10] = x;
x = wrapper[10];