代码之家  ›  专栏  ›  技术社区  ›  Sazzad Hissain Khan

快速排序与合并排序性能分析

  •  2
  • Sazzad Hissain Khan  · 技术社区  · 7 年前

    合并排序的最坏情况复杂度为O(logN),而快速排序的最坏情况复杂度为O(N^2),因此理论上,合并排序应该比快速排序性能更好。但我听说,由于一些复制开销,大多数情况下,快速排序优于合并排序。 See the reference .

    然后我决定实现和测试,下面是我用C语言编写的完整源代码,

    #include <stdio.h>
    #include <time.h>
    
    #define SZ 10000000
    #define MOD 10000007
    #define i64 long long int
    
    i64 nums[SZ];
    
    i64 L[SZ], R[SZ];
    
    i64 seed = 0xff;
    i64 srand(){
        seed = (seed + 17 * seed) % MOD;
        return seed;
    }
    
    void make(){
        for (register int i = 0; i < SZ; i++)
            nums[i] = srand() % MOD;
    }
    
    void swap(i64 *a, i64 *b){
        i64 t = *a;
        *a = *b;
        *b = t;
    }
    
    int pivote(int s, int e){
    
        //int p = s + srand() % (e - s + 1);
        int p = s + (e - s) / 2;
        //int p = s;
        //int p = e;
    
        i64 v = nums[p];
        int c = s;
        swap(nums + p, nums + e);
        for (register int i = s; i < e; i++){
            if (nums[i] < v){
                swap(nums + i, nums + c);
                c++;
            }
        }
        swap(nums + c, nums + e);
        return c;
    }
    
    void qsort(int s, int e){
    
        if (s < e){
            int p = pivote(s, e);
            qsort(s, p - 1);
            qsort(p + 1, e);
        }
    }
    
    void merge(i64 arr[], int l, int m, int r){
        int i, j, k;
        int n1 = m - l + 1;
        int n2 = r - m;
    
        for (i = 0; i < n1; i++)
            L[i] = arr[l + i];
        for (j = 0; j < n2; j++)
            R[j] = arr[m + 1 + j];
    
        i = 0;
        j = 0;
        k = l;
        while (i < n1 && j < n2)
        {
            if (L[i] <= R[j])
            {
                arr[k] = L[i];
                i++;
            }
            else
            {
                arr[k] = R[j];
                j++;
            }
            k++;
        }
    
        while (i < n1)
        {
            arr[k] = L[i];
            i++;
            k++;
        }
    
        while (j < n2)
        {
            arr[k] = R[j];
            j++;
            k++;
        }
    }
    
    void mergeSort(i64 arr[], int l, int r){
        if (l < r){
            int m = l + (r - l) / 2;
    
            mergeSort(arr, l, m);
            mergeSort(arr, m + 1, r);
            merge(arr, l, m, r);
        }
    }
    
    
    void testQsort(){
        double s, e;
    
        make();
    
        s = clock();
        qsort(0, SZ - 1);
        e = clock();
        printf("qsort random: %Lf ms\n", (e - s) / 1);
    
        s = clock();
        qsort(0, SZ - 1);
        e = clock();
        printf("qsort sorted: %Lf ms\n", (e - s) / 1);
    
    }
    
    void testMsort(){
        double s, e;
    
        make();
    
        s = clock();
        mergeSort(nums, 0, SZ - 1);
        e = clock();
        printf("msort random: %Lf ms\n", (e - s) / 1);
    
        s = clock();
        mergeSort(nums, 0, SZ - 1);
        e = clock();
        printf("msort sorted: %Lf ms\n", (e - s) / 1);
    }
    
    int main(){
    
        testMsort();
        testQsort();
    
        return 0;
    }
    

    1000万个元素的结果:

    msort random: 4596.000000 ms
    msort sorted: 3354.000000 ms
    qsort random: 7637.000000 ms
    qsort sorted: 5074.000000 ms
    

    • 在第一个位置旋转
    • 在最后一个位置旋转
    • 中间位置转动

    没有一个版本的快速排序似乎优于合并排序。 有人能告诉我为什么提到快速排序优于合并排序吗?

    void qsort3(int s, int e){
        if (s < e){
            i64 p = nums[(s + e) / 2];
            int i = s - 1;
            int j = e + 1;
            while (true){
                while (nums[++i] < p);
                while (nums[--j] > p);
                if (i >= j) break;
                swap(nums + i, nums + j);
            }
            qsort3(s, j);
            qsort3(j + 1, e);
        }
    }
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   rcgldr    7 年前

    该问题的快速排序的例子是基于Lomuto划分方案,它比Hoare划分方案慢。链接到霍尔分区方案的示例:

    QuickSort with middle elemenet as pivot

    'MergeSort Algorithm' - What's the better implementation in JAVA?

    至于相对性能,一个简单的快速排序,如一个链接到这个答案是15%左右,比基本的合并排序排序一个简单的元素数组,如整数或浮点数。但是,如果增强了快速排序以避免最坏情况下的时间复杂度O(n^2),则优势会降低,主要优势是它不需要合并排序的合并操作所需的O(n)空间。一般来说,合并排序比快速排序做更多的移动,但比较少。如果对指向对象的指针数组进行排序,则比较开销将大于移动指针所需的时间,合并排序将更快。另一方面,排序指向对象的指针数组涉及对这些对象的随机访问,这对缓存不友好,而且排序对象比排序指针要快,除非对象相当大(根据系统的不同,这种折衷通常在128到256字节左右)。