簡體   English   中英

基數排序實現

[英]Radix sort implementation

我正在嘗試制作基數排序函數,該函數使用基數排序作為基數來計算整數的位數,然后將數字從最不重要到最重要。

我正在使用一個包含隨機整數的數組。

我怎樣才能使這種方法運作良好?

我正在使用此代碼:

public static void sort( int[] a, int radix)
    {
        int i, m = a[0], exp = 1, n = a.length;
        int[] b = new int[10];
        for (i = 1; i < n; i++)
            if (a[i] > m)
                m = a[i];
        while (m / exp > 0)
        {
            int[] bucket = new int[10];

            for (i = 0; i < n; i++)
                bucket[(a[i] / exp) % 10]++;
            for (i = 1; i < 10; i++)
                bucket[i] += bucket[i - 1];
            for (i = n - 1; i >= 0; i--)
                b[--bucket[(a[i] / exp) % 10]] = a[i];
            for (i = 0; i < n; i++)
                a[i] = b[i];
            exp *= 10;        
        }
    }    

我只是指出最明顯的問題,把細節留給你。

每個存儲桶都必須保存一個數字列表,因此僅使用int作為存儲桶是行不通的。 使用類似這樣的東西:

List<Integer>[] bucket = new List<Integer>[10];

用於按新順序收集元素的數組需要與原始數組大小相同。 你剛剛做了 10 長。

嘗試

    int[] b = new int[a.length];

或者因為 n = a.length

    int[] b = new int[n];

最后一個 for 循環中的語句

a[i] = b[i];

告訴 b 的大小必須等於或大於 a。 因此去@rcgldr 回答。 傳遞給函數的基數值也未使用。 您還可以通過交換數組指針而不是復制元素來使您的函數更快一點,即避免最后一個 for 循環。

int swap[] = a;
a = b;
b = swap;

然后最后在所有循環結束后,返回數組 a

return a;

以上是您按升序排序的程序。 我在程序下面給出按降序排序。 唯一需要的改變是開始添加從基本數組(在本例中為 Z )末尾到索引零的頻率。

public static int[] DSC(int A[], int radix, int base)
{
    int length = A.length ;
    int B[] = new int[length] ;
    int div = 1 ;
    int swap[] ;
    int i ;
    while(radix > 0)
    {
        int Z[] = new int[base] ;
        i = 0 ;
        while(i < length)
        {
            Z[( A[i] / div ) % base]++ ;
            i++ ;
        }
        i = base ;
        while(i > 1)
        {
            i--;
            Z[i-1] += Z[i] ;
        }
        i = length ;
        while(i > 0)
        {
            i-- ;
            B[--Z[( A[i] / div ) % base]] = A[i];
        }
        swap = A;
        A = B;
        B = swap;
        div *= base;
        radix--;
    }
    return A;
}

對於非負整數,使用binary而不是decimal ,可能對機器更有效和直觀。

這是我寫的一個實現,帶有測試用例:

基數排序程序

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * Radix sort.
 *
 * @author eric
 * @date 3/12/20 12:05 PM
 */
public class RadixSort {
    /**
     * Sort given array, the array will be modified.
     *
     * @param data array of integer of non-negative integers,
     * @throws IllegalArgumentException if input contain negative integer,
     */
    public static void sort(int[] data) {
        int numSys = 2;
        int bits = validAndfindHighestBit(data); // find highest bit,

        // create queues,
        List<List<Integer>> queues = new ArrayList<>(numSys);
        for (int i = 0; i < numSys; i++) queues.add(new LinkedList<>());

        // sort bit by bit, low to high,
        for (int i = 0; i < bits; i++) {
            // re-init queues,
            for (int j = 0; j < numSys; j++) queues.get(j).clear();

            // array -> queues,
            for (int x : data) {
                int bit = (x >> i) & 1; // get the i-th bit,
                queues.get(bit).add(x);
            }

            // queues -> array,
            int t = 0;
            for (List<Integer> queue : queues) {
                for (int x : queue) data[t++] = x;
            }
        }
    }

    /**
     * Valid input number, and find highest bit that has 1.
     *
     * @param data
     * @return
     * @throws IllegalArgumentException if input contain negative integer,
     */
    private static int validAndfindHighestBit(int[] data) {
        // find max number,
        int max = 0;
        for (int x : data) {
            if (x < 0) throw new IllegalArgumentException("negative integers are not supported");
            if (x > max) max = x;
        }
        System.out.printf("max number: %d, ", max);

        // find highest bit,
        int highestBit = 0;
        while (max != 0) {
            highestBit++;
            max >>= 1;
        }
        System.out.printf("highest bit: %d\n", highestBit);

        return highestBit;
    }
}

基數排序測試.java
(通過TestNG測試用例)

import org.testng.Assert;
import org.testng.annotations.Test;

import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

import static org.testng.Assert.*;

/**
 * RadixSort test.
 */
public class RadixSortTest {
    @Test
    public void testSort() {
        int[] data;
        // generated un-sorted random array,
        do data = genRandomArr(); while (data.length > 1 && isSorted(data));
        System.out.printf("input arr:\t%s\n", Arrays.toString(data));
        if (data.length > 1) Assert.assertFalse(isSorted(data));

        // sort
        RadixSort.sort(data);
        System.out.printf("output arr:\t%s\n", Arrays.toString(data));
        Assert.assertTrue(isSorted(data));
    }

    // corner case,
    @Test
    public void testSort_corner() {
        int[] dataEmpty = new int[0]; // empty array,
        RadixSort.sort(dataEmpty);
        Assert.assertTrue(isSorted(dataEmpty));

        int[] dataSingle = new int[]{5}; // single element,
        RadixSort.sort(dataSingle);
        Assert.assertTrue(isSorted(dataSingle));
    }

    // invalid input,
    @Test(expectedExceptions = IllegalArgumentException.class)
    public void testSort_invalid() {
        int[] dataSingle = new int[]{1, -1}; // negative number,
        RadixSort.sort(dataSingle);
    }

    /**
     * generate random array, of size 10, in range [0, 1024),
     *
     * @return
     */
    public static int[] genRandomArr() {
        return genRandomArr(10, 100);
    }

    /**
     * generate random array,
     *
     * @param size  array size, default to 10,
     * @param bound upper bound, default to 100,
     * @return
     */
    public static int[] genRandomArr(int size, int bound) {
        if (size <= 0) size = 10;
        if (bound <= 0) bound = 100;
        ThreadLocalRandom rd = ThreadLocalRandom.current();
        int[] arr = new int[size];
        for (int i = 0; i < arr.length; i++) arr[i] = rd.nextInt(bound);
        return arr;
    }

    // check whether array is sorted,
    private static boolean isSorted(int[] a) {
        for (int i = 0; i < a.length - 1; i++) {
            if (a[i] > a[i + 1]) return false;
        }
        return true;
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM