2015-11-29 2 views
0

Я пытаюсь написать шаблонную функцию на C++, которая может принимать массив любого типа и сортировать его. Используемая сортировка должна быть быстрой сортировкой или сортировкой слияния, но у меня возникли проблемы с реализацией любого из них, так как быстрый заголовок сортировки обычно имеет верхний и нижний параметр, а сортировка слияния - с первый и последний параметр. Мой заголовок функции выглядит следующим образом: недействительный mySort (T * массив, Int N)Templated Quick/Merge Sort

До сих пор у меня есть это:

template <typename T> 
void sort(T *a, int n) 
{ 
    int i = 0; 
    int j = n-1; 
    int tmp; 
    int pivot = a[(n-1)/2]; 
    while (i <= j){ 
    while (a[i] < pivot) 
     i++; 
    while (a[j] > pivot) 
     j--; 
    if (i<=j){ 
     tmp = a[i]; 
     a[i] = a[j]; 
     a[j] = a[i]; 
     i++; 
     j--; 
    } 
    } 

    if(0<j) 
    sort(a, j); 
    /* 
    if(i<right) 
    sort(
    */ 
} 

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

+0

вы уже знаете, что оба вида нужны первые и последние параметры, до сих пор вы код их не имеют, только массив и размер. Зачем? – VillasV

+0

Вам нужно также остановить рекурсию, когда n становится слишком маленьким. Например, когда 'j == 1' вы удовлетворены' 0 JSF

+0

Если вы игнорируете любые знания, которые могут иметь о том, где находится элемент опоры, и игнорировать любые проблемы с рекурсией, тогда вторая сортировка будет «sort (a + j, n-j);». (Не говорите, что вы обязательно должны игнорировать эти вещи, просто отвечая на то, что вы, похоже, спрашиваете). – JSF

ответ

0

Прежде чем отвечать на реальный вопрос: ваш код выиграет от факторинга кода раздела из тела функции! Таким образом, вы бы по существу назвать раздел, чтобы определить среднюю точку между двумя массивами можно назвать, например, вы бы что-то вроде этого:

template <typename T> 
void sort(T* a, int n) { 
    T* mid = partition(a, n); 
    // ... 
} 

Идея заключается в том, что [a, mid) содержит все элементы сортировки меньше чем точка поворота, а [mid, a + n) содержит все элементы, которые сортируются равными или большими, чем точка поворота. Все, что остается

  1. Вызов sort() рекурсивно с двумя массива, т.е.

    sort(a, mid - a); 
    sort(mid, (a + n) - mid); 
    
  2. Убедитесь sort() заканчивается, если массив получается мало чем 2.

Of Конечно, если вы хотите, чтобы ваш Быстрый Сортировка был быстро, вам также понадобится вытащить полдюжины или около того трюков. Как:

  1. Используйте Introsort, чтобы гарантировать сложность является O(n lg n) (например, вместе с Merge Sort).
  2. Использование Вставка Сортировка по небольшим диапазонам.
  3. Используйте реализацию разделения разделов и вставок, используя подходящие стражи.
  4. Сортировать действительно сортировать диапазоны напрямую.

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

+0

@rcgldr: Конечно - оригинальная бумага почти наверняка использовала массив с индексами. Оказывается, что с помощью указателей на самом деле _does_ просто алгоритмы, такие как 'partition()' и 'qsort()'. –

+0

Удалил мой предыдущий комментарий. Для этой конкретной схемы, когда выполняются рекурсивные вызовы, (i-j) == 1 или (i-j) == 2, в зависимости от значений рядом с точкой поворота. – rcgldr

0

Отдельные вызываемая функция из рекурсивной функции:

// recursive function 
template <typename T> 
void quicksort(T *a, int lo, int hi) 
{ 
    // ... 
} 

// called function  
template <typename T> 
void sort(T *a, int n) 
{ 
    if(n < 2)return; 
    quicksort(a, 0, n-1); 
}