Java实现基数排序算法

Radix Sort是一种有效的基于非比较的排序算法,可以按线性O(N)时间复杂度对数据集进行排序,因此比其他同类竞争算法要好快速排序。它使用另一种算法计数排序 作为子例程。

“基数排序”利用以下思想:

  • 整数中的位数取决于:
    • 它的基础
    • 与数据相比要少得多

数字线性增加,但数字对数增加。

开发基数排序可以对大整数排序。它会将整数视为一串数字,因此我们也可以使用“基数排序”对字符串进行排序。

算法

  • 对于i从最低有效数字到最高有效数字变化的每个数字i,都要执行以下操作。
    • 使用以下命令对输入数组进行排序 计数排序(或任何稳定的排序)根据第i个数字。

例子

假设输入数组为:

[326、453、608、835、751、435、704、690]

基于该算法,我们将根据个位数(最低有效数字)对输入数组进行排序。

原始数组基于 [6、3、8、5、1、5、4、0] 使用计数排序

所以,数组变成 [690、751、453、704、835、435、326、608]

现在,我们将根据十位数进行排序:

上面部分排序的数组是基于 [9、5、5、0、3、3、2、0] 使用计数排序

现在,该数组变为: [704、608、326、835、435、751、453、690]

最后,我们根据百位数(最高有效位数)进行排序:

上面部分排序的数组是基于 [7、6、3、8、4、7、4、6] 使用计数排序

该数组变为: [326、435、453、608、690、704、751、835] 排序。

请按照以下图片了解概念:

基数排序的图像

为什么在Radix Sort中可以一次排序一位数字?

伪码


Radix-Sort(A, d)
       for j = 1 to d do
            int count[10] = {0};
            for i = 0 to n do
                count[key of(A[i]) in pass j]++
            for k = 1 to 10 do
                count[k] = count[k] + count[k-1]
            for i = n-1 downto 0 do
                result[ count[key of(A[i])] ] = A[j]
                count[key of(A[i])]--
            for i=0 to n do
                A[i] = result[i]
       end for(j)
 end func 
 

复杂度分析

最佳案例时间复杂度:Ω(nk)

平均案例时间复杂度:Θ(nk)

最坏案例时间复杂度:O(nk)

空间复杂度:O(n+k)

其中n是输入数据的数量,k是输入数据中的最大元素

设输入整数为d位。“基数排序”取O(d(n + b)) *时间,其中b是表示数字的基数,例如对于十进制,b是10。d的值是多少?如果k是最大可能值,则d将为O(logb(k))。因此,总体时间复杂度为O((n + b)* logb(k))。它看起来比基于比较的大k排序算法的时间复杂度更高。

让我们首先限制k。令k <= nc,其中c为常数。在这种情况下,复杂度变为O(nLogb(n))。但是它仍然不能胜过基于比较的排序算法。

如果我们增大b的值怎么办?使时间复杂度线性化的b的值应该是多少?如果将b设置为n,则时间复杂度为O(n)。换句话说,如果数字以基数n表示(或者每个数字取log2(n)位),则我们可以对范围从1到nc的整数数组进行排序。

Java实现


// Radix sort Java implementation 
import java.util.*;

class RadixSortDemo2 {

	// A utility function to get maximum value in arr[]
	static int getMax(int arr[]) {
		int n = arr.length;
		int mx = arr[0];
		for (int i = 1; i < n; i++)
			if (arr[i] > mx)
				mx = arr[i];
		return mx;
	}

	// A function to do counting sort of arr[] according to
	// the digit represented by exp.
	static void countSort(int arr[], int exp) {
		int n = arr.length;
		int output[] = new int[n]; // output array
		int i;
		int count[] = new int[10];
		Arrays.fill(count, 0);

		// Store count of occurrences in count[]
		for (i = 0; i < n; i++)
			count[(arr[i] / exp) % 10]++;

		// Change count[i] so that count[i] now contains
		// actual position of this digit in output[]
		for (i = 1; i < 10; i++)
			count[i] += count[i - 1];

		// Build the output array
		for (i = n - 1; i >= 0; i--) {
			output[count[(arr[i] / exp) % 10] - 1] = arr[i];
			count[(arr[i] / exp) % 10]--;
		}

		// Copy the output array to arr[], so that arr[] now
		// contains sorted numbers according to curent digit
		for (i = 0; i < n; i++)
			arr[i] = output[i];
	}

	// The main function to that sorts arr[] of size n using
	// Radix Sort
	static void radixSort(int arr[]) {
		// Find the maximum number to know number of digits
		int m = getMax(arr);

		// Do counting sort for every digit. Note that instead
		// of passing digit number, exp is passed. exp is 10^i
		// where i is current digit number
		for (int exp = 1; m / exp > 0; exp *= 10) {
			countSort(arr, exp);
			System.out.println(exp + "位处理:" + Arrays.toString(arr));
		}
	}

	/* Driver function to check for above function */
	public static void main(String[] args) {
		int arr[] = { 326, 453, 608, 835, 751, 435, 704, 690 };
		System.out.println("未排序:" + Arrays.toString(arr));
		radixSort(arr);
		System.out.println("排序后:" + Arrays.toString(arr));
	}
}

输出:

未排序:[326, 453, 608, 835, 751, 435, 704, 690]
1位处理:[690, 751, 453, 704, 835, 435, 326, 608]
10位处理:[704, 608, 326, 835, 435, 751, 453, 690]
100位处理:[326, 435, 453, 608, 690, 704, 751, 835]
排序后:[326, 435, 453, 608, 690, 704, 751, 835]
 

好处

Radix Sort的优点是:

  • 键短时(即数组元素的范围较小时)快。
  • 用于后缀数组构造算法,例如Manber算法和DC3算法。
  • 基数排序是稳定的排序,因为具有相等值的元素的相对顺序得以保持。

缺点

Radix Sort的缺点是:

  • 由于“基数排序”取决于数字或字母,因此“基数排序”比其他类型的灵活性要差得多。因此,对于每种不同类型的数据,都需要重写它。
  • 与其他排序算法相比,Radix排序的常数更大。
  • 与就地排序的Quicksort相比,它占用了更多空间。
  • 如果操作效率不高,则基数排序可能比合并排序和快速排序等其他排序算法慢。这些操作包括子列表的插入和删除功能以及隔离所需数字的过程。
  • 基数排序不如其他排序灵活,因为它取决于数字或字母。如果更改了数据类型,则需要重写基数排序。
  • 它不是就地排序算法,因为它需要额外的额外空间。

猜你喜欢

转载自blog.csdn.net/allway2/article/details/114055570