Algorithm 将列表分层到无序分区中
我正在努力为以下问题找到一个好的算法:Algorithm 将列表分层到无序分区中,algorithm,sorting,Algorithm,Sorting,我正在努力为以下问题找到一个好的算法: 输入:n个整数的未排序列表 输出:p个大小(大致)相等的未排序列表,其中每个列表的最小元素都大于其前面列表的最大元素 目标是对输出进行分层,这样,例如,在p=3的情况下,我可以得到3个无序的小、中、大数字列表(按该顺序) 例如: n=10,p=3 输入:[4,1,8,7,9,3,6,0,2,5] 输出:[[1,0,2],[4,3,6,5],[8,7,9]] 显然,我可以在O(n*log(n))时间内通过简单的排序和分区来完成这项工作,但我想知道这是
- 输入:n个整数的未排序列表
- 输出:p个大小(大致)相等的未排序列表,其中每个列表的最小元素都大于其前面列表的最大元素
- 输入:[4,1,8,7,9,3,6,0,2,5]
- 输出:[[1,0,2],[4,3,6,5],[8,7,9]]
O(n*log(n))
时间内通过简单的排序和分区来完成这项工作,但我想知道这是否不能在线性时间内完成。我知道QuickSelect在预期的O(n)
平均情况下运行,所以我的直觉是这个问题应该在O(p*n)
时间内解决
我天真地认为您可以简单地运行QuickSelect p次,依次找到下一个第k个最小的元素,然后对每个元素执行类似于基数的排序,以按原始步骤中标识的p轴对元素进行分区
因此:
O(p*n)
O(p*n)
,我也不确定
这是一个最佳的复杂性(尽管我怀疑是这样,因为
似乎在p=1和p=n的边缘情况下有效)谢谢我觉得你的算法不错。我唯一的疑惑是,我看不出你怎么能执行你所说的“类似基数的排序”。对于每个值x,您需要确定它进入p个插槽中的哪一个,并且由于这些插槽似乎没有非常特殊的结构(不像在常规的基数排序中,它们对应于某个固定值的倍数),我认为您需要对每个值进行O(log p)比较 假设只使用比较,则不能比O(n logn)更好,因为如果可以,则只需设置p=n并运行此算法,就可以将n个数字按比O(n logn)更好的顺序排序 还要注意的是,如果一个值可能出现多次,则生成的子集可能是任意不平衡的。(如果在您的情况下使用严格的“大于”,则这种可能性是不可避免的。)
最后,如果最坏情况下的性能是一个问题,那么就存在一个问题。它有一个很大的常数,请注意,如果你的输入是异常的模式或者来自潜在的敌意源,那么只考虑它。 QuestSoad实际上是一个分区算法,所以在快速选择之后不需要额外的步骤。
让我们假设我们有一个函数分区(arr,lo,hi),它返回一些
k
,这样lo给你的例子,[[0],[1],[4,8,7,9,3,6,2,5]
是有效的输出吗?可以在O(p*n)时间内找到p-1
最小的元素,并将每个元素放在一个单件列表中,其余元素放在最终列表中。如果它是无效的,那么你的问题就没有明确说明。很好。目的是使输出列表具有相同的大小+/-1元素。更新问题。
# After this call:
# arr[i] <= arr[med] if lo <= i < med
# arr[med] <= arr[i] if med < i < hi
QuickSelect(arr, lo, med, hi):
if lo < hi:
k = Partition(arr, lo, hi)
if med < k:
QuickSelect(arr, lo, med, k)
else if k < med:
QuickSelect(arr, k + 1, med, hi)
QuickSort(arr, lo, hi):
if lo < hi:
k = Partition(arr, lo, hi)
QuickSort(arr, lo, k)
QuickSort(arr, k + 1, hi)
Stratify(arr, n, p):
for i from 0 to p - 2 (inclusive):
QuickSelect(arr, floor(i * n / p), floor((i+1) * n /p, n)
Stratum(i, n, p): floor(i * p / n)
QuickStratify(arr, n, p, lo, hi):
if Stratum(lo, n, p) < Stratum(hi, n, p):
k = Partition(arr, lo, hi)
QuickStratify(arr, n, p, lo, k)
QuickStratify(arr, n, p, k + 1, hi)