Быстрая сортировка с вставкой Сортировка конца - где я иду не так? - PullRequest
0 голосов
/ 30 ноября 2010

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

Одно из требований заключается в том, что он должен сортировать массив из 5 000 000 точек менее чем за 1300 мс (это на стандартных компьютерах, поэтому скорость процессора не является проблемой). Прежде всего, я не могу заставить его работать на 5 000 000 из-за ошибки переполнения стека (слишком много рекурсивных вызовов ...). Если я увеличу размер кучи, я все равно буду работать намного медленнее.

Ниже приведен код. Кто-нибудь намекает на кого-нибудь?

Заранее спасибо

public class MyQuickSort {

    public static void sort(int [] toSort, int moveToInsertion)
    {
        sort(toSort, 0, toSort.length - 1, moveToInsertion);
    }

    private static void sort(int[] toSort, int first, int last, int moveToInsertion)
    {
        if (first < last)
        {
            if ((last - first) < moveToInsertion)
            {
                insertionSort(toSort, first, last);
            }
            else
            {
                int split = quickHelper(toSort, first, last);
                sort(toSort, first, split - 1, moveToInsertion);
                sort(toSort, split + 1, last, moveToInsertion);
            }
        }
    }

    private static int quickHelper(int[] toSort, int first, int last)
    {
        sortPivot(toSort, first, last);
        swap(toSort, first, first + (last - first)/2);
        int left = first;
        int right = last;
        int pivotVal = toSort[first];
        do
        {
            while ( (left < last) && (toSort[left] <= pivotVal)) 
            {
                left++;
            }

            while (toSort[right] > pivotVal) 
            {
                right--;
            }

            if (left < right) 
            { 
                swap(toSort, left, right); 
            }

        } while (left < right);

        swap(toSort, first, right);


        return right;
    }

    private static void sortPivot(int[] toSort, int first, int last)
    {
        int middle = first + (last - first)/2;

        if (toSort[middle] < toSort[first]) swap(toSort, first, middle);

        if (toSort[last] < toSort[middle]) swap(toSort, middle, last);

        if (toSort[middle] < toSort[first]) swap(toSort, first, middle);

    }

    private static void insertionSort(int [] toSort, int first, int last)
    {
         for (int nextVal = first + 1; nextVal <= last; nextVal++)
            {
                int toInsert = toSort[nextVal];
                int j = nextVal - 1;
                while (j >= 0 && toInsert < toSort[j])
                {
                    toSort[j + 1] = toSort[j];
                    j--;
                }
                toSort[j + 1] = toInsert;
            }
    }

    private static void swap(int[] toSort, int i, int j)
    {
        int temp = toSort[i];
        toSort[i] = toSort[j];
        toSort[j] = temp;
    }

}

Ответы [ 3 ]

0 голосов
/ 30 ноября 2010

Я не проверял это с вашим алгоритмом, и я не знаю, с каким набором данных вы работаете, но подумайте о выборе лучшей оси, чем самый левый элемент.Из Википедии о быстрой сортировке:

Выбор оси В очень ранних версиях быстрой сортировки крайний левый элемент раздела часто выбирался как элемент центра.К сожалению, это вызывает поведение в худшем случае для уже отсортированных массивов, что является довольно распространенным вариантом использования.Эта проблема была легко решена путем выбора случайного индекса для оси, выбора среднего индекса для раздела или (особенно для более длинных разделов) выбора медианы первого, среднего и последнего элемента раздела для центра

0 голосов
/ 30 ноября 2010

Разобрался.

На самом деле, это не моя вина. Я генерировал числа в диапазоне 0-100 (для тестирования, чтобы убедиться, что он был отсортирован). Это привело к множеству дубликатов, что означало путь ко многим разделам. Изменение диапазона на min_int и max_int сделало его намного быстрее.

Спасибо за вашу помощь, хотя: D

0 голосов
/ 30 ноября 2010

Когда входной массив большой, естественно ожидать, что рекурсивные функции сталкиваются с проблемами переполнения стека. что происходит здесь, когда вы пытаетесь с приведенным выше кодом. Я бы порекомендовал вам написать итерационную Quicksort, используя ваш собственный стек. Это должно быть быстро, потому что во время выполнения не выполняется выделение / освобождение кадров стека. Вы также не столкнетесь с проблемами переполнения стека. Производительность также зависит от того, в какой момент вы выполняете сортировку вставкой. У меня нет определенного размера ввода, где сортировка вставкой работает плохо по сравнению с быстрой сортировкой. Я бы посоветовал вам попробовать разные размеры, и я уверен, что вы заметите разницу.

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

Я не хочу делиться кодом, потому что это не заставит вас научиться конвертировать рекурсивную быструю сортировку в итеративную. Если у вас возникли проблемы с переходом на итеративный, дайте мне знать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...