简体   繁体   English

这个函数(for loop)是空间复杂度O(1)还是O(n)?

[英]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);
        }
    }
}

Would this be O(1) or O(n)? 这是O(1)还是O(n)? I'm guessing O(n), but isn't it reusing the spot of memory a each time making it O(1)? 我猜O(n),但不是每次重复使用内存点O(1)?

Space complexity asks "how much additional space (asymptotically, speaking) am I using in this snippet of code". 空间复杂性问“我在这段代码中使用了多少额外空间(渐近,说话)”。 Here's how a space complexity analysis would work, showing two general cases (for your code snippet): 以下是空间复杂度分析的工作原理,显示了两个一般情况(对于您的代码片段):

Example 1: Pass-by-value hashtable and list 示例1:按值传递hashtablelist

// 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);
        }
    }
}

Assuming you have N elements in hashtable and no elements are removed (ie, a <= 10 for all N elements), at the termination of the loop, you will have N elements remaining in hashtable . 假设您在hashtableN元素并且没有删除任何元素(即,对于所有N元素, a <= 10 ),在循环终止时,您将在hashtable保留N元素。 Furthermore, each String in the N keys in the hashtable contains up to S characters. 此外, hashtableN键中的每个String最多包含S字符。 Lastly, each Integer in the N values in the hashtable is constant. 最后, hashtable N值中的每个Integer都是常量。

Similarly, you have a possible M number of strings in list , where each String may contain up to S characters. 同样, list可能有M个字符串,其中每个String最多可包含S字符。

Lastly, the Integer a does not contribute to the analysis because it references memory already accounted for. 最后, Integer a对分析没有贡献,因为它引用了已经占用的内存。 We can consider this Integer a constant memory still. 我们可以认为这个Integer a仍然Integer a恒定的记忆。

Therefore, assuming hashtable and list had been declared in the method, you are looking at a space complexity of O(N*S + M*S + I) . 因此,假设在方法中声明了hashtablelist ,您将看到O(N*S + M*S + I)的空间复杂度O(N*S + M*S + I)

That said, asymptotically, we don't really care about I (the Integer a ) because it is constant size that is likely much smaller than N and M . 也就是说,渐渐地,我们并不真正关心IInteger a )因为它是恒定的大小,可能比NM小得多。 Similarly, S is likely much smaller than both N and M . 类似地, S可能比NM都小得多。 This means the space complexity is O(N + M) . 这意味着空间复杂度为O(N + M) Because both are linear terms, we can (carefully) reduce this to O(n) , where n is a linear term that is a linear combination of N and M . 因为两者都是线性项,我们可以(小心地)将其减少为O(n) ,其中n是线性项,它是N and M的线性组合。

Example 2: Pass-by-reference hashtable and list or elsewhere declared (as in your example) 示例2:传递引用hashtablelist 其他声明的内容(如示例中所示)

// 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);
        }
    }
}

In this method, list and hashtable have already been allocated elsewhere, which means that the space complexity for this method is O(1) because we are only using constant space in Integer a and String i (even though technically, they are references to previously allocated memory -- you can consider the constant space as a result of storing the reference). 在这个方法中, listhashtable已经在别处分配了,这意味着这个方法的空间复杂度是O(1)因为我们只在Integer aString i使用常量空间(尽管从技术上讲,它们是对先前的引用)分配内存 - 您可以考虑存储引用的常量空间)。

but isn't it reusing the spot of memory a each time making it O(1)? 但是不是每次重复使用记忆点O(1)?

It depends on what you mean by "reusing" the spot in memory. 这取决于你在内存中“重复使用”这个位置的含义。 In theory, space complexity analysis does not exactly consider the implementation details of the language in this sense. 从理论上讲,空间复杂性分析并没有从这个意义上准确地考虑语言的实现细节。 This means that if you had a loop like 这意味着如果你有一个像这样的循环

for (int i = 0; i < N; i++) {
    T myvar = new T();
}

