简体   繁体   English

该算法(Big-O)的时间复杂度是多少?

[英]What is the time complexity of this algorithm (Big-O)?

I am still trying to understand the BigO notation and time complexity, however, I am really not sure what is the time complexity of this algorithm (my code). 我仍在尝试了解BigO表示法和时间复杂度,但是,我真的不确定此算法(我的代码)的时间复杂度是多少。

// 03_BeaverConstructions.c
// Created for FIKS on 28/12/2013 by Dominik Hadl
//
// Time complexity: O(N+M)
// Space complexity: O(N)
// ------------------------------------------
// LICENSE (MIT)
// Copyright (c) 2013 Dominik Hadl
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// ------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// ------------------------------------------
// Setup
// ------------------------------------------

#define MAX_PROFILE_LENGTH 10000
#define NO_VALUE -99999

#define BLOCK_VOLUME 1
#define SLOPE_VOLUME 0.5

const char kSlopeRise = '/';
const char kSlopeLower = '\\';
const char kSlopeStay = '_';

// ------------------------------------------
// Structs
// ------------------------------------------

typedef struct
{
    int start_elevation;
    float current_volume;
} Lake;

typedef struct
{
    int location;
    int elevation;
} Peak;

// ------------------------------------------
// Declarations
// ------------------------------------------

int main(int argc, char const *argv[]);
float get_water_volume_of_profile(char const *hill_profile);

// ------------------------------------------
// Main
// ------------------------------------------

int main(int argc, char const *argv[])
{
    // Get the profile
    char hill_profile[MAX_PROFILE_LENGTH + 1];
    fgets(hill_profile, MAX_PROFILE_LENGTH + 1, stdin);

    // Calculate the volume
    float volume = get_water_volume_of_profile(hill_profile);

    // Print it!
    printf("%0.1f\n", volume);

    return 0;
}

// ------------------------------------------
// Calculation
// ------------------------------------------

float get_water_volume_of_profile(char const *hill_profile)
{
    float total_volume = 0; 
    int current_elevation = 0, number_of_peaks = 0, last_peak_index = 0;

    // Get the actual length of the hill profile    
    int profile_length = strlen(hill_profile);

    // Prepare the peaks and lakes in the hill profile
    Peak peaks[profile_length / 2];
    Lake lake = {NO_VALUE, 0};

    // First, get all the peaks
    for (int i = 0; i < profile_length; i++)
    {
        char current_char = hill_profile[i];
        char next_char = hill_profile[i + 1];

        switch (current_char)
        {
            case kSlopeRise:
                current_elevation += 1;
                break;
            case kSlopeLower:
                current_elevation -= 1;
                break;
            case kSlopeStay:
                break;
        }

        if (next_char == '\n')
        {
            peaks[number_of_peaks].location = i + 1;
            peaks[number_of_peaks].elevation = current_elevation;
            number_of_peaks++;
            break;
        }

        if (current_char == kSlopeRise &&
            (next_char == kSlopeLower || next_char == kSlopeStay))
        {
            peaks[number_of_peaks].location = i + 1;
            peaks[number_of_peaks].elevation = current_elevation;
            number_of_peaks++;
        }
    }

    // Now, go through the profile and get the water volume
    current_elevation = 0;
    for (int i = 0; i < profile_length; i++)
    {
        // Get current char and decide what to do
        char current_char = hill_profile[i];
        switch (current_char)
        {
            case kSlopeRise:
            {
                if (lake.start_elevation != NO_VALUE &&
                    lake.start_elevation > current_elevation)
                {
                    lake.current_volume += SLOPE_VOLUME;
                }

                // Increase the elevation
                current_elevation++;

                if (lake.start_elevation == current_elevation)
                {
                    total_volume += lake.current_volume;

                    lake.start_elevation = NO_VALUE;
                    lake.current_volume = 0;
                    break;
                }

                if (lake.start_elevation != NO_VALUE)
                {
                    int elevation_diff = abs(lake.start_elevation - current_elevation);
                    if (elevation_diff > 1)
                    {
                        lake.current_volume += (elevation_diff - 1) * BLOCK_VOLUME;
                    }
                }

                break;
            }
            case kSlopeLower:
            {
                current_elevation--; // Lower the elevation

                // Set elevation where water starts if not already set
                if (lake.start_elevation == NO_VALUE)
                {
                    for (int p = last_peak_index; p < number_of_peaks; p++)
                    {
                        if (peaks[p].elevation >= current_elevation + 1 &&
                            peaks[p].location > i)
                        {
                            lake.start_elevation = current_elevation + 1;
                            last_peak_index = p;
                            break;
                        }
                    }
                    if (lake.start_elevation == NO_VALUE) 
                    {
                        break;
                    }
                }

                lake.current_volume += SLOPE_VOLUME;

                int elevation_diff = abs(lake.start_elevation - current_elevation);
                if (elevation_diff > 1)
                {
                    lake.current_volume += elevation_diff * BLOCK_VOLUME;
                }

                break;
            }
            case kSlopeStay:
            {
                if (lake.start_elevation != NO_VALUE)
                {
                    int elevation_diff = abs(lake.start_elevation - current_elevation);
                    lake.current_volume += elevation_diff * BLOCK_VOLUME;
                }   
                break;
            }
        }
    }

    // Return the total water volume
    return total_volume;
}

