Como esse algoritmo de classificação Θ (n³) e não Θ (n²) é o pior caso?


52

Acabei de começar um curso sobre Estruturas de Dados e Algoritmos e meu assistente de ensino nos deu o seguinte pseudo-código para classificar uma matriz de números inteiros:

void F3() {
    for (int i = 1; i < n; i++) {
        if (A[i-1] > A[i]) {
            swap(i-1, i)
            i = 0
        }
    }
}

Pode não estar claro, mas aqui n é o tamanho da matriz Aque estamos tentando classificar.

De qualquer forma, o assistente de ensino explicou à classe que esse algoritmo está em Θ(n3) tempo (na pior das hipóteses, acredito), mas não importa quantas vezes eu o atravesse com uma matriz classificada inversamente, parece para mim que deveria ser Θ(n2) e não Θ(n3) .

Alguém poderia me explicar por que isso é e não ?Θ(n3)Θ(n2)


Você pode estar interessado em uma abordagem estruturada da análise ; tente encontrar uma prova você mesmo!
Raphael

Basta implementá-lo e medir para se convencer. Uma matriz com 10.000 elementos na ordem inversa deve levar muitos minutos e uma matriz com 20.000 elementos na ordem reversa deve levar cerca de oito vezes mais.
precisa saber é o seguinte

@ gnasher729 Você não está errado, mas a minha solução é diferente: se você tentar provar seu limite de , irá invariavelmente falhar, o que lhe dirá algo errado. (Obviamente, é possível fazer as duas coisas. Plotar / ajustar é definitivamente mais rápido para rejeitar hipóteses, mas menos confiável . Contanto que você faça algum tipo de análise formal / estruturada, nenhum dano será causado. Basear - se em parcelas é onde começa o problema.)O(n2)
Rafael

11
por causa da i = 0declaração
njzk2

Respostas:


60

Esse algoritmo pode ser reescrito assim

  1. Digitalize Aaté encontrar uma inversão .
  2. Se você encontrar um, troque e comece de novo.
  3. Se não houver, encerre.

Agora pode haver no máximo inversões e você precisa de uma varredura em tempo linear para encontrar cada uma - portanto, o pior caso de execução é . Um belo exemplo de ensino, ao abordar a abordagem de correspondência de padrões que muitos sucumbem!(n2)Θ(n2)Θ(n3)

Nota bene: É preciso ter um pouco de cuidado: algumas inversões aparecem cedo, outras tarde, por isso não é trivial que os custos se acumulem conforme reivindicado (para o limite inferior). Você também precisa observar que os swaps nunca introduzem novas inversões. Uma análise mais detalhada do caso com a matriz inversamente classificada resultará em algo como o caso quadrático da fórmula de Gauss.

Como @ gnasher729 comenta apropriadamente, é fácil ver o pior caso de execução é analisando o tempo de execução ao classificar a entrada (embora essa entrada provavelmente não seja o pior caso).Ω(n3)[1,2,,n,2n,2n1,,n+1]

Cuidado: não assuma que uma matriz classificada inversamente será necessariamente a entrada do pior caso para todos os algoritmos de classificação. Isso depende do algoritmo. Existem alguns algoritmos de classificação em que uma matriz classificada inversamente não é o pior caso e pode até estar próxima do melhor.


14
Se você pegar uma matriz em que a primeira metade consiste nos números 1 a n / 2 em ordem crescente e a segunda metade é n a n / 2 + 1 em ordem inversa, é óbvio que você precisa de pelo menos n / 2 passos para encontrar cada inversão, e haverá cerca de (n / 2) ^ 2/2 deles. E esse provavelmente não é o pior caso.
precisa saber é o seguinte

@AnthonyRossello É um resultado padrão (na combinatória de permutações). Em resumo, conte o número de inversões na matriz classificada inversamente (é óbvio que esse é o pior caso?); é uma soma de Gauss.
Raphael

É preciso lembrar que, não importa o que, as somas parciais de são sempre , é apenas o coeficiente que cai rapidamente: (observe o coeficiente bastante grande ). O problema é que não se importa com coeficientes. Θ(nα)Θ(nα+1)k=0nkα1α+1nα+11α+1Θ
yo'

2
@yo 'E isso está relacionado à resposta (ou à pergunta) como?
Raphael