you don't consider the implications of what's happening to myvar after each loop iteration. 你不考虑每次循环迭代后myvar发生的事情的含义。 By "implications of what's happening" I mean, does the garbage collector reclaim memory after each iteration or are you continually allocating N spots of memory on the heap? 通过“对正在发生的事情的影响”我的意思是,垃圾收集器是在每次迭代后回收内存还是你不断在堆上分配N个内存点? In the GC case, it would be O(1) since you are reusing memory. 在GC情况下,由于您正在重用内存,因此它将是O(1) In the "infinite" allocation case, it would be O(N) since you now have N spots allocated. 在“无限”分配情况下,它将是O(N)因为您现在已经分配了N点。 Again, in theory, this is usually not considered in the analysis, and any T myvar = new T() is usually considered to be O(1) regardless of whether it sits in a loop or not. 同样,理论上,这通常不在分析中考虑,并且任何T myvar = new T()通常被认为是O(1),无论它是否位于循环中。

In general, though, if you are referring to reusing the same spot in memory for list and hashtable each iteration, the answer is simpler. 但是,一般情况下,如果您指的是在每次迭代中重复使用内存中的相同位置listhashtable ,答案就更简单了。 Consider the following: 考虑以下:

public void foo() {
    int list[] = {1, 2, 3, 4};
    for (int i = 0; i < list.length; i++) {
        System.out.println(list[i]);
    }
}

Even though list is declared once and we're only iterating through list and printing the contents, foo() is still O(n) in memory complexity because we have allocated list , where in the asymptotic case could have up to n elements. 即使list被声明一次并且我们只是遍历list并打印内容, foo()仍然是内存复杂度的O(n),因为我们已经分配了list ,其中渐近情况下最多可以有n元素。 Therefore, regardless of whether it reuses the same or different spots in memory, they both still contribute to a linear space complexity. 因此,无论它是否在内存中重用相同或不同的点,它们都仍然有助于线性空间复杂性。

tl;dr TL;博士

In your specific case, though, both list and hashtable had already been allocated elsewhere in the program and are not introduced here, so they do not contribute to the complexity, and Integer a and String i are only constant in memory. 但是,在您的特定情况下, listhashtable都已经在程序的其他地方分配,并且未在此处介绍,因此它们不会导致复杂性,并且Integer aString i仅在内存中保持不变。 Therefore, this method will be O(1) . 因此,这种方法将是O(1)

It is O(1) 是O(1)

Other than 2 constant sized variables string i and Integer a this method does not allocate any extra space. 除了2个常量大小的变量string iInteger a此方法不会分配任何额外的空间。 Which means this loop clearly has constant space complexity .ie. 这意味着这个循环显然具有恒定的空间复杂性。 O(1) . O(1)

To clarify it further, I would rather ask you a question : 为了进一步澄清,我宁愿问你一个问题:

Do you call (iterative)binary search an O(n) space complexity algorithm ? 你是否称为(迭代)二进制搜索O(n)空间复杂度算法?

Absolutely not. 绝对不。

Your function check_10() uses a preallocated list and hash table (just like iterative binary search uses preallocated sorted array) and 2 constant space variables so it has O(1) space complexity. 您的函数check_10()使用预分配列表和哈希表(就像迭代二进制搜索使用预分配的排序数组)和2个常量空间变量,因此它具有O(1)空间复杂度。

PS : I am clarifying the doubt raised by OP in comments of this answer from here onwards -> PS :我正在澄清OP在此回答的评论中提出的疑问 - >

As pointed out by MichaelRecachinas, String and Integer in this loop are references. 正如MichaelRecachinas所指出的,这个循环中的StringInteger是引用。 They are not a copy so they won't contribute anything to the space complexity of this function. 它们不是副本,因此它们不会对此功能的空间复杂性做出任何贡献。

PPS : Integer a and String i are allocated memory only once and then are reused in each iteration of the loop. PPSInteger aString i只分配一次内存,然后在循环的每次迭代中重用。

This has O(n) space complexity because the list takes up that space. 这具有O(n)空间复杂度,因为列表占用了该空间。 :). :)。 The hash table is at most another O(n), so the sum of the space complexities is still O(n). 哈希表最多是另一个O(n),因此空间复杂度的总和仍然是O(n)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM