2015-11-02 187 views
0

我在jsperf.com上測試了3種排序方法:Bubble,Insertion和Merge。 Link爲什麼插入排序比合並排序更快?

在測試之前,我使用從0到1Mln的隨機數創建未排序數組。 每次測試顯示Insertion排序比合並排序快。 什麼原因這樣的結果,如果歸併排序時間爲O(n的log(n)),而插入和氣泡各種具有爲O(n^2) test result here

+0

有趣。我沒有看到任何明顯的事情,但都可以優化,改善他們的時間。你的合併排序不合適,因此需要數百萬次的分配,所以並不令人感到震驚。 –

+0

所以你的意思是在這個特定的情況下,排序數組的數組,合併排序是不正確的解決方案? –

+1

合併排序是一個很好的解決方案;它比插入排序更難實現。 – Amadan

回答

0

沒有更多的測試,試探性的答案:

你插入排序相當優化 - 你只是開關元件。您的合併排序使用[]實例化新陣列,並使用sliceconcat創建新陣列,這是一個很大的內存管理開銷,更不用說concatslice(儘管在本機代碼中)存在隱式循環。合併排序在原地完成時效率很高;隨着所有複製的進行,這應該會讓你減慢很多。

+0

也許我需要重寫沒有concat和slice方法的合併排序? –

+0

@MalikNur:可能每次重複使用相同的幾個數組。我認爲內存緩存是什麼殺死它。 –

+1

是的。 http://stackoverflow.com/questions/2571049/how-to-sort-in-place-using-the-merge-sort-algorithm有很好的討論,並鏈接到描述就地合併排序算法的論文。最好的一個,AFAIK,是有兩個相同大小的陣列,其中一個成爲工作區域,以避免過度swappage。 – Amadan

0

正如Amadan所評論的那樣,合併排序最好與要排序的數組進行一次性分配。自頂向下合併排序使用遞歸生成合並使用的索引,而自下而上跳過遞歸併使用迭代生成索引。大部分時間將用於子陣列的實際合併,因此自頂向下在超大陣列(100萬或更多)上的額外開銷僅爲5%左右。

示例C++代碼,用於稍微優化自底向上合併排序。

void MergeSort(int a[], size_t n)   // entry function 
{ 
    if(n < 2)        // if size < 2 return 
     return; 
    int *b = new int[n]; 
    BottomUpMergeSort(a, b, n); 
    delete[] b; 
} 

size_t GetPassCount(size_t n)    // return # passes 
{ 
    size_t i = 0; 
    for(size_t s = 1; s < n; s <<= 1) 
     i += 1; 
    return(i); 
} 

void BottomUpMergeSort(int a[], int b[], size_t n) 
{ 
size_t s = 1;        // run size 
    if(GetPassCount(n) & 1){    // if odd number of passes 
     for(s = 1; s < n; s += 2)   // swap in place for 1st pass 
      if(a[s] < a[s-1]) 
       std::swap(a[s], a[s-1]); 
     s = 2; 
    } 
    while(s < n){       // while not done 
     size_t ee = 0;      // reset end index 
     while(ee < n){      // merge pairs of runs 
      size_t ll = ee;     // ll = start of left run 
      size_t rr = ll+s;    // rr = start of right run 
      if(rr >= n){     // if only left run 
       rr = n; 
       BottomUpCopy(a, b, ll, rr); // copy left run 
       break;      // end of pass 
      } 
      ee = rr+s;      // ee = end of right run 
      if(ee > n) 
       ee = n; 
      // merge a pair of runs 
      BottomUpMerge(a, b, ll, rr, ee); 
     } 
     std::swap(a, b);     // swap a and b 
     s <<= 1;       // double the run size 
    } 
} 

void BottomUpCopy(int a[], int b[], size_t ll, size_t rr) 
{ 
    while(ll < rr){       // copy left run 
     b[ll] = a[ll]; 
     ll++; 
    } 
} 

void BottomUpMerge(int a[], int b[], size_t ll, size_t rr, size_t ee) 
{ 
    size_t o = ll;       // b[]  index 
    size_t l = ll;       // a[] left index 
    size_t r = rr;       // a[] right index 
    while(1){        // merge data 
     if(a[l] <= a[r]){     // if a[l] <= a[r] 
      b[o++] = a[l++];    // copy a[l] 
      if(l < rr)      // if not end of left run 
       continue;     //  continue (back to while) 
      while(r < ee)     // else copy rest of right run 
       b[o++] = a[r++]; 
      break;       //  and return 
     } else {       // else a[l] > a[r] 
      b[o++] = a[r++];    // copy a[r] 
      if(r < ee)      // if not end of right run 
       continue;     //  continue (back to while) 
      while(l < rr)     // else copy rest of left run 
       b[o++] = a[l++]; 
      break;       //  and return 
     } 
    } 
} 
相關問題