我被困在递归地实现基数排序
Posted
技术标签:
【中文标题】我被困在递归地实现基数排序【英文标题】:I am stuck at implementing Radix sort recursively 【发布时间】:2016-12-25 15:39:17 【问题描述】:我需要实现一个对 0 到 99999 范围内的数字进行递归排序的程序(这基本上是基数排序)。这个过程本身有点简单:用户在 main 方法中输入一个包含这些数字的数组。然后,主要方法调用排序方法,在该方法中我创建了一个名为“空间”的二维数组,包含 10 行和 1 列。然后,我将数组中的每个数字除以数字,第一次运行时为 10.000。因此,例如,23456 / 10000 = 2,3456 = 2(在 java 中),因此,程序将这个数字放在空格 [2] [0] 中,所以放在第二行。然后,我们获取整行并扩展它,这是在 putInBucket 方法中完成的。我们这样做是为了确保我们可以将另一个数字放入同一行。
我们对“数字”数组中的每个数字都执行此操作。然后,我们想处理这些行并按照相同的原则再次对它们进行排序,但现在我们看一下第二个数字。我们想从左到右,而不是从右到左。所以,如果我们的第二行看起来像这样
[23456, 24567],
我们想比较 3 和 4,得出 23456
我们借助排序方法末尾的递归调用来做到这一点。现在,这就是我迷路的地方。我根本不知道如何操作数字变量,以便能够处理每个数字的第二个、第三个、... 数字。如您所见,在第一次运行中,这可以简单地通过除以 10.000 来完成,但我没有找到离这里更远的方法。
请注意:是的,这是一道家庭作业题,因此,我只能在这里使用原语。我们还没有经历过 math.pow(...) 之类的东西。提前致谢!
public static int[] sort(int[] numbers, int digit)
if (numbers.length == 0)
return numbers;
int[][]space = new int[10][1];
int i, j = 0;
for (j = 0; j < numbers.length; j++)
i = numbers[j] / digit;
space[i][0] = numbers[j];
space[i] = putInBucket(space[i], numbers[j]);
for (i = 0; i < space[i].length; i++)
sort(space[i], digit); //not sure how to work with digit here
return ... //not sure what to return here
private static int[] putInBucket(int[] bucket, int number)
int[] bucket_new = new int[bucket.length+1];
for (int i = 1; i < bucket_new.length; i++)
bucket_new[i] = bucket[i-1];
return bucket_new;
public static void main (String [] argv)
int[] numbers = IO.readInts("Numbers: ");
int digit = 10000;
int[] bucket = sort(numbers, digit);
【问题讨论】:
第一步,使用您的 IDE 自动格式化此代码,使其具有一致的缩进(一致的缩进使您和我们更容易看到代码的结构)。事实上,我建议您将 ide 配置为在保存文件时自动格式化代码。 我正在使用 vim,我认为没有自动格式化。 这里的缩进有什么问题? 几乎所有东西。例如,所有行都从它们所属的方法所在的列开始。所以我们看不到它们是这个方法的一部分,方法在哪里结束,等等。如果你不能使用 vim 自动缩进,那么手动缩进,或者使用你可以缩进的编辑器。基本上所有以代码为中心的编辑器都允许这样做。 就我个人而言,我使用 eclipse,尽管其他人更喜欢 IntelliJ(社区版是免费的)或 netbeans。任何这些都适合初学者。 【参考方案1】:要提取最后一位,余数运算符%
是你的朋友:
123 % 10 == 3
如果你还没有覆盖%
运算符,你可以使用
123 % 10 == 123 - (123 / 10 * 10) == 3
要提取另一个数字,您可以先将其移动到末尾/
:
123 / 10 == 12
12 % 10 == 2
因此,您可以使用
提取任意数字(number / mask) % 10
其中掩码 ∈ ..., 10000, 1000, 100, 10, 1。
额外功劳
基数排序通常在二进制数字系统中实现,因为可以在不执行除法的情况下提取二进制数字(或其序列),这样更有效:
x % 16 == x & 15;
x \ 16 == x >> 4;
此外,如果您要真正实现这一点,则需要一种更有效的方法来增加存储桶(您的实现需要 O(n) 才能将单个元素添加到存储桶,因此向存储桶添加 n 个元素需要 O (n^2),这使您的基数排序比插入排序慢)。 Dynamic arrays 通常使用更高效的geometric expansion 来实现。
【讨论】:
是的,我们介绍了模运算符。 我知道的基数排序使用least significant digit first。 不是递归的,可以在下面的文章中找到。 啊好吧,不知道那个变种。好的,那么先提取最重要的数字。无论哪种情况,您都可以使用(number \ mask) % 10
提取数字,其中 mask ∈ ..., 10000, 1000, 100, 10, 1。
@meriton - 看看example radix sort。这是使用 256(一个字节)作为“数字”的 lsd(最低有效位)基数排序。生成一个计数矩阵,然后将其转换为“输出”数组的索引。代码通过交换指针在每次通过时交替移动方向。由于它是偶数遍,因此排序后的数据最终会出现在原始数组中。该示例返回一个指向已排序数组的指针,但这不是必需的,因为已排序的数据最终会出现在原始数组中。【参考方案2】:
这应该有效:
public static int[] sort(int[] numbers, int digit)
if (numbers.length == 0 || digit <= 0)
return numbers;
int[][]space = new int[10][10];
int[] len = new int[10];
int i, j = 0;
for (j = 0; j < numbers.length; j++)
i = (numbers[j] / digit) % 10;
len[i]++;
for (int k = len[i] - 1; k > 0; k--)
space[i][k] = space[i][k - 1];
space[i][0] = numbers[j];
for (i = 0; i < 10; i++)
int[] bucket = new int[len[i]];
for (int k = 0; k < len[i]; k++)
bucket[k] = space[i][k];
space[i] = sort(bucket, digit / 10);
int k = 0;
for (i = 0; i < 10; i++)
for (j = 0; j < len[i]; j++)
numbers[k] = space[i][j];
k++;
return numbers;
a) 首先,space
被分配为只有一列。因此,space[i] = bucket
将不起作用。
相反,您可以将其声明为 int[10][10]。 (注意:它只支持一个桶中最多 10 个值)。或者您可以以编程方式分配新数组。或者当然,List
可能更适合。
b)i = (numbers[j] / digit) % 10;
仅获取所需的数字。例如:如果号码是12130
,并且digit
= 1000
,我们希望将i
设置为2
,而不是12
。
c) putInBucket
替换为就地循环。
d) 对于space
中的每个bucket
,我们通过递归调用sort
将其排序低一位。
e) 最后,要返回的结果 (numbers
),可以通过从数字 0 到 9 循环 space
来创建。
注意: 这个解决方案可能会变得更好。
【讨论】:
我不能替换 putInBucket 方法,抱歉。 如果是这种情况,只需将循环替换为space[i] = putInBucket(space[i])
。另外,如果您不使用它,为什么要传递numbers[j]
?我怀疑你应该在putInBucket
中设置bucket_new[0] = number
,如果这是给你的方法签名。
我正在使用这些数字。它们在扩展数组的末尾复制,然后返回整个内容。如果您从 12345 开始并使用第一行和此数字调用 putInBucket 方法,那么您将得到一个如下所示的新数组:[0, 12345]。然后,如果出现另一个以 1 开头的数字,例如 13456,那么我们可以把它放在第一个位置,所以我们会得到 [13456, 12345] 并再次扩展它: [0, 13456, 12345] .这意味着要进一步排序。
我明白这一点。但是请查看您发布的putInBucket
方法。变量number
根本没有在方法体中使用!这就是我要说的。您可能希望在 putInBucket
中使用 bucket_new[0] = number
而不是在 sort
方法中使用 space[i][0] = numbers[j]
,但忘记了。
有人告诉我,由于可见性,我需要使用数字参数,尽管我没有清楚地使用它。您可能想查看我的更新版本:***.com/questions/41323554/…以上是关于我被困在递归地实现基数排序的主要内容,如果未能解决你的问题,请参考以下文章