Гибридная сортировка слияния и вставки

#c #algorithm #sorting #mergesort #insertion-sort

Вопрос:

Я пытаюсь реализовать гибрид сортировки слияния и вставки. Когда размер подмассива становится ниже порогового значения, он должен переключиться на сортировку вставки. Однако я пробовал использовать множество массивов разной длины и разной пороговой величины, и в большинстве случаев нет никакой заметной разницы, кроме 2-3 меньших сравнений. Мне сказали, что переключение на сортировку вставки для массива меньшего размера очень помогло бы.

Я делаю это неправильно?

 #include <iostream>


int comparisons = 0;
int swaps = 0;

void mergesort(int x[], int l, int r);
void insertionSort(int x[],int start, int end);

int main() {
  int x[] = {9,5,1,4,3,10,29,69,5,9,11,19,21,69,0,2,3,4,5,11,111,96,25,32,21,2,12,3,52,55,23,32,15,15,14,13,9,5,1,4,3,10,29,69,5,9,11,19,21,69,0,2,3,4,5,11,111,96,25,32,21,2,12,3,52,55,23,32,15,15,14,13,};

  // insertionSort(x,10);
  int sizeX= sizeof(x)/sizeof(x[0]) ;
  mergesort(x, 0, sizeX-1);

  for(int i =0;i<sizeX;i  ){
    std::cout << x[i] << " ";
  }
  // std::cout << "nSWAPS: " << swaps;
  std::cout << "nCOMPARISONS: " << comparisons;
}


void insertionSort(int arr[], int start,int end)
{
    int i, key, j;
    for (i = start  1 ; i < end; i  )
    {
        key = arr[i];
        j = i - 1;
 
        /* Move elements of arr[0..i-1], that are
        greater than key, to one position ahead
        of their current position */
        while (j >= 0 amp;amp; arr[j] > key)
        {
            comparisons  ;

            arr[j   1] = arr[j];
            j = j - 1;
        }
        arr[j   1] = key;
    }
}

void insertionSort2(int x[],int start, int end){
  for(int i =start; i < end;i  ){
    for (int j= i; j!= 0;j--){
      comparisons  ;

      if(x[j] < x[j-1]){
        int temp = x[j-1];
        x[j-1] = x[j];
        x[j] = temp;
        swaps  ;
      }
      else{
        break;
      }
    }
  }
}


void mergesort(int x[], int l, int r) {
  if (l >= r)
    return;

  int mid = (l   r) / 2;

  if(r - l  < 3){
    insertionSort(x, l,r 1);
  }else{
    mergesort(x, l, mid);
    mergesort(x, mid   1, r);

    int i = l; 
    int j = mid   1; 
    int k = 0; 

    int tmp[r - l   1];

    while (i <= mid amp;amp; j <= r) {
      comparisons  ;
      if (x[i] >= x[j]) {
        tmp[k] = x[j];
        j  ;
      } else {
        tmp[k] = x[i];
        i  ;
      }
      swaps  ;
      k  ;
    }

    while (i <= mid) {
      tmp[k] = x[i];
      i  ;
      k  ;
    }

    while (j <= r) {
      tmp[k] = x[j];
      j  ;
      k  ;
    }

    for (i = 0; i < k; i  ) x[l   i] = tmp[i];
  }
}
 

Комментарии:

1. «Однако я попробовал с кучей массивов разной длины и разной пороговой величины» — не могли бы вы быть более конкретным, чем «куча»? Каковы наименьшие и наибольшие пороговые суммы, которые вы пробовали? (Я ожидал бы очень небольшой разницы с вашим текущим порогом 3. С таким коротким массивом даже пузырьковая сортировка работает хорошо.)

2. Я попробовал использовать несколько тысяч элементов, которые я произвольно сгенерировал с веб-сайта, и попробовал от 3 до 150, и mergesort сделал все возможное

3. Я пробовал с несколькими тысячами элементов -это вряд ли что-то. Также это: int tmp[r - l 1]; недопустим C . Массивы в C должны иметь размер, обозначаемый выражением во время компиляции, а не вычисляемым значением во время выполнения. Используйте std::vector вместо этого.

4. @PaulMcKenzie какой размер массива я должен попробовать? Да, вы правы, это недопустимый C . По какой-то причине он компилируется и правильно запускается в replt

5. Это связано с тем, что компилятор, который вы используете, использует массивы переменной длины, которые не являются частью стандартного C . Если вы скомпилировали с использованием соответствующих переключателей компилятора или просто использовали Visual C , вы увидите, что ваш код не удалось скомпилировать.