- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我的任务是在 Python 或 Java(或任何其他语言)中实现堆排序算法。由于我对 Python 或 Java 并不是那么“流利”,所以我决定两者都做。
但在这里我遇到了一个问题,程序的运行时间比它“应该”的时间高太多了。我的意思是,堆排序应该会遇到 O(n * log n) 并且对于以几 GHz 的时钟速率运行的当前处理器,我没想到该算法会遇到超过 2000 秒的数组大小为 320k
因此,对于我所做的,我在 Python 和 Java 中通过此类伪代码实现了算法(我还尝试了 Rosetta Code 中的 Julia 代码,以查看运行时间是否相似,为什么是 Julia?随机选择)
所以我检查了输出是否存在小输入大小问题,例如大小为 10、20 和 30 的数组。看来它在两种语言/实现中都正确排序了数组。
然后我使用实现相同算法的 heapq 库再次检查运行时间是否相似。当实际情况如此时,这让我感到惊讶......但经过几次尝试后,我尝试了最后一件事,即更新 Python,然后,使用 heapq 的程序运行速度比以前的程序快得多。实际上,320k 阵列大约需要 2k 秒,现在大约需要 1.5 秒左右。
我重试了我的算法,问题仍然存在。
下面是我实现的 Heapsort 类:
class MaxHeap:
heap = []
def __init__(self, data=None):
if data is not None:
self.buildMaxHeap(data)
@classmethod
def toString(cls):
return str(cls.heap)
@classmethod
def add(cls, elem):
cls.heap.insert(len(cls.heap), elem)
cls.buildMaxHeap(cls.heap)
@classmethod
def remove(cls, elem):
try:
cls.heap.pop(cls.heap.index(elem))
except ValueError:
print("The value you tried to remove is not in the heap")
@classmethod
def maxHeapify(cls, heap, i):
left = 2 * i + 1
right = 2 * i + 2
largest = i
n = len(heap)
if left < n and heap[left] > heap[largest]:
largest = left
if right < n and heap[right] > heap[largest]:
largest = right
if largest != i:
heap[i], heap[largest] = heap[largest], heap[i]
cls.maxHeapify(heap, largest)
@classmethod
def buildMaxHeap(cls, heap):
for i in range(len(heap) // 2, -1, -1):
cls.maxHeapify(heap, i)
cls.heap = heap
@staticmethod
def heapSort(table):
heap = MaxHeap(table)
output = []
i = len(heap.heap) - 1
while i >= 0:
heap.heap[0], heap.heap[i] = heap.heap[i], heap.heap[0]
output = [heap.heap[i]] + output
heap.remove(heap.heap[i])
heap.maxHeapify(heap.heap, 0)
i -= 1
return output
为了记录每个数组大小 (10000 - 320000) 的运行时间,我在主函数中使用了这个循环:
i = 10000
while i <= 320000:
tab = [0] * i
j = 0
while j < i:
tab[j] = randint(0, i)
j += 1
start = time()
MaxHeap.heapSort(tab)
end = time()
pprint.pprint("Size of the array " + str(i))
pprint.pprint("Total execution time: " + str(end - start) + "s")
i *= 2
如果您需要其余的代码来查看错误可能出在哪里,请不要犹豫,我会提供它。只是不想无缘无故地共享整个文件。
如前所述,我预期的运行时间是最坏情况下的运行时间:O(n * log n)使用现代架构和 2.6GHz 的处理器,我希望大约 1 秒甚至更短(因为运行时间以纳秒为单位,我想即使是 1 秒也太长了)
结果如下:
Python (own) : Java (Own)
Time Size Time Size
593ms. 10k 243ms. 10k
2344ms. 20k 600ms. 20k
9558ms. 40k 1647ms. 40k
38999ms. 80k 6666ms. 80k
233811ms. 160k 62789ms. 160k
1724926ms. 320k 473177ms. 320k
Python (heapq) Julia (Rosetta Code)
Time Size Time Size
6ms. 10k 21ms. 10k
14ms. 20k 21ms. 20k
15ms. 40k 23ms. 40k
34ms. 80k 28ms. 80k
79ms. 160k 39ms. 160k
168ms. 320k 60ms. 320k
And according to the formula the O(n * log n) give me :
40000 10k
86021 20k
184082 40k
392247 80k
832659 160k
1761648 320k
我认为这些结果可以用来确定需要多少时间,具体取决于机器(理论上)
如您所见,高运行时间结果来 self 的算法,但我无法确定代码中的位置,这就是我在这里寻求帮助的原因。 (在 Java 和 Python 中运行缓慢)(没有尝试在 java lib 中使用堆排序是不是有人看到了我的实现的差异,我的不好)
非常感谢。
编辑:我忘了补充一点,我在 MacBook Pro(最新版本的 MacOS,i7 2,6GHz)上运行这个程序。以防问题也可能来自代码以外的任何其他东西。
编辑 2:以下是我根据收到的答案对算法所做的修改。该程序的运行速度比以前快了大约 200 倍,因此现在对于大小为 320k 的数组,它运行仅需 2 秒
class MaxHeap:
def __init__(self, data=None):
self.heap = []
self.size = 0
if data is not None:
self.size = len(data)
self.buildMaxHeap(data)
def toString(self):
return str(self.heap)
def add(self, elem):
self.heap.insert(self.size, elem)
self.size += 1
self.buildMaxHeap(self.heap)
def remove(self, elem):
try:
self.heap.pop(self.heap.index(elem))
except ValueError:
print("The value you tried to remove is not in the heap")
def maxHeapify(self, heap, i):
left = 2 * i + 1
right = 2 * i + 2
largest = i
if left < self.size and heap[left] > heap[largest]:
largest = left
if right < self.size and heap[right] > heap[largest]:
largest = right
if largest != i:
heap[i], heap[largest] = heap[largest], heap[i]
self.maxHeapify(heap, largest)
def buildMaxHeap(self, heap):
for i in range(self.size // 2, -1, -1):
self.maxHeapify(heap, i)
self.heap = heap
@staticmethod
def heapSort(table):
heap = MaxHeap(table)
i = len(heap.heap) - 1
while i >= 0:
heap.heap[0], heap.heap[i] = heap.heap[i], heap.heap[0]
heap.size -= 1
heap.maxHeapify(heap.heap, 0)
i -= 1
return heap.heap
它使用与之前给定的相同的 main 运行
最佳答案
有趣的是,您发布了计算机的时钟速度 - 您可以计算出您的算法所需的实际步数...但是您需要了解很多关于实现的信息。例如,在 Python 中,每次创建对象或超出范围时,解释器都会更新底层对象的计数器,并在这些引用计数达到 0 时释放内存。相反,您应该查看相对 速度。
您发布的第三方示例显示,当输入数组长度加倍时,速度不会加倍。这似乎不对,是吗?事实证明,对于这些示例,构建数组的初始工作可能支配了对数组进行排序所花费的时间!
在您的代码中,已经有一条注释指出了我要说的话...
heap.remove(heap.heap[i])
此操作将遍历您的列表(从索引 0 开始)以查找匹配的值,然后将其删除。这已经很糟糕了(如果它按预期工作,如果您的代码按预期工作,那么您将在该行上进行 320k 比较!)。但情况变得更糟——从数组中删除一个对象并不是就地修改——删除对象之后的每个对象都必须在列表中向前移动。最后,不能保证您确实删除了那里的最后一个对象……可能存在重复值!
这是一个有用的网站,列出了 python 中各种操作的复杂性 - https://wiki.python.org/moin/TimeComplexity .为了尽可能高效地实现算法,您需要尽可能多的数据结构操作为 O(1)。这是一个示例...这是一些原始代码,大概是 heap.heap 是一个列表...
output = [heap.heap[i]] + output
heap.remove(heap.heap[i])
做
output.append(heap.heap.pop())
将避免分配新列表并使用常量时间操作来改变旧列表。 (向后使用输出比使用 O(n) 时间 insert(0) 方法要好得多!如果你真的需要顺序,你可以使用 dequeue 对象进行输出以获得 appendleft 方法)
如果您发布了完整的代码,我们可能会提供很多其他的帮助。希望这对您有所帮助!
关于python - 为什么我的 Python 脚本在我的 HeapSort 实现上运行得比它应该运行的慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55369804/
我已经看了好几个小时了,还是想不通。如果 heapify 函数中的比较更改为大于,则输出按应有的顺序递增。我希望我的列表按降序排序,但它没有使用以下代码给出正确的输出: #include #incl
我是 C++/算法的新手,我不太确定我的 heapSort 函数有什么问题。给定数字(6、2、9、1、5),我输出了以下不正确的数字: 9 4197040 2 4196422 6 感谢您的关注。 #i
我卡在 heapSort 上了。我有一些代码,但我认为它是错误的,因为我很难编译它。有什么建议么?堆排序应该很容易实现,但我有一堆语法错误。这是我的代码: /* Framework for Heap
考虑一个已经按降序排列的数组 A[n]。堆已经建立。现在考虑我们将 A[1](数组索引从 1 开始)与 A[heap.size] 交换的循环。这是伪代码: Build-Max-Heap(A) //Al
我正在研究算法,特别是堆排序。根据我的理解,heapsort 算法涉及通过首先将列表转换为最大堆来准备列表。 转动我的 [2, 8, 5, 3, 9, 1] 进入 [9, 8, 5, 3, 2, 1]
我在 http://students.ceid.upatras.gr/~lebenteas/Heapsort-using-Multiple-Heaps-final.pdf 找到了使用多个堆的 Heap
传统的Heapsort 算法在每次heapification 后将堆的最后一个元素与当前堆的根交换,然后再次继续该过程。但是,我注意到这是不必要的。 在子数组的堆化之后,当节点包含最高值(如果它是ma
任务是为数组中未知类型的元素编写堆排序(仅使用 C 代码),但我的代码不起作用。对于以下数字输出是 '-100 7 -4 0 33 -3 67 1 5 44' 我也尝试将相同的代码仅用于 int 输入
代码如下: import java.util.Arrays; public class HeapSort { pub
有人可以描述一种算法,该算法在最小堆的数组实现中找到所有小于 x 的键。 我希望运行时间至少为 O(k),其中 k 是报告的键数。 我已经为此挠头一段时间了。 最佳答案 树最小堆有一个简单的递归算法:
出于某种原因,我的 Heapsort 无法正常工作。使用以下测试程序: int main() { AddArrayElement(10); AddArrayElement(110);
我正在尝试使用最小堆实现堆排序。输入是正整数数组,数组的零索引存储大小。谁能发现我的错误?这里使用的语言是 C#。该算法有时可以正常工作,但对于更大的数组,根不是数组中的最小值。 static
我正在尝试用 java 编写一个堆排序方法,但它并没有完全按照我想要的方式工作: public class HeapSort { private static int n; priva
我今天写了两个不同的堆排序实现,都给了我相同的结果: Object i: 18 Object i: 11 Object i: 10 Object i: 9 Object i: 8 Object i:
我正在为软件开发人员面试做准备,并且一直在研究算法问题。我的书展示了一种 Heapsort 算法,它可以按升序对无序数组进行排序。我正在尝试修改它,以便它可以使用最小堆进行排序。但是当我按照代码中的逻
我必须在 C# 中检查 HeapSort 算法时间,我的问题是我知道我必须使用 System.Timers,因为我不知道如何测量算法时间。我必须检查表的算法时间包含 1000、10 000、100 0
我读到 C++ 对其内置的 std::sort 使用 introsort(内省(introspection)排序),它从快速排序开始,并在达到深度限制时切换到堆排序。 我还读到深度限制应该是 2*lo
对于类(class),我必须实现 BST 或 heapSort。我做了 BST,但认为也知道这一点会很好,但现在我被困住了。这是我第一次使用堆(并且真正使用泛型编码/实现 Comparable,所以我
我有一个随机生成的测试程序,数据是随机生成的,然后将它们传递给类 Sorter 的类构造函数。然后Sorter会对数据进行排序,通过一个方法传回给main函数。我还实现了其他几种排序方法作为 Sort
假设我有一个 vector 要排序: std::vector v{9, 8, 0, 2, 7, 3, 2, 1} 假设我想从第三个元素(索引 2)开始排序直到结束,所以我有一个迭代器指向 0 表示开始
我是一名优秀的程序员,十分优秀!