Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sorting 为什么插入排序比合并排序快?_Sorting_Mergesort_Bubble Sort_Insertion Sort_Jsperf - Fatal编程技术网

Sorting 为什么插入排序比合并排序快?

Sorting 为什么插入排序比合并排序快?,sorting,mergesort,bubble-sort,insertion-sort,jsperf,Sorting,Mergesort,Bubble Sort,Insertion Sort,Jsperf,我在jsperf.com上为3种排序方法创建了测试:冒泡、插入和合并 在测试之前,我创建了随机数为0到1Mln的未排序数组。 每次测试都显示插入排序比合并排序快。 如果合并排序时间为O(n log(n)),而插入排序和冒泡排序时间为O(n^2),那么产生这种结果的原因是什么 没有更多的测试,一个初步的答案是: 您的插入排序相当优化-您只是切换元素。合并排序使用[]实例化新数组,并使用slice和concat创建新数组,这是一个巨大的内存管理开销,更不用说concat和slice内部有隐式循环(尽

我在jsperf.com上为3种排序方法创建了测试:冒泡、插入和合并

在测试之前,我创建了随机数为0到1Mln的未排序数组。 每次测试都显示插入排序比合并排序快。 如果合并排序时间为O(n log(n)),而插入排序和冒泡排序时间为O(n^2),那么产生这种结果的原因是什么
没有更多的测试,一个初步的答案是:


您的插入排序相当优化-您只是切换元素。合并排序使用
[]
实例化新数组,并使用
slice
concat
创建新数组,这是一个巨大的内存管理开销,更不用说
concat
slice
内部有隐式循环(尽管在本机代码中)。合并排序在适当位置完成时是有效的;随着所有复制的进行,这将大大降低您的速度。

正如Amadan所评论的,merge sort最好一次性分配与要排序的数组相同的大小。自顶向下的合并排序使用递归生成合并使用的索引,而自底向上跳过递归并使用迭代生成索引。大部分时间将用于子阵列的实际合并,因此自顶向下在较大阵列(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
        }
    }
}
void MergeSort(int a[],size\t n)//输入函数
{
if(n<2)//if size<2返回
回来
int*b=新的int[n];
BottomUpMergeSort(a、b、n);
删除[]b;
}
size_t GetPassCount(size_t n)//返回#个过程
{
尺寸i=0;
对于(尺寸s=1;s这很有趣。我看不到任何明显的迹象,但所有这些都可以优化,提高它们的时间。您的合并排序不到位,因此需要数百万次分配,因此速度慢并不令人震惊。因此,您的意思是,在这种特定情况下,对数字数组进行排序,合并排序不是合适的解决方案?合并排序是一个好的解决方案;它只是比插入排序更难优化实现。也许我需要在没有concat和slice方法的情况下重写Merge sort?@MalikNur:并且可能每次都重复使用相同的几个数组。我认为是内存缓存杀死了它。有很好的讨论,并链接到描述就地合并排序算法的论文。最好的一个是AFAIK,它有两个相同大小的阵列,其中一个成为工作区以避免过度交换。