7

Uma maneira alternativa de pensar sobre isso é qual é o valor máximo de iantes de ser redefinido. Acontece que isso torna mais simples o raciocínio sobre como a ordem de classificação anterior Aafeta o tempo de execução do algoritmo.

Em particular, observe que quando idefine seu novo valor máximo, vamos chamá-lo de N, a matriz [A[0], ..., A[N-1]]é classificada em ordem crescente.

Então, o que acontece quando adicionamos o elemento A[N]à mistura?

A matemática:

Bem, digamos que ele se encaixa na posição . Em seguida, precisamos de iterações de loop (que eu denotarei ) para movê-lo para colocar as iterações , para movê-lo para colocar e, em geral:pNNstepsN1N+(N1)N2

stepsN(pN)=N+(N1)+(N2)++(pN+1)=12(N(N+1)pN(pN+1))

Para uma matriz classificada aleatoriamente, assume a distribuição uniforme em para cada , com:pN{0,1,,N}N

E(stepsN(pN))=a=1NP(pN=a)stepsN(a)=a=1N1N12(N(N+1)a(a+1))=12(N(N+1)13(N+1)(N+2))=13(N21)=Θ(N2)

a soma pode ser mostrada usando a fórmula de Faulhaber ou o link Wolfram Alpha na parte inferior.

Para uma matriz inversamente classificada, para todos os e obtemos:pN=0N

stepsN(pN)=12N(N+1)

exatamente, levando estritamente mais tempo do que qualquer outro valor de .pN

Para uma matriz já classificada, e , com os termos de ordem inferior se tornando relevantes.pN=NstepsN(pN)=0

Tempo total:

Para obter o tempo total, que soma-se os passos de toda a fazenda . (Se estivéssemos sendo super cuidadosos, resumiríamos os swaps e as iterações do loop e cuidaríamos das condições de início e fim, mas é razoavelmente fácil ver que eles não contribuem para a complexidade na maioria dos casos) .N

E, novamente, usando linearidade de expectativa e a fórmula de Faulhaber:

Expected Total Steps=E(N=1nstepsN(pN))=N=1nE(stepsN(pN))=Θ(n3)

Obviamente, se por algum motivo não for (por exemplo, a distribuição de matrizes que estamos vendo já está muito perto de ser classificada), isso nem sempre será necessário. Seja o caso. Mas são necessárias distribuições muito específicas no para conseguir isso!stepsN(pN)Θ(N2)pN

Leitura relevante:


@ Rafael - obrigado pelas melhorias sugeridas, eu adicionei um pouco mais de detalhes. Bem, as variáveis ​​aleatórias são (de , o conjunto de ordenações de ), de modo que as expectativas são tecnicamente feitas sobrepiΩAΩ
David E

diferente ; Eu quis dizer o Landau. Ω
Raphael

3

Aviso Legal:

Isso não é uma prova (parece que algumas pessoas pensam que eu postei como se fosse). Esta é apenas uma pequena experiência que o OP poderia realizar para resolver suas dúvidas sobre a tarefa:

não importa quantas vezes eu o atravesse com uma matriz classificada inversamente, parece-me que deve ser e não .Θ(n2)Θ(n3)

Com um código tão simples, a diferença entre e não deve ser difícil de detectar e, em muitos casos práticos, essa é uma abordagem útil para verificar pressentimentos ou ajustar expectativas.Θ(n2)Θ(n3)


O @Raphael já respondeu à sua pergunta, mas apenas para chutes, ajustando a saída deste programa para usando esse script gnuplot relatou valores de expoente de e e produziu os seguintes gráficos ( a primeira é a escala normal e a segunda é a escala log-log):f(x)=axb+cx2.997961668332222.99223727692339

normal loglog

Espero que isso ajude¨


2
Você pode ajustar qualquer função a esses valores. Veja também aqui .
Raphael

3
@Raphael Se você não quiser escolher dessa maneira, então não, não poderá ajustar nenhuma função (por exemplo, você não poderá ajustar uma função constante com precisão razoável). Isso não é uma prova, mas já existe uma resposta que fornece um esboço. Quanto à utilidade, posso citar seu próprio post que você vinculou: "Eu tenho que concordar que essa é uma abordagem muito útil que às vezes é subutilizada". Além disso, o OP disse que achava que deveria ser vez de , então por que não experimentar e ver se seu palpite estava correto? Cont. Θ(n2)Θ(n3)
precisa saber é o seguinte

