我有一个大O符号问题。假设我有一个执行以下操作的Java程序:
将一个整数数组读入HashMap
,以跟踪数组中存在的整数的出现次数。 [1,2,3,1]将是[1-> 2,2-> 1,3-> 1]。
然后我从HashMap
抓取密钥并将其放入Array
:
Set<Integer> keys = dictionary.keySet();
Integer[] keysToSort = new Integer[keys.size()];
keys.toArray(keysToSort);
使用keyArray
对<{1}}进行排序。
然后遍历已排序的Arrays.sort
抓取keyArray
中的相应值,以显示或格式化结果。
我想我知道以下内容:
步骤4是O(n)
第2步:在进行此类计算时,我应该知道Java如何实现HashMap
类Set
方法。我会假设它遍历toArray
检索HashMap
。如果是这种情况,我会假设其为O(n)。
如果顺序操作指示我添加每个部分,那么最终的计算将是 O(n + n·log n + n + n)= O(3n + n·log n)。
跳过常数,你有 O(n + n log n)。这可以进一步减少还是我完全错了?
答案 0 :(得分:6)
我相信O(n + nlogn)
可以进一步简化为O(nlogn)
。这是因为n
与nlogn
相比渐渐变得无意义,因为它们是复杂的不同顺序。 nlogn
的排序高于n
。这可以通过向下滚动到公共功能顺序部分在wikipedia page上进行验证。
答案 1 :(得分:2)
当使用哈希映射等复杂数据结构时,您需要知道它如何检索对象,并非所有数据结构都具有相同的检索过程或时间来检索元素。
这可以帮助您在Java中找到复杂数据类型的大O: http://www.coderfriendly.com/wp-content/uploads/2009/05/java_collections_v2.pdf
答案 2 :(得分:0)
第2步需要O(地图容量)。
如果您有许多具有相同哈希码的密钥(即O(这些密钥的数量)用于单个查找或更改,则步骤1和4可能会变坏,再乘以数量那些查找/更改)。
O(n + n·log n)= O(n·log n)
答案 3 :(得分:0)
关于第2步,您可以稍微担心一下。据我所知,Java API没有指定这些操作的运行时间。
至于O(n + n log n)
Treebranch是对的。您可以将其减少到O(n log n)
,因为对于某些基本值n0
n log n > c*n forall c /= 0, n > n0
,显然就是这种情况,因为无论您为c
选择了什么号码,都可以使用n0
设置为2^c+1
答案 4 :(得分:0)
首先,
如果将O(n)
中的整数插入HashMap
,则步骤1仅为O(1)
。在Perl中,插入哈希值的最坏情况是O(N)
N
个项目(也称为摊销O(1)
),如果您折扣密钥的长度(这是可接受的) 。 HashMap
可能效率较低,具体取决于它如何解决某些问题。
其次,
O(N)
为O(N log N)
,因此O(N + N log N)
为O(N log N)
。
答案 5 :(得分:0)
大O没告诉你的一件事是缩放因子有多大。它还假设您有一台理想的机器。这很重要的原因是从文件中读取的内容可能远远超过其他任何内容。
如果你确实计时,你会收到startup cost
+ read time
的内容。即使是一百万条记录,启动成本也可能是最大的。读取时间与读取的字节数有关(即数字长度可能很重要)如果你有1亿读取时间可能更重要。如果您有十亿条记录,则很多将取决于唯一条目的数量而不是条目的总数。唯一条目的数量限制在20亿左右。
顺便说一句:要更有效地执行计数,请尝试使用TIntIntHashMap,它可以最大限度地减少对象创建,使其快几倍。
当然我只谈论大O不考虑的真机;)
我要说的是你可以做一个大的O计算,但它不会提供有关真实应用程序行为的信息。