基数排序,一种很费内存但是快得一塌糊涂的排序算法。

测试用例为两千万的int数组,使用随机数生成器生成整个数组的数值,测试结果为:

堆排序14.8秒;

qsort库函数6.4秒;

归并排序4.4秒;

快速排序版本1为2.7秒;

快速排序版本2为2.7秒;

二进制快速排序为4.8秒;

基数排序为0.95秒,大比分领先于其他常见排序算法。

附:测试代码如下(gcc -O3 test.c -o test.exe)

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h>
#include <string.h>
#include <windows.h>

#define NUMS 20000000

void maxHeapify(int a[], int i, int n)
{
    int j, temp;
    while(2*i + 1 < n)
    {
        j = 2*i + 1;
        if(j + 1 < n && a[j] < a[j+1])
        {
            ++j;
        }
        if(a[i] >= a[j])
        {
            break;
        }
        temp = a[i];
        a[i] = a[j];
        a[j] = temp;
        i = j;
    }
}

void generateMaxHeap(int h[], int n)
{
    int i;
    for(i = n/2 - 1; i >= 0; --i)
    {
        maxHeapify(h, i, n);
    }
}

void heapSort(int h[], int n)
{
    int temp;
    generateMaxHeap(h, n);
    while(n > 1)
    {
        temp = h[0];
        h[0] = h[n - 1];
        h[n - 1] = temp;
        --n;
        maxHeapify(h, 0, n);
    }
}

int bigRand()
{
    int i = rand() * (RAND_MAX + 1) + rand();
    return i;
}

int intCmp(const void *a, const void *b)
{
    return *(int*)(a) - *(int*)(b);
}

void merge(int a[], int p, int m, int r)
{
    int *cl = (int*)malloc((m + 2 - p)* sizeof(int)), *cr = (int*)malloc((r - m + 1)* sizeof(int)), i, j = 0, k = 0;
    cl[m + 1 - p] = INT_MAX;
    cr[r - m] = INT_MAX;
    memcpy(cl, &a[p], (m + 1 - p)* sizeof(int));
    memcpy(cr, &a[m + 1], (r - m)* sizeof(int));
    for(i = 0; i < r - p + 1; ++i)
    {
        if(cl[j] <= cr[k])
        {
            a[p + i] = cl[j++];
        }
        else
        {
            a[p + i] = cr[k++];
        }
    }
    free(cl), free(cr);
}

void insertionSort(int a[], int n)
{
    int e, i, j;
    for(i = 1; i < n; ++i)
    {
        e = a[i];
        j = i;
        while(j > 0 && a[j - 1] > e)
        {
            a[j] = a[j - 1];
            --j;
        }
        a[j] = e;
    }
}

void mergeSort(int a[], int p, int r)
{
    if(r - p < 23)
    {
        insertionSort(&a[p], r - p + 1);
        return;
    }
    int m = p + (r - p) / 2;
    mergeSort(a, p, m);
    mergeSort(a, m + 1, r);
    merge(a, p, m, r);
}

int partition(int a[], int p, int r)
{
    int i = p, j, e = a[p], temp;
    for(j = p + 1; j <= r; ++j)
    {
        if(a[j] < e)
        {
            ++i;
            temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }
    }
    a[p] = a[i];
    a[i] = e;
    return i;
}

