Java 使用合并排序算法所需的最小比较次数?
对于那些熟悉合并排序的人,我试图计算出合并大小为n/2的两个子数组所需的最小比较次数,其中n是原始未排序数组中的项数Java 使用合并排序算法所需的最小比较次数?,java,complexity-theory,Java,Complexity Theory,对于那些熟悉合并排序的人,我试图计算出合并大小为n/2的两个子数组所需的最小比较次数,其中n是原始未排序数组中的项数 我知道该算法的平均时间复杂度和最坏情况时间复杂度只有n,但我无法计算出以n为单位所需的确切最小比较次数。合并步骤的最小比较次数约为n/2,顺便说一句,它仍然处于启用状态,一旦其中一个列表被完全遍历,就假设一个正常的实现 例如,如果两个已经有效排序的列表正在合并,则较大列表的第一个成员将与较小列表进行n/2次比较,直到其耗尽;然后可以复制较大的列表,而无需进一步比较 List 1
我知道该算法的平均时间复杂度和最坏情况时间复杂度只有n,但我无法计算出以n为单位所需的确切最小比较次数。合并步骤的最小比较次数约为n/2,顺便说一句,它仍然处于启用状态,一旦其中一个列表被完全遍历,就假设一个正常的实现 例如,如果两个已经有效排序的列表正在合并,则较大列表的第一个成员将与较小列表进行n/2次比较,直到其耗尽;然后可以复制较大的列表,而无需进一步比较
List 1 List 2 Merged List Last Comparison
[1, 2, 3] [4, 5, 6] [] N/A
[2, 3] [4, 5, 6] [1] 1 < 4
[3] [4, 5, 6] [1, 2] 2 < 4
[] [4, 5, 6] [1, 2, 3] 3 < 4
[] [5, 6] [1, 2, 3, 4] N/A
[] [6] [1, 2, 3, 4, 5] N/A
[] [] [1, 2, 3, 4, 5, 6] N/A
注意,进行了3次比较,列表中有6名成员
再次注意,即使在最好的情况下,合并步骤仍然有效地被考虑。合并排序算法在*lgn上具有时间复杂度,因为合并步骤在整个列表上都处于打开状态,并且在Olgn递归级别上进行除法/合并。合并步骤的最小比较次数约为n/2,顺便说一句,这仍然处于打开状态,一旦其中一个列表被完全遍历,就假设一个正常的实现 例如,如果两个已经有效排序的列表正在合并,则较大列表的第一个成员将与较小列表进行n/2次比较,直到其耗尽;然后可以复制较大的列表,而无需进一步比较
List 1 List 2 Merged List Last Comparison
[1, 2, 3] [4, 5, 6] [] N/A
[2, 3] [4, 5, 6] [1] 1 < 4
[3] [4, 5, 6] [1, 2] 2 < 4
[] [4, 5, 6] [1, 2, 3] 3 < 4
[] [5, 6] [1, 2, 3, 4] N/A
[] [6] [1, 2, 3, 4, 5] N/A
[] [] [1, 2, 3, 4, 5, 6] N/A
注意,进行了3次比较,列表中有6名成员
再次注意,即使在最好的情况下,合并步骤仍然有效地被考虑。合并排序算法在*lgn上具有时间复杂度,因为合并步骤在整个列表中都处于打开状态,并且分割/合并以Olgn递归级别进行。对于每次比较,从两个列表中的一个列表中排出一个元素。因此,比较的数量最多是两个列表长度的总和。正如Platinum所展示的,如果您到达一个阵列的末端,而另一个阵列中仍有项目,则可能会更少
因此,比较的数量介于n/2和n之间。对于每次比较,您将从两个列表中的一个列表中释放一个元素。因此,比较的数量最多是两个列表长度的总和。正如Platinum所展示的,如果您到达一个阵列的末端,而另一个阵列中仍有项目,则可能会更少
因此,比较的数量在n/2和n之间。这个答案给出了一个精确的结果,而不仅仅是使用一些公式编写的渐近行为 合并长度为m和n的列表至少需要minm,n个比较。原因是,只有当其中一个输入列表已被完全处理时,您才能停止比较元素,即,您需要在两个列表中的较小列表上进行迭代。请注意,此数量的比较仅适用于某些输入,因此在假设可能输入数据的最佳情况的意义上,它是最小的。对于最坏情况的输入,您将发现更高的数字,即 设n=2k为二的幂。假设我是一个合并级别,0≤ 我
List 1 List 2 Merged List Last Comparison
[1, 2, 3] [4, 5, 6] [] N/A
[2, 3] [4, 5, 6] [1] 1 < 4
[3] [4, 5, 6] [1, 2] 2 < 4
[] [4, 5, 6] [1, 2, 3] 3 < 4
[] [5, 6] [1, 2, 3, 4] N/A
[] [6] [1, 2, 3, 4, 5] N/A
[] [] [1, 2, 3, 4, 5, 6] N/A
现在让n比2的幂小1。设k=⌈lg n⌉ 仍然表示合并级别的数量。与2k案例相比,您现在在每个级别都少了一个比较。因此,合并的总数减少了k,结果是2kk/2− k=2k/2− 1k比较。但是,如果再删除一个元素,则会导致n=2k− 2,则不会减少最顶端合并的数量,因为另一个列表已经是较短的列表。这意味着这里的事情可能会变得更加困难
让我们来看一个演示程序,我们可以用它来检查之前的结果,并计算其他值的比较次数:
mc=[0,0]动态编程,缓存以前的结果
循环中的k=1个单元n
对于范围为2128的n:
a=n//2靠近中心的拆分列表
b=n—另一半列表的计算长度
mc.appendmc[a]+mc[b]+mina,b需要对它们进行排序,然后合并
如果n&n-1==0:如果n是2的幂
断言mc[-1]==n*k/2检查先前的结果
k+=1增量k=ceillg n
打印“,”。从n=0开始,在mc打印比较计数序列中,为m连接STRM
这将为您提供以下顺序:
0,
0, 1, 2, 4, 5, 7, 9, 12, 13, 15, 17, 20, 22, 25, 28, 32, 33, 35,
37, 40, 42, 45, 48, 52, 54, 57, 60, 64, 67, 71, 75, 80, 81, 83, 85,
88, 90, 93, 96, 100, 102, 105, 108, 112, 115, 119, 123, 128, 130, 133,
136, 140, 143, 147, 151, 156, 159, 163, 167, 172, 176, 181, 186, 192,
193, 195, 197, 200, 202, 205, 208, 212, 214, 217, 220, 224, 227, 231,
235, 240, 242, 245, 248, 252, 255, 259, 263, 268, 271, 275, 279, 284,
288, 293, 298, 304, 306, 309, 312, 316, 319, 323, 327, 332, 335, 339,
343, 348, 352, 357, 362, 368, 371, 375, 379, 384, 388, 393, 398, 404,
408, 413, 418, 424, 429, 435, 441
您可以在中查找,以发现此序列描述了。这里也有一些公式,但要么它们是不精确的,涉及一些朗道符号项,要么它们依赖于其他一些非平凡序列,要么它们非常复杂。我最喜欢的一个表达了我上面的程序所做的:
a0=0,a2n=an+an-1+n,a2n+1=2an+n+1拉尔夫·斯蒂芬,2003年9月13日
考虑到这些备选方案,我想我会坚持使用上面的脚本来计算这些数字。您可以删除断言和与此相关的所有内容,依赖于a
mc=[0,0]
对于范围为1024的n:
a=n//2
mc.附录mc[a]+mc[n-a]+a
注意,例如,对于n=3,只能进行两次比较。很明显,只有将两个极值元素与中间元素进行比较,这样就不必再将极值元素与其他元素进行比较了。这说明了为什么上述计算仅适用于最佳情况输入。最坏情况下的输入将使您在某一点上计算彼此的最小和最大元素,从而导致通过该公式计算的三个比较。此答案给出了一个精确的结果,而不仅仅是使用某些公式编写的渐近行为 合并长度为m和n的列表至少需要minm,n个比较。原因是,只有当其中一个输入列表已被完全处理时,您才能停止比较元素,即,您需要在两个列表中的较小列表上进行迭代。请注意,此数量的比较仅适用于某些输入,因此在假设可能输入数据的最佳情况的意义上,它是最小的。对于最坏情况的输入,您将发现更高的数字,即 设n=2k为二的幂。假设我是一个合并级别,0≤ 我
List 1 List 2 Merged List Last Comparison
[1, 2, 3] [4, 5, 6] [] N/A
[2, 3] [4, 5, 6] [1] 1 < 4
[3] [4, 5, 6] [1, 2] 2 < 4
[] [4, 5, 6] [1, 2, 3] 3 < 4
[] [5, 6] [1, 2, 3, 4] N/A
[] [6] [1, 2, 3, 4, 5] N/A
[] [] [1, 2, 3, 4, 5, 6] N/A
现在让n比2的幂小1。设k=⌈lg n⌉ 仍然表示合并级别的数量。与2k案例相比,您现在在每个级别都少了一个比较。因此,合并的总数减少了k,结果是2kk/2− k=2k/2− 1k比较。但是,如果再删除一个元素,则会导致n=2k− 2,则不会减少最顶端合并的数量,因为另一个列表已经是较短的列表。这意味着这里的事情可能会变得更加困难
让我们来看一个演示程序,我们可以用它来检查之前的结果,并计算其他值的比较次数:
mc=[0,0]动态编程,缓存以前的结果
循环中的k=1个单元n
对于范围为2128的n:
a=n//2靠近中心的拆分列表
b=n—另一半列表的计算长度
mc.appendmc[a]+mc[b]+mina,b需要对它们进行排序,然后合并
如果n&n-1==0:如果n是2的幂
断言mc[-1]==n*k/2检查先前的结果
k+=1增量k=ceillg n
打印“,”。从n=0开始,在mc打印比较计数序列中,为m连接STRM
这将为您提供以下顺序:
0, 0, 1, 2, 4, 5, 7, 9, 12, 13, 15, 17, 20, 22, 25, 28, 32, 33, 35,
37, 40, 42, 45, 48, 52, 54, 57, 60, 64, 67, 71, 75, 80, 81, 83, 85,
88, 90, 93, 96, 100, 102, 105, 108, 112, 115, 119, 123, 128, 130, 133,
136, 140, 143, 147, 151, 156, 159, 163, 167, 172, 176, 181, 186, 192,
193, 195, 197, 200, 202, 205, 208, 212, 214, 217, 220, 224, 227, 231,
235, 240, 242, 245, 248, 252, 255, 259, 263, 268, 271, 275, 279, 284,
288, 293, 298, 304, 306, 309, 312, 316, 319, 323, 327, 332, 335, 339,
343, 348, 352, 357, 362, 368, 371, 375, 379, 384, 388, 393, 398, 404,
408, 413, 418, 424, 429, 435, 441
您可以在中查找,以发现此序列描述了。这里也有一些公式,但要么它们是不精确的,涉及一些朗道符号项,要么它们依赖于其他一些非平凡序列,要么它们非常复杂。我最喜欢的那个
这正是我上面的程序所做的:
a0=0,a2n=an+an-1+n,a2n+1=2an+n+1拉尔夫·斯蒂芬,2003年9月13日
考虑到这些备选方案,我想我会坚持使用上面的脚本来计算这些数字。您可以删除断言和与此相关的所有内容,依赖于a
mc=[0,0]
对于范围为1024的n:
a=n//2
mc.附录mc[a]+mc[n-a]+a
注意,例如,对于n=3,只能进行两次比较。很明显,只有将两个极值元素与中间元素进行比较,这样就不必再将极值元素与其他元素进行比较了。这说明了为什么上述计算仅适用于最佳情况输入。最坏情况下的输入会使您在某一点上计算彼此的最小和最大元素,从而导致通过该公式计算的三个比较。您的答案似乎只描述了一个合并操作,即将两个排序列表合并为一个。您缺少递归的最高级别。@MvG:我不是这样解释这个问题的。合并两个子数组所需的最小比较次数不是合并排序所需的最小比较次数。您的答案似乎只描述了一个合并操作,即将两个已排序列表合并为一个。您缺少递归的最高级别。@MvG:我不是这样解释这个问题的。合并两个子阵列所需的最小比较次数,而不是合并排序所需的最小比较次数。