简体   繁体   中英

Why is my Radix Sort JAVA implementation slower than Quick sort?

I'm trying to write radix code using ByteBuffer.allocate()
I've learnt that radix sort's time complexity is O(kn) and I wrote this code to make k=4.
I also wrote quick sort and figured out my radix sort is 2~3 times slower than quick sort.
Is it because of inefficient memory access?
Here's my radix sort code.

private static int[] radixSort(int[] value)
{

    byte[][] valueByBytes = new byte[value.length][4];
    for (int i=0; i<value.length; i++) {
        valueByBytes[i] = ByteBuffer.allocate(4).putInt(value[i]).array();
    }

    for (int key = 3; key >=0; key--) {
        valueByBytes = countingSort(valueByBytes, key);
    }

    for (int i=0; i<value.length; i++) {
        value[i] = ByteBuffer.wrap(valueByBytes[i]).getInt();
    }
    return (value);
}

private static byte[][] countingSort(byte[][] valueByBytes, int key) {
    int[] countingArr = new int[256]; // 0 ~ 255
    byte[][] toReturnArr = new byte[valueByBytes.length][4];
    for (int i=0; i<256; i++) {
        countingArr[i] = 0;
    }

    int[] intArr = new int[valueByBytes.length];

    if (key > 0) {
        for (int j=0; j<valueByBytes.length; j++) {
            intArr[j] = (int) valueByBytes[j][key] >= 0 ? valueByBytes[j][key] : 256+valueByBytes[j][key];
        }
    }
    else {
        for (int j=0; j<valueByBytes.length; j++) {
            intArr[j] = (int) valueByBytes[j][key] + 128;
        }
    }

    for (int j=0; j<intArr.length; j++) {
        countingArr[intArr[j]]++;
    }

    for (int i=1; i<256; i++) {
        countingArr[i] = countingArr[i-1] + countingArr[i];
    }

    for (int j=intArr.length-1; j>=0; j--) {
        toReturnArr[countingArr[intArr[j]]-1] = valueByBytes[j];
        countingArr[intArr[j]]--;
    }

    return toReturnArr;
}

Radix sort takes O(x k n) time. Where K is number of digits. Quick sort takes O(y n log n) where x > y, extracting bits out of a longer key is may be an expensive operation. Overheads used here may be causing trouble in your case.

You can get more answers by referring this question When should we use Radix sort?

Using ByteBuffer along with all the copy|convert operations is slowing down the radix sort. I tested sorting 16777216 integers, and on my system, (Intel 3770K, Windows 7 Pro 64 bit, Netbeans 8.2), the question's radix sort takes about 16.7 seconds, while the implementation of radix sort shown below takes about 0.55 seconds (about 30 times faster), while the implementation of quicksort shown below takes about 1.8 seconds.

package x;
import java.util.Random;

public class x {

    public static void RadixSort(int[] a)
    {
        int count = a.length;
        if(count < 2)
            return;
        int[] b = new int[count];           // allocate working array
        int [][] mIndex = new int[4][256];  // histograms | indexes
        int i,j,m,n,u;
        for(i = 0; i < count; i++){         // generate histograms
            u = a[i];
            mIndex[0][u&0xff]++;
            u >>= 8;
            mIndex[1][u&0xff]++;
            u >>= 8;
            mIndex[2][u&0xff]++;
            u >>= 8;
            mIndex[3][u+128]++;
        }
        for(j = 0; j < 4; j++){             // convert to indices
            m = 0;
            for(i = 0; i < 256; i++){
                n = mIndex[j][i];
                mIndex[j][i] = m;
                m += n;
            }       
        }
        for(i = 0; i < count; i++){         //  radix sort
            u = a[i];
            m = u&0xff;
            b[mIndex[0][m]++] = u;
        }
        for(i = 0; i < count; i++){
            u = b[i];
            m = (u>>8)&0xff;
            a[mIndex[1][m]++] = u;
        }
        for(i = 0; i < count; i++){
            u = a[i];
            m = (u>>16)&0xff;
            b[mIndex[2][m]++] = u;
        }
        for(i = 0; i < count; i++){
            u = b[i];
            m = (u>>24)+128;
            a[mIndex[3][m]++] = u;
        }
    }

    public static void main(String[] args) {
        int[] a = new int[16*1024*1024];
        Random r = new Random(0);
        for(int i = 0; i < a.length; i++)
            a[i] = r.nextInt();
        long bgn, end;
        bgn = System.currentTimeMillis();
        RadixSort(a);
        end = System.currentTimeMillis();
        for(int i = 1; i < a.length; i++){
            if(a[i-1] > a[i]){
                System.out.println("failed");
                break;
            }
        }
        System.out.println("milliseconds " + (end-bgn));
    }
}

    @SuppressWarnings("empty-statement")
    public static void qsort(int[] a, int lo, int hi)
    {
        if(lo >= hi)
            return;
        int  p = a[lo+(hi-lo)/2];
        int  i = lo-1;
        int  j = hi+1;
        int t;
        while(true){                // partition
            while(a[++i] < p);
            while(a[--j] > p);
            if(i >= j)
                break;
            t     = a[i];
            a[i] = a[j];
            a[j] = t;
        }
        qsort(a, lo, j);
        qsort(a, j+1, hi);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM