合并排序性能与插入排序相比

时间:2017-07-24 23:18:57

标签: mergesort insertion-sort

对于任何长度大于10的数组,可以肯定地说,合并排序在数组元素之间执行的比较少于在同一数组上执行插入排序的比较,因为合并排序的运行时间的最佳情况对于插入排序,它是O(N log N),它的O(N)?

1 个答案:

答案 0 :(得分:0)

我对此的看法。首先,你谈论的是比较,但也存在掉期问题。

在最坏情况下的插入排序(按相反方向排序的数组)中,您必须进行n^2 - n 比较和交换(11 ^ 2 - 11 = 121 - 11 = 110表示11个元素,例如)。但是,如果阵列甚至按需要的顺序进行部分分类(我的意思是许多元素已经保持在正确的位置或者甚至离它们不远),则交换和比较的数量可能会显着下降。很快就会找到元素的正确位置,并且不需要执行与按相反顺序排序的数组一样多的动作。因此,正如您可以看到几乎已排序的arr2操作数将变为线性(相对于输入大小) - 6

var arr1 = [11,10,9,8,7,6,5,4,3,2,1];
var arr2 = [1,2,3,4,5,6,7,8,11,10,9];

function InsertionSort(arr) {
    var arr = arr, compNum = 0, swapNum = 0;
    for(var i = 1; i < arr.length; i++) {
        var temp = arr[i], j = i - 1;
        while(j >= 0) {
            if(temp < arr[j]) { arr[j + 1] = arr[j]; swapNum++; } else break;
            j--;
            compNum++;
        }
        arr[j + 1] = temp;
    }
    console.log(arr, "Number of comparisons: " + compNum, "Number of swaps: " + swapNum);
}
InsertionSort(arr1); // worst case, 11^2 - 11 = 110 actions
InsertionSort(arr2); // almost sorted array, few actions

在合并排序中,我们总是做aprox。 n*log n个动作 - 输入数组的属性无关紧要。因此,正如您在两种情况下都可以看到的那样我们将在39个操作中对两个数组进行排序

var arr1 = [11,10,9,8,7,6,5,4,3,2,1];
var arr2 = [1,2,3,4,5,6,7,8,11,10,9];
var actions = 0;
function mergesort(arr, left, right) {
  if(left >= right) return;
  var middle = Math.floor((left + right)/2);
  mergesort(arr, left, middle);
  mergesort(arr, middle + 1, right);
  merge(arr, left, middle, right);
}
function merge(arr, left, middle, right) {
  var l = middle - left + 1, r = right - middle, temp_l = [], temp_r = [];
  for(var i = 0; i < l; i++) temp_l[i] = arr[left + i];
  for(var i = 0; i < r; i++) temp_r[i] = arr[middle + i + 1];
  var i = 0, j = 0, k = left;
  while(i < l && j < r) {
    if(temp_l[i] <= temp_r[j]) {
    arr[k] = temp_l[i]; i++;
    } else {
    arr[k] = temp_r[j]; j++;  
    }
  k++; actions++; 
  }
  while(i < l) { arr[k] = temp_l[i]; i++; k++; actions++;}
  while(j < r) { arr[k] = temp_r[j]; j++; k++; actions++;}
}
mergesort(arr1, 0, arr1.length - 1);
console.log(arr1, "Number of actions: " + actions); // 11*log11 = 39 (aprox.)
actions = 0;
mergesort(arr2, 0, arr2.length - 1);
console.log(arr2, "Number of actions: " + actions); // 11*log11 = 39 (aprox.)

所以,回答你的问题:

  

对于任何长度大于10的数组,可以肯定地说,合并排序在数组元素之间执行的比较少于在同一数组上插入排序的比较

我会说不,这样说是不安全的。在某些情况下,与插入排序相比,合并排序可以执行更多操作。数组的大小在这里并不重要。在比较插入排序与合并排序的特定情况下,重要的是排序状态与数组的距离。我希望它有所帮助:)

BTW,合并排序和插入排序已合并在一个名为Timsort的混合稳定排序算法中,以便从两者中获得最佳效果。如果有兴趣,请查看。