2
Isso fornece evidências de que o algoritmo é mas a pergunta pergunta o porquê . Está pedindo uma explicação do fenômeno, não uma confirmação dele. Θ(n3)
David Richerby

2
@DavidRicherby Isso significa que esta resposta não é útil?
precisa saber é o seguinte

3
@ Magicsowon É um site de perguntas e respostas, não um fórum. Estamos procurando respostas para a pergunta, não discussões sobre ela.
David Richerby

3

Suponha que você tenha uma matriz.

array a[10] = {10,8,9,6,7,4,5,2,3,0,1}

Seu algoritmo faz o seguinte

Scan(1) - Swap (10,8) => {8,10,9,6,7,4,5,2,3,0,1}  //keep looking at "10"
Scan(2) - Swap (10,9) => {8,9,10,6,7,4,5,2,3,0,1}
...
Scan(10) - Swap(10,1) => {8,9,6,7,4,5,2,3,0,1,10}

Basicamente, ele move para o final da matriz o elemento mais alto e, ao fazer isso, ele começa a exceder a cada varredura efetivamente fazendo O(n^2)movimentos ... apenas para esse elemento. No entanto, existem n elementos, por isso teremos que repetir esse ntempo. Esta não é uma prova formal, mas ajuda a entender de uma maneira "não formal" por que o tempo de execução é O(n^3).


4
O que isso acrescenta sobre outras respostas? Uma explicação do que o algoritmo faz já foi fornecida, e seu raciocínio para o tempo de execução é superficial na melhor das hipóteses. (Na pior das hipóteses, não se comporta linearmente!)
Raphael

2
Às vezes, vale a pena explicar a mesma idéia de várias maneiras (com formalismo; com um exemplo simples para "bombear a intuição"), especialmente quando a pessoa que faz a pergunta é nova no campo. Então, para mim, o que isso acrescenta é que é apresentado de uma maneira que pode ajudar a intuição.
DW

Desde que recebi uma resposta ao meu comentário em uma bandeira (não faça isso!): "O pior caso não se comporta linearmente!" - Quero dizer as propriedades algébricas do operador de pior caso. Grosso modo, você está usando o WorstCase (1 + ... + n) "=" WorstCase (1) + ... + WorstCase (n), mas essa identidade não é válida.
Raphael

11
Sou novo nesse campo e fornecer uma explicação com um exemplo concreto e detalhado me ajudou a ganhar intuição sobre o problema. Agora, a solução aceita faz mais sentido para mim.
Vær-k

0

A lógica parece estar classificando os elementos na matriz em uma ordem crescente.

Suponha que o menor número esteja no final da matriz (a [n]). Para que ele chegue ao seu devido lugar - (n + (n-1) + (n-2) + ... 3 + 2 + 1) são necessárias operações. = O (n2).

Para um único elemento na matriz, são necessárias operações O (n2). Então, para elementos é O (n3).


5
O que isso acrescenta sobre outras respostas? Uma explicação do que o algoritmo faz já foi fornecida, e seu raciocínio para o tempo de execução é superficial na melhor das hipóteses. (Na pior das hipóteses, não se comporta linearmente!)
Raphael

Ótima explicação. Isso fornece uma perspectiva diferente e mais intuitiva sobre o problema, não explicada em outras respostas. (Para não mencionar muito curto e fácil de entender.)
2501 18/01

11
@ 2501 Não, está errado. Tente usar essa "intuição" no algoritmo de Dijkstra e você obterá o tempo de execução quadrático (no número de nós), o que está errado.
Raphael

@ Rafael Não, está certo, como explicado na resposta. Essa explicação funciona para esse algoritmo, não para outros. Embora possa estar errado para eles, essa alegação não prova que está errado para esta.
2501

@ Rafael Não entendi a explicação na resposta aceita. Então, resolvi isso e tentei explicá-lo em termos simples, sem termos técnicos .. então, isso é para membros como eu que não conseguiram entender a resposta aceita. Fico feliz que alguém esteja achando isso útil.
mk .. 18/01
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.