DEV Community

Wagner Abrantes
Wagner Abrantes

Posted on

6 1

Complexidade Linear O(n)

Toda complexidade diferente da constante se da em relação ao numero de itens que a sua função recebe, então quanto maior o input maior o tempo de execução do algoritmo. Só que na complexidade linear a diferença é bem proporcional ao tamanho da entrada, ao invés de ser gritante.

Em Big O Notation, complexidade linear é apresentada como O(n). Algoritmos de String matching, como Boyer-Moore (usando a regra de Galil) e Ukkonen tem complexidade linear.

Mas a questão toda não é pegar os algoritmos conhecidos e procurar no Google a complexidade deles e sim enxergar os padrões nesses algoritmos e entender a ponto de flagrar a complexidade no seu código e de outras pessoas. A pergunta a ser feita não é “esse algoritmo é O(n)?” e sim “O porquê desse algoritmo ser O(n)?”.

Se chegar ao final e conseguir responder essa ultima pergunta, você começou a entender Big O Notation.

A complexidade linear,O(n), é demonstrada em um algoritmo da seguinte forma:



package main

import (
    "fmt"
)

func linear(n int) int {
    total := 0
    for i := 1; i <= n; i++ {
        total++
    }
    return total
}

func main() {
    fmt.Println(linear(10))
}


Enter fullscreen mode Exit fullscreen mode

Aqui temos uma operação apenas e não três como anteriormente, nesse caso é total ++ que é o mesmo que: total é igual a total + 1, porém a complexidade é totalmente diferente pois o input também define quantas vezes i será incrementado no for statement. Então quanto maior for o input_(n)_ maior o numero de operações serão feitas em total.

Se no lugar de (i <= n) eu colocasse (i <= 10) seria um tempo constante O(1) mas como o input interfere no for essa complexidade é O(n).

Se formos olhar cada pedaço e dizer o número de operações:

  • total := 0 (Uma operação)
  • i := 0 (Uma operação)
  • i++(N operações)
  • total ++( N operações)

Quando for analisar a complexidade do algoritmo não é necessário contar todas as operações, na maioria das vezes você vai acabar percebendo. Nesse caso como temos operações que são relacionadas a N que é o numero de inputs não tem porque nos preocuparmos com as que são constantes pois a parte linear já dominará a notação de complexidade, então se a gente deixar as constantes de lado sobram apenas as O(n).

E se você tiver dois for statement? Tipo assim:



package main

import "fmt"

func elevador(n) {
    for i := 0 ; i < n; i++{
        fmt.Println(i)
    }

    for j := n - 1 ; j >= 0; j--{
        fmt.Println(j)
    }
}


Enter fullscreen mode Exit fullscreen mode

Ainda assim a complexidade será O(n) e não O(2n) porque Big O é sobre o comportamento quando a entrada cresce muuuuito. Lá perto do infinito e além pouco importa se é n ou 2n.

Pode ser que eu esteja batendo na mesma tecla, porém recomendo que leia mesmo as partes que você considera que já sabe. O maior perigo de aprender é achar que já entendeu e não precisa estudar mais.

Agora temos em perspectiva dois tipos de complexidade a constante em cinza e a linear em azul e agora fica muito óbvio o porque do nome. Repare que dessa vez o input é de 10gb e não 10tb se eu tentasse fazer com um input de 10tb em um algoritmo de complexidade O(n) levaria bem mais tempo. A linha de O(1) permanece plana não leva nem 1 segundo de runtime, a azul com um input de 10gb já leva 18 segundos.

Eu não to falando pra você ficar contando segundo, isso vai depender do seu cenário, mas se você olhar o quanto as linhas já se distanciaram é bastante e como diz o ditado “de grão em grão a galinha enche o papo”.

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up