使用哈希图的这种方法的复杂性是什么
我知道插入hashmap
采用 o(1)时间复杂性,因此,对于插入n
元素,复杂性应为 o (n)。我对以下方法有疑问。
代码:
private static Map<Character, Character> mapCharacters(String message) {
Map<Character, Character> map = new HashMap<>();
char idx = 'a';
for (char ch : message.toCharArray()) { // a loop - O(n)
if (!map.containsKey(ch)) { // containsKey - take O(n) to check the whole map
map.put(ch, idx);
++idx;
}
}
return map;
}
我正在做的是用顺序“ abcd”
映射解密的消息。
因此,我的困惑是上述方法的复杂性是否为 o(n^2)或 o(n)?请帮助我清除我的疑问。
I know that the insertion into a HashMap
takes O(1) time Complexity, so for inserting n
elements the complexity should be O(n). I have a little doubt about the below method.
Code:
private static Map<Character, Character> mapCharacters(String message) {
Map<Character, Character> map = new HashMap<>();
char idx = 'a';
for (char ch : message.toCharArray()) { // a loop - O(n)
if (!map.containsKey(ch)) { // containsKey - take O(n) to check the whole map
map.put(ch, idx);
++idx;
}
}
return map;
}
What I am doing is to map the decrypted message with the sequential "abcd"
.
So, My confusion is whether the complexity of the above method is O(n^2) or O(n)? Please help me to clear my doubt.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
它是摊销的O(n)。
containsKey
和put
均为amortized o(1);参见 hashmap.containskey()的时间复杂性是什么?特别是在Java?。It's amortised O(n).
containsKey
andput
are both amortised O(1); see What is the time complexity of HashMap.containsKey() in java? in particular.这两个
containskey()
和put()
的时间复杂性将取决于实现equals/hashcode 用于使用的对象的合同作为键。
在引擎盖下,
hashmap
维护一系列存储桶。每个 bucket 对应于一系列哈希。每个非空键包含 nodes (每个节点都包含与特定映射输入相关的信息),形成a 链接列表或a tree (以来,Java 8 )。根据提供的 key 的 hash 确定右 bucket 的过程几乎是即时的,除非计算 hash的过程很重,但无论如何它被认为具有恒定的时间复杂性 o(1)。访问 bucket (即访问数组元素)也是 o(1),但是事情可能会变得棘手。假设 bucket 仅包含很少的元素,则检查它们不会显着增加总成本(同时执行
containskey()
and code>和put()
我们应该检查 map 中提供的键),并且总体时间复杂性将为 o(1) 。但是,在所有出于某种原因出于某种原因最终出现在同一桶中时,然后在链接列表上进行迭代将导致< strong> o(n),如果将节点存储为红黑树,则
containskey()
and and put()的情况下,containskey()
是 o(log n)。如果
字符
作为A 键,我们可以正确实现equals/hashcode
。适当的哈希功能对于确保对象均匀分布在铲斗之间很重要。但是,如果您使用的是hashcode()
破坏的自定义对象,例如始终返回相同的数字,那么所有条目最终都会在同一存储桶中,并且性能将很差。碰撞,当不同对象在映射到同一桶的范围内产生哈希时的情况是不可避免的,我们需要一个良好的哈希功能来使碰撞数量尽可能少,这样当非空存量 buckets 的数量超过负载因子时,将“均匀”占用,并扩大地图。
该特定方法的时间复杂性是线性 o(n)。但是,如果您要更改键的类型,可能并非如此。
The time complexity of both
containsKey()
andput()
will depend on the implementation of theequals/hashCode
contract of the object that is used as a key.Under the hood,
HashMap
maintains an array of buckets. And each bucket corresponds to a range of hashes. Each non-empty bucket contains nodes (each node contains information related to a particular map-entry) that form either a linked list or a tree (since Java 8).The process of determining the right bucket based on the hash of the provided key is almost instant, unless the process of computing the hash is heavy, but anyway it's considered to have a constant time complexity O(1). Accessing the bucket (i.e. accessing array element) is also O(1), but then things can become tricky. Assuming that bucket contains only a few elements, checking them will not significantly increase the total cost (while performing both
containsKey()
andput()
we should check whether provided key exists in the map) and overall time-complexity will be O(1).But in the case when all the map-entries for some reason ended up in the same bucket then iterating over the linked list will result in O(n), and if nodes are stored as a Red-black tree the worse case cost of both
containsKey()
andput()
will be O(log n).In case
Character
as a key we have a proper implementation of theequals/hashCode
. Proper hash function is important to ensure that objects would be evenly spread among buckets. But if you were using instead a custom object whichhashCode()
is broken, for instance always returning the same number, then all entries will end up in the same bucket and performance will be poor.Collisions, situations when different objects produces hashes in the range that is being mapped to the same bucket, are inevitable, and we need a good hash function to make the number of collisions as fewer as possible, so that bucket would be "evenly" occupied and the map get expanded when the number of non-empty buckets exceeds load factor.
The time complexity of this particular method is linear O(n). But it might not be the case if you would change the type of the key.
给定您的原始代码下面:
以下是关于时间复杂性的一些观察:
消息中的每个字符
将为o(n) - 很明显,如果有10个字符,则需要10个步骤,10,000个字符将采用10,000步。时间复杂性与n
直接成比例。containskey()
,这是一个恒定时间操作,定义为O(1)时间复杂性。这个想法是,评估containskey()
的实际时间是相同的,无论您的地图有10个键还是10,000个键。map.put()
是另一个恒定时间操作,另一个O(1)操作。nth
字符,您将其花费时间在循环中迭代,检查地图是否已经具有并添加;所有这些都是3n(三次n
),只是O(n)。另外,您可以通过更换此块来对代码进行少量改进:
仅当您放置某些内容时,它保留了运行
++ IDX
的相同行为,特别是如果是上一件事要么是“不存在”,要么是用“ null”设置的,尽管“ null”不适用于您的代码示例中):尽管使用
containskey( )
使代码更清晰,还利用了经过良好测试的性能代码,可以免费使用。在封面下,呼叫 map.putifabsent() 如下(从OpenJDK 17开始)实现
get()
,然后是put()
如果不存在键。Given your original code below:
Here are some observations about the time complexity:
message
will be O(n) – pretty clearly if there are 10 characters it takes 10 steps, 10,000 characters will take 10,000 steps. The time complexity is directly proportional ton
.containsKey()
, this is a constant-time operation which is defined as O(1) time complexity. The idea is that the actual time to evaluate the result ofcontainsKey()
should be the same whether your map has 10 keys or 10,000 keys.if
, you havemap.put()
which is another constant-time operation, another O(1) operation.nth
character, you spend time iterating it in the loop, checking if the map has it already, and adding it; all of this would be 3n (three timesn
) which is just O(n).Separately, you could make a small improvement to your code by replacing this block:
with something like below (which retains the same behavior of running
++idx
only if you've put something, and specifically if the previous thing was either "not present" or perhaps had been set with "null" - though the "set as null" doesn't apply from your code sample):Though the time complexity wouldn't change, using
containsKey()
makes the code clearer, and also takes advantage of well-tested, performant code that's available for free.Under the covers, calling
Map.putIfAbsent()
is implemented like below (as of OpenJDK 17) showing an initial call toget()
followed byput()
if the key isn't present.