简体   繁体   中英

The time complexity of the for loop nested with if-statement and while loop

void makeGraph(){
    for(auto itr = inputs.begin(); itr != inputs.end(); itr++){
        string str = itr->second;
        if (strstr(str.c_str(), "->") != NULL){
            char ch = '>';
            size_t pos = str.find_last_of(ch);
            parent = str.substr(0, pos-2);
            string child = str.substr(pos+2);
            if (strstr(parent.c_str(), ",") != NULL){
                int size_parent = parent.length();
                char ch_parent[size_parent+1];
                strcpy(ch_parent, parent.c_str());
                char *token = strtok(ch_parent, ",");
                while (token != NULL){
                    string sub_Parent = token;
                    sub_Parent.erase(std::remove(sub_Parent.begin(),
                                                 sub_Parent.end(),
                                                 ' '),
                                     sub_Parent.end());
                    graph[sub_Parent].push_back(child);
                    token = strtok(NULL, ",");
                }
            } else{
                graph[parent].push_back(child);
            }
        } else{
            cout<<"Just for TEST"<<endl;
        }
    }
    printGraph();
}

What is the time complexity of this function? Is it n O(n)?? How do you handle the loop inside the else statement?

The difficulty in this case is that you have many variables that need to be accounted for. The important one being:

  1. The number of elements in input .
  2. For each string in input , the number of characters in the string.

If you want a precise estimate, you would have to separately account for each of these variables. If we use N to refer to the length of input , then we have N strings whose lengths are M1 , M2 , ..., MN . Each string can be handled differently, so that complicates things as well.

Since Big-O provides an upper bound, we can save ourself some trouble by instead considering these variables:

  1. N , being the number of elements in input .
  2. M , being the length of the longest input string.

The last big simplification comes from looking at the worst case behaviour. Without know more about the input data, we can't really do more nuanced calculation anyways, so let's just do the worst case.

Since there is so much going on here, I like to look at the "leaves" - the most nested blocks - and then work my way up. Let's hone in on the elephant in the room: the while loop. What's going on here? The loop itself is basically just iterating over parent . Note that the length of parent can scale linearly with the length of str , which means the complexity of the while loop will look like O(M * [complexity of the while body]) . The body is only composed of a few steps:

string sub_Parent = token;
sub_Parent.erase(std::remove(sub_Parent.begin(), sub_Parent.end(), ' '), sub_Parent.end());
graph[sub_Parent].push_back(child);
token = strtok(NULL, ",");

The work involving sub_Parent and token plays into the looping behaviour of the while loop (ie, the fewer while loop iterations there are, the longer token will generally be, and vice versa). However, none of those operations will scale worse than O(M) since the length of parent is itself O(M) . Instead let's focus on the push_back() call. Since the length of child is O(M) , and since this push_back() copies child , this operation is O(M) in time complexity. Therefore, we can confidently say that the complexity of the while loop body is O(M) as well. Combining the body with the loop itself, the total complexity of the while loop is:

  O(M * [complexity of the while body]
= O(M * M)
= O(M^2)

Now let's go up one level. The operations outside of the while loop are clearly O(M) since they deal with copying and searching parent . The while loop dominates this, so we can ignore those contributions.

Going up one more level, we hit the if . What do we do here? Well, in the true case, we get the while loop with complexity O(M^2) . In the false case, we get a push_back() with a copy of child , making that O(M) . Since we're looking at the worst case, we'll say the complexity of the if / else is the larger expression: O(M^2) .

Going up another level (just outside the if from the previous step), we have a similar situation as before in that the operations are at worst O(M) as they search and copy str to create parent and child . These are dominated by the if complexity, so we can ignore their contributions.

Now for the outermost if . We again compare branches. In the true branch, we have the O(M^2) complexity we just worked out. In the false branch we have O(1) complexity (just printing a constant string). So in the worst case, this if has O(M^2) complexity.

We're almost there. Outside of that if we have a copy to create str . This is O(M) , so we can ignore it as it is dominated by the O(M^2) from the if . So the for loop body is O(M^2) in total.

Finally we look at the for loop itself. It is a simple linear iteration over input (being N elements in length), meaning its complexity is:

  O(N * [complexity of the body])
= O(N * M^2)

So there you have it. The worst case complexity is linear in the length of input , but quadratic in the length of the longest string.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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