Antes de ler A arte da programação de computadores (TAOCP) , não considerei essas questões profundamente. Eu usaria pseudo-código para descrever algoritmos, entendê-los e estimar o tempo de execução apenas sobre ordens de crescimento. O TAOCP muda completamente de idéia.
O TAOCP usa inglês misturado com etapas e vá para descrever o algoritmo e usa fluxogramas para visualizar o algoritmo mais rapidamente. Parece baixo, mas acho que há algumas vantagens, especialmente no fluxograma, que eu ignorei bastante. Podemos rotular cada uma das setas com uma afirmação sobre o estado atual das coisas no momento em que o cálculo atravessa essa seta e fazer uma prova indutiva do algoritmo. O autor diz:
É a afirmação do autor que realmente entendemos por que um algoritmo é válido somente quando atingimos o ponto em que nossas mentes preencheram implicitamente todas as afirmações, como foi feito na Fig.4.
Eu não experimentei essas coisas. Outra vantagem é que podemos contar o número de vezes que cada etapa é executada. É fácil verificar a primeira lei de Kirchhoff. Não analisei exatamente o tempo de execução; portanto, pode ter sido omitido quando eu estava estimando o tempo de execução.
A análise das ordens de crescimento às vezes é inútil. Por exemplo, não podemos distinguir quicksort de heapsort porque eles são todos , onde é o número esperado de variável aleatória , portanto devemos analisar a constante, digamos, e , assim podemos comparar e melhor. E também, às vezes, devemos comparar outras quantidades, como variações. Apenas uma análise aproximada das ordens de crescimento do tempo de execução não é suficiente. Como TAOCP traduz os algoritmos para a linguagem assembly e calcula o tempo de execução. É muito difícil para mim, então eu quero conhecer algumas técnicas para analisar o tempo de execução um pouco mais a fundo, o que também é útil para linguagens de nível superior, como C, C ++ ou pseudo-códigos.
E quero saber que estilo de descrição é usado principalmente em trabalhos de pesquisa e como tratar esses problemas.
fonte
Respostas:
Existe uma enorme variedade de abordagens viáveis. Qual é o mais adequado depende da
Se o algoritmo é amplamente conhecido e usado como sub-rotina, você geralmente permanece em um nível superior. Se o algoritmo for o principal objeto sob investigação, você provavelmente desejará ser mais detalhado. O mesmo pode ser dito para análises: se você precisar de um limite superior de tempo de execução aproximado, proceda de maneira diferente de quando deseja contagens precisas de instruções.
Vou dar três exemplos para o conhecido algoritmo Mergesort, que espero ilustrar isso.
Alto nível
O algoritmo Mergesort pega uma lista, divide-a em duas (aproximadamente) partes igualmente longas, repete-se nessas listas parciais e mescla os resultados (classificados) para que o resultado final seja classificado. Em listas singleton ou vazias, ele retorna a entrada.
Esse algoritmo é obviamente um algoritmo de classificação correto. Dividir a lista e mesclá-la podem ser implementadas no tempo , o que nos dá uma recorrência para o pior tempo de execução T ( n ) = 2 T ( nΘ(n) . Pelo teorema do mestre, isso é avaliado comoT(n)∈Θ(nlogn).T(n)=2T(n2)+Θ(n) T(n)∈Θ(nlogn)
Nível médio
O algoritmo Mergesort é dado pelo seguinte pseudocódigo:
mergesort
left
right
while
result
result
left
right
while
reverse
while
reverse
mergesort
Nível ultra baixo
Considere esta implementação (generalizada) do Mergesort em Isabelle / HOL :
Isso já inclui provas de bem-definição e rescisão. Encontre aqui uma prova de correção (quase) completa .
Para o "tempo de execução", ou seja, o número de comparações, é possível configurar uma recorrência semelhante à da seção anterior. Em vez de usar o teorema mestre e esquecer as constantes, você também pode analisá-lo para obter uma aproximação assintoticamente igual à quantidade verdadeira. Você pode encontrar a análise completa em [1]; Aqui está um esboço (não necessariamente se encaixa no código Isabelle / HOL):
Como acima, a recorrência do número de comparações é
que, juntamente com a fórmula da Perron, nos leva a
A avaliação de depende de qual caso é analisado. Fora isso, podemos - depois de alguns truques - aplicar o teorema do resíduo para obter⊟(s)
onde é uma função periódica com valores em .A [−1,−0.9]
fonte
A "Disciplina de Programação" de Dijkstra trata de analisar e provar algoritmos e projetar para provabilidade. No prefácio desse livro, Dijkstra explica como uma minilinguagem construída muito simples, projetada adequadamente para ser analisada, é suficiente para explicar formalmente muitos algoritmos:
Mais tarde, ele explica o quão pequeno conseguiu obter sua mini-linguagem.
fonte