int hoarePartition(int a[], int p, int r)
{
    int i = p - 1, j = r, e = a[r], temp;
    while(1)
    {
        while(a[++i] < e);
        while(a[--j] > e)
        {
            if(j == p)
            {
                break;
            }
        }
        if(i >= j)
        {
            break;
        }
        temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
    a[r] = a[i];
    a[i] = e;
    return i;
}

void quickSort(int a[], int p, int r)
{
    if(r - p < 23)
    {
        insertionSort(&a[p], r - p + 1);
        return;
    }
    int m = partition(a, p, r);
    quickSort(a, p, m - 1);
    quickSort(a, m + 1, r);
}

void quickSortWithHoarePartition(int a[], int p, int r)
{
    if(r - p < 23)
    {
        insertionSort(&a[p], r - p + 1);
        return;
    }
    int m = hoarePartition(a, p, r);
    quickSortWithHoarePartition(a, p, m - 1);
    quickSortWithHoarePartition(a, m + 1, r);
}

void bubbleSort(int a[], int n)
{
    int i, j, temp;
    for(i = 1; i < n; ++i)
    {
        for(j = 0; j < n - i; ++j)
        {
            if(a[j] > a[j + 1])
            {
                temp = a[j];
                a[j] = a[j+1];
                a[j+1] = temp;
            }
        }
    }
}

#define BPW 32

int digit(int i, int w)
{
    i >>= w;
    return i & 1;
}

void binaryQuickSort(int a[], int p, int r, int w)
{
    int i = p, j = r, temp;
    if(p >= r || w < 0)
    {
        return;
    }
    while(1)
    {
        while(!digit(a[i], w) && i < j)
        {
            ++i;
        }
        while(digit(a[j], w) && i < j)
        {
            --j;
        }
        if(i == j)
        {
            break;
        }
        temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
    if(!digit(a[i], w))
    {
        ++i;
    }
    binaryQuickSort(a, p, i - 1, w - 1);
    binaryQuickSort(a, i, r, w - 1);
}

#define BPR 8

int getRadix(int num, int w)
{
    return (num>>(BPR*w)) & ((1<<BPR)-1);
}

void radixLSD(int a[], int n)
{
    int i, w, count[1<<BPR], *copy = (int*)malloc((n)*sizeof(int)), pos;
    for(w = 0; w < BPW/BPR; ++w)
    {
        memcpy(copy, a, n*sizeof(int));
        memset(count, 0, sizeof(count));
        for(i = 0; i < n; ++i)
        {
            ++count[getRadix(a[i], w)];
        }
        for(i = 1; i < 1<<BPR; ++i)
        {
            count[i] += count[i-1];
        }
        for(i = n-1; i >= 0; --i)
        {
            pos = --count[getRadix(copy[i], w)];
            a[pos] = copy[i];
        }
    }
    free(copy);
}

int main()
{
    unsigned t1, t2;
    srand(time(0));
    int *a = (int*)malloc(NUMS * sizeof(int)), i;

    for(i = 0; i < NUMS; ++i)
    {
        a[i] = bigRand();
    }
    t1 = GetTickCount();
    heapSort(a, NUMS);
    t2 = GetTickCount();
    printf("heapSort took %ums\n", t2 - t1);

    for(i = 0; i < NUMS; ++i)
    {
        a[i] = bigRand();
    }
    t1 = GetTickCount();
    qsort(a, NUMS, sizeof(int), intCmp);
    t2 = GetTickCount();
    printf("qsort took %ums\n", t2 - t1);

    for(i = 0; i < NUMS; ++i)
    {
        a[i] = bigRand();
    }
    t1 = GetTickCount();
    mergeSort(a, 0, NUMS - 1);
    t2 = GetTickCount();
    printf("mergeSort took %ums\n", t2 - t1);

    for(i = 0; i < NUMS; ++i)
    {
        a[i] = bigRand();
    }
    t1 = GetTickCount();
    quickSort(a, 0, NUMS - 1);
    t2 = GetTickCount();
    printf("quickSort took %ums\n", t2 - t1);

    for(i = 0; i < NUMS; ++i)
    {
        a[i] = bigRand();
    }
    t1 = GetTickCount();
    quickSortWithHoarePartition(a, 0, NUMS - 1);
    t2 = GetTickCount();
    printf("quickSortWithHoarePartition took %ums\n", t2 - t1);

    for(i = 0; i < NUMS; ++i)
    {
        a[i] = bigRand();
    }
    t1 = GetTickCount();
    binaryQuickSort(a, 0, NUMS - 1, BPW - 1);
    t2 = GetTickCount();
    printf("binaryQuickSort took %ums\n", t2 - t1);

    for(i = 0; i < NUMS; ++i)
    {
        a[i] = bigRand();
    }
    t1 = GetTickCount();
    radixLSD(a, NUMS);
    t2 = GetTickCount();
    printf("radixLSD took %ums\n", t2 - t1);
/*
    for(i = 0; i < NUMS; ++i)
    {
        printf("%d\n", a[i]);
    }
*/
    free(a);
    return 0;
}

 

posted @ 2012-12-11 21:45  knull  Views(616)  Comments(0)    收藏  举报