[英]Is this function (for loop) space complexity O(1) or O(n)?
public void check_10() {
for (string i : list) {
Integer a = hashtable.get(i);
if (a > 10) {
hashtable.remove(i);
}
}
}
这是O(1)还是O(n)? 我猜O(n),但不是每次重复使用内存点O(1)?
空间复杂性问“我在这段代码中使用了多少额外空间(渐近,说话)”。 以下是空间复杂度分析的工作原理,显示了两个一般情况(对于您的代码片段):
hashtable
和list
// assume `list` and `hashtable` are passed by value
public void check_10(List<String> list, HashMap<String, Integer> hashtable) {
for (String i : list) {
Integer a = hashtable.get(i);
if (a > 10) {
hashtable.remove(i);
}
}
}
假设您在hashtable
有N
元素并且没有删除任何元素(即,对于所有N
元素, a <= 10
),在循环终止时,您将在hashtable
保留N
元素。 此外, hashtable
中N
键中的每个String
最多包含S
字符。 最后, hashtable
N
值中的每个Integer
都是常量。
同样, list
可能有M
个字符串,其中每个String
最多可包含S
字符。
最后, Integer a
对分析没有贡献,因为它引用了已经占用的内存。 我们可以认为这个Integer a
仍然Integer a
恒定的记忆。
因此,假设在方法中声明了hashtable
和list
,您将看到O(N*S + M*S + I)
的空间复杂度O(N*S + M*S + I)
。
也就是说,渐渐地,我们并不真正关心I
( Integer a
)因为它是恒定的大小,可能比N
和M
小得多。 类似地, S
可能比N
和M
都小得多。 这意味着空间复杂度为O(N + M)
。 因为两者都是线性项,我们可以(小心地)将其减少为O(n)
,其中n
是线性项,它是N and M
的线性组合。
hashtable
和list
或其他声明的内容(如示例中所示) // assume `list` and `hashtable` are passed by reference or
// declared elsewhere in the class as in
//
// public void check_10() {
public void check_10(List<String> list, HashMap<String, Integer> hashtable) {
for (String i : list) {
Integer a = hashtable.get(i);
if (a > 10) {
hashtable.remove(i);
}
}
}
在这个方法中, list
和hashtable
已经在别处分配了,这意味着这个方法的空间复杂度是O(1)
因为我们只在Integer a
和String i
使用常量空间(尽管从技术上讲,它们是对先前的引用)分配内存 - 您可以考虑存储引用的常量空间)。
但是不是每次重复使用记忆点O(1)?
这取决于你在内存中“重复使用”这个位置的含义。 从理论上讲,空间复杂性分析并没有从这个意义上准确地考虑语言的实现细节。 这意味着如果你有一个像这样的循环
for (int i = 0; i < N; i++) {
T myvar = new T();
}
你不考虑每次循环迭代后myvar
发生的事情的含义。 通过“对正在发生的事情的影响”我的意思是,垃圾收集器是在每次迭代后回收内存还是你不断在堆上分配N个内存点? 在GC情况下,由于您正在重用内存,因此它将是O(1)
。 在“无限”分配情况下,它将是O(N)
因为您现在已经分配了N
点。 同样,理论上,这通常不在分析中考虑,并且任何T myvar = new T()
通常被认为是O(1),无论它是否位于循环中。
但是,一般情况下,如果您指的是在每次迭代中重复使用内存中的相同位置list
和hashtable
,答案就更简单了。 考虑以下:
public void foo() {
int list[] = {1, 2, 3, 4};
for (int i = 0; i < list.length; i++) {
System.out.println(list[i]);
}
}
即使list
被声明一次并且我们只是遍历list
并打印内容, foo()
仍然是内存复杂度的O(n),因为我们已经分配了list
,其中渐近情况下最多可以有n
元素。 因此,无论它是否在内存中重用相同或不同的点,它们都仍然有助于线性空间复杂性。
但是,在您的特定情况下, list
和hashtable
都已经在程序的其他地方分配,并且未在此处介绍,因此它们不会导致复杂性,并且Integer a
和String i
仅在内存中保持不变。 因此,这种方法将是O(1)
。
除了2个常量大小的变量string i
和Integer a
此方法不会分配任何额外的空间。 这意味着这个循环显然具有恒定的空间复杂性。 O(1) 。
为了进一步澄清,我宁愿问你一个问题:
你是否称为(迭代)二进制搜索O(n)空间复杂度算法?
绝对不。
您的函数check_10()使用预分配列表和哈希表(就像迭代二进制搜索使用预分配的排序数组)和2个常量空间变量,因此它具有O(1)空间复杂度。
PS :我正在澄清OP在此回答的评论中提出的疑问 - >
正如MichaelRecachinas所指出的,这个循环中的String
和Integer
是引用。 它们不是副本,因此它们不会对此功能的空间复杂性做出任何贡献。
PPS : Integer a
和String i
只分配一次内存,然后在循环的每次迭代中重用。
这具有O(n)空间复杂度,因为列表占用了该空间。 :)。 哈希表最多是另一个O(n),因此空间复杂度的总和仍然是O(n)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.