I am not sure if it is O(N), but I don't think so, as there is one nested loop in the second for loop. 我不确定是否为O(N),但我不这样认为,因为第二个for循环中有一个嵌套循环。 However, it probably is not O(N^2) also... more something like O((N^2)/2). 但是,它也可能不是O(N ^ 2)……更像是O((N ^ 2)/ 2)。

Could somebody give me advice? 有人可以给我建议吗?

The complexity of the algorithm is O(n + m) where n is the size of your input and m is the number of "peaks," whatever these are. 算法的复杂度为O(n + m) ,其中n是输入的大小, m是“峰值”的数目,无论这些数目是多少。

The reason is that the core algorithm consists of two loops that run roughly n times. 原因是核心算法由大约运行n次的两个循环组成。 One of the loops contains an inner loop. 循环之一包含一个内部循环。 We need to count how many times the body of the inner loop is executed. 我们需要计算内部循环的主体执行了多少次。

The inner loop is run when you encounter a peak, and it looks like the total number of times the body of the loop executes is roughly the number of peaks you have. 当您遇到一个峰时,将运行内部循环,看起来循环主体执行的总次数大约是您拥有的峰数。 It does not matter that the loop is nested: for the complexity calculation, the total number of iterations of the body is what counts. 循环嵌套并不重要:对于复杂度计算,主体的迭代总数才是最重要的。

(Usually a nested loop's iteration count is multiplied rather than added because it is executed in full every iteration of the outer loop, but this is not the case here. You logically are iterating (in the inner loop) from the first peak to the last; notice that you keep track (using p ) of where you break out of the inner loop between iterations of the outer one, and start from p when you return to the inner loop.) (通常,嵌套循环的迭代计数是相乘而不是相加,因为它是在外循环的每次迭代中完全执行,但是这里不是这种情况。您在逻辑上是从第一个峰到最后一个(在内部循环中)进行迭代;请注意,您要跟踪(使用p )在外部循环的两次迭代之间break内部循环的位置,并在返回内部循环时从p开始。)

Am I missing something? 我想念什么吗? I'd rather you have just provided the pseudocode/or necessary lines of code, but it looks like it's just two for loops in a row, and the second for loop has a nested loop. 我希望您只提供了伪代码/或必要的代码行,但看起来它只是一行中的两个for循环,而第二个for循环具有嵌套循环。 That will be O(N^2), no? 那将是O(N ^ 2),不是吗? As your dataset increases, the time complexity should be proportional to the square of your dataset... 随着数据集的增加,时间复杂度应与数据集的平方成正比。

I never mastered this subject though, if someone wants to correct me. 但是,如果有人要纠正我,我永远不会精通此主题。

Edit-- See Comments for why this is wrong..! 编辑-请参阅注释以了解为什么这是错误的..!

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

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