为啥基数排序的空间复杂度为 O(k + n)?
Posted
技术标签:
【中文标题】为啥基数排序的空间复杂度为 O(k + n)?【英文标题】:Why does radix sort have a space complexity of O(k + n)?为什么基数排序的空间复杂度为 O(k + n)? 【发布时间】:2017-11-12 15:55:01 【问题描述】:考虑一个包含n
数字的数组,该数组具有最大k
数字(请参阅编辑)。考虑here的基数排序程序:
def radixsort( aList ):
RADIX = 10
maxLength = False
tmp, placement = -1, 1
while not maxLength:
maxLength = True
# declare and initialize buckets
buckets = [list() for _ in range( RADIX )]
# split aList between lists
for i in aList:
tmp = i / placement
buckets[tmp % RADIX].append( i )
if maxLength and tmp > 0:
maxLength = False
# empty lists into aList array
a = 0
for b in range( RADIX ):
buck = buckets[b]
for i in buck:
aList[a] = i
a += 1
# move to next digit
placement *= RADIX
buckets
基本上是所有数字的二维列表。但是,只会将 n
值添加到其中。为什么空间复杂度是 O(k + n) 而不是 O(n)?如果我错了,请纠正我,即使我们考虑用于在特定位置提取数字的空间,它也只使用 1(常量)内存空间?
编辑:我想解释一下我对k
的理解。假设我输入[12, 13, 65, 32, 789, 1, 3]
,链接中给出的算法将经过4遍(函数内的第一个while
循环)。这里k
= 4,即最大数量。数组中任何元素的位数 + 1。因此 k 不是。通行证。这与该算法的时间复杂度所涉及的 k
相同:O(kn)
这是有道理的。我无法理解它在空间复杂性中的作用:O(k + n)
。
【问题讨论】:
【参考方案1】:基数排序的空间复杂度与它用于对每个基数进行排序的排序有关。最好的情况是计数排序。
这是CLRS提供的用于计数排序的伪代码:
Counting-sort(A,B,k)
let C[0..k] be a new array
for i = 0 to k
C[i] = o
for j = 1 to A.length
C[A[j]] = C[A[j]] + 1
for i = 1 to k
C[i] = C[i] + C[i-1]
for j = A.length down to 1
B[C[A[j]]] = A[j]
C[A[j]] = C[A[j]] - 1
如您所见,计数排序会创建多个数组,一个基于 K 的大小,一个基于 N 的大小。B 是大小为 n 的输出数组。 C 是一个大小为 k 的辅助数组。
因为基数排序使用计数排序,所以计数排序的空间复杂度是基数排序空间复杂度的下限。
【讨论】:
这完全是错误的。 Here,例如,您可以找到我的就地基数排序实现,其空间复杂度为O(1)
。更重要的是,这个答案实际上并没有回答问题。
如果算法采用可变大小的输入,它就不可能有 O(1) 的空间复杂度。空间复杂度是衡量算法需要的工作存储量的指标。如果算法对数组进行操作,则需要该数组作为存储。就地并不意味着 O(1)。
另外,我只是在这里引用 CLRS。如果您能证明这些人是错的,那么我认为您将获得比堆栈溢出代表更多的收益。
嗯。我错了额外空间复杂度≠实际空间复杂度。我现在明白你的意思了; +1。
很抱歉延迟接受答案。我现在才满意地理解了这一点。【参考方案2】:
我认为存在术语问题。 Jayson Boubin's answer中提到的问题的实现和实现的空间复杂度是O(n+k)
。但k
不是最长单词(或最长数字)的长度。 k
是“字母”的大小:不同数字(数字)或字母(单词)的数量。
buckets = [list() for _ in range( RADIX )]
此代码创建一个包含RADIX
元素的数组。在这个特定的实现中,RADIX
是一个常数(空间复杂度为 O(n)),但一般来说,它是一个变量。 RADIX
是 k
,不同数字(字母表中的字母)的数量。而这个k
不依赖于n
,在某些情况下可以大于n
,所以空间复杂度一般为O(n+k)。
编辑:在this 实现中,placement
(或tmp
)的大小是O(k)
(使用您对k
的定义),因为k
是@987654339 @base 10
,而placement
大小为log(maxNumber)
base 256
。但我不确定这是一般情况。
【讨论】:
是的。 k 表示数字,如果是数字。 我不相信 k 与基数或其长度相同。基数始终为 10 。但如果至少有一个三位数,则 k 将为 3,其余为 2 或 1 位数。 @skr_robo,这就是我要说的,在O(n+k)
k
不是某个数字中的最大位数。
@DAIe 如果我们输入这个数组 = [12, 13, 65, 32, 789, 1, 3],上述算法将运行 4 遍(因为有一个 3 位数字)。现在,时间复杂度是 O(kn),这个 k 是通过的次数,即 4。我的观点是 O(k+n) 也有相同的 k。我不明白为什么基数在这里起作用?
我在调用k
最大位数时出错了。它不止于此。【参考方案3】:
基数排序对数据集中的每一位数字使用计数排序。计数排序的空间复杂度为 O(n+k),其中 k 是数据集中的最大数。
十进制数字的范围从 0 到 9,所以如果我们使用基数排序(基数排序中使用的计数排序)对 4 个十进制数(11,22,88,99)进行排序,对于每个数字,它将创建大小为 b = 10 其中 b 是底数。
这意味着使用的总空间将是总位数 * (n + base)。如果总位数不变。空间复杂度变为 O(n+base)。
因此基数排序的空间复杂度为 O(n+b)。
【讨论】:
以上是关于为啥基数排序的空间复杂度为 O(k + n)?的主要内容,如果未能解决你的问题,请参考以下文章