java - 查找和最小化归并排序算法运行时分析
问题描述
假设我有一个大小为 n 的数组,我想将它分配给大小为 n/k 的 k 个新数组。-这一步的运行时间可能是多少?****我想自从我们拆分数组时到 2 我们看它像 2^x=n =>x=log N => O(log n) 那么它在这里也一样:k^(n/k)=n => n/k=log N ****但是接下来呢?
现在我在每个 k 数组上运行冒泡排序算法-O(n^2) 并在所有 k 数组上使用合并算法来制作大小为 n 的排序数组-假设合并复杂度为 O(kn )。
另外我不想找到一个 K 来最小化算法的运行时间,我该怎么做?我认为对运行时函数求导并找到它的最小值就可以了,这是正确的方法吗?
解决方案
合并排序将数组拆分为连续的小块,直到它变成一堆 2 元素子数组。然后它开始将合并算法应用于连续更大的子数组。
想象一下,您有一个包含 16 个元素的数组。合并排序是这样进行合并的:
8 merges of two 1-item subarrays
4 merges of two 2-item subarrays
2 merges of two 4-item subarrays
1 merge of two 8-item subarrays
有四 (log 2 (16)) 遍,并且在每遍中它检查每个项目。每遍都是O(n)。所以这个归并排序的运行时间是 O(n * log 2 (n))。
现在,假设您有一个包含 81 个项目的数组,并且您想使用 3 路归并排序来合并它。现在您有以下合并序列:
27 merges of three 1-item subarrays (gives 27 3-item subarrays)
9 merges of three 3-item subarrays (gives 9 9-item subarrays)
3 merges of three 9-item subarrays (gives 3 27-item subarrays)
1 merge of three 27-item subarrays
有四个 (log 3 (81)) 通过。每次合并是 O(m * log 2 (k)),其中 m 是要合并的项目的总数,k 是列表的数量。所以第一遍有 27 次合并,进行 3*log 2 (3) 次比较。下一遍有 9 次合并,进行 9*log 2 (3) 比较等。最终总合并为 O(n * log 3 (n) * log 2 (3))
您可以看到 3 路归并排序让您执行更少的传递(16 个项目的 3 路归并排序只需要 3 遍),但每次传递的成本要高一些。您必须确定的是:
n * log k (n) * log 2 (k) < n * log 2 (n)
k
您要将数组拆分成的子数组的数量在哪里。我会让你做这个数学。
但是,您必须小心,因为渐近分析没有考虑到现实世界的影响。例如,2 路合并非常简单。当您进行 k > 2 的 k 路合并时,您最终不得不使用堆或其他优先级队列数据结构,这具有相当多的开销。因此,即使上面的数学告诉您 3 路合并排序应该更快,您仍需要将其与标准的 2 路合并进行基准测试。
更新
你是对的。如果你简化方程,你最终会得到相同的方程。因此,无论 k 的值如何,计算复杂度都是相同的。
这是有道理的,因为如果 k = x,那么你最终会得到一个堆排序。
因此,您必须确定是否存在随着 k 增加而增加的合并开销被减少的通过次数所抵消的点。您可能需要凭经验确定。
推荐阅读
- c++ - 运行最小 GTest 示例的链接错误
- php - Laravel with() 慢
- r - 使用多列名称的字符向量以编程方式对 data.table 进行排序
- java - 快速排序实现中的 Stackoverflow 错误
- javascript - 如何使用 Closure Compiler 在函数中定义“this”的类型
- c# - 为什么当我碰到鼠标滚轮时我的 WPF 应用程序会崩溃?
- c# - DocuSign 服务集成真实帐户无法进行身份验证
- javascript - 在递归函数调用中递增计数器
- javascript - 用作 GET 请求时准确发送的 javascript POST 请求是什么?
- php - 使用 PHP 显示数据库中的图像