Lista de Exercícios 1: Parte II Projeto e Análise de Algoritmos Profa. Jerusa Marchi 1. Em cada uma das seguintes situações, indique se f = O(g) ou f = (g) ou ambos (caso f = _(g)): 2. Prove, usando indução matemática, as seguintes séries: RESP: 3. Selecione uma estrutura de dados que você conheça e discuta seus pontos fortes e fracos. Forneça uma análise da complexidade de manipulação desta estrutura quando um novo item é inserido, buscado e removido. RESP: A estrutura de dados escolhida é uma lista não ordenada. A inserção e remoção não dependem do tamanho do array, logo possuem complexidade constante de O(1). A busca não ordenada será feita por um algoritmo de busca sequencial, que tem complexidade O(n), pois precisará fazer uma comparação com cada elemento da lista. 4. Considere o problema de encontrar o máximo elemento em um vetor. Apresente o pseudocódigo para este problema, prove sua corretude e parada através do loop invariante. Apresente também as funções de complexidade obtidas pelas análises de melhor caso, caso médio e pior caso. RESP: Pseudocódigo: MAXIMO(V):X x = v[0] For i=1 à N { If (v[i] > x) { X=v[i] } } Loop invariante: a cada interação o vetor V não é alterado e um de seus elementos é analisado. - inicialização: x recebe o primeiro elemento do vetor, se o vetor somente tiver um elemento, ele já é o maior. - manutenção: a cada iteração, se o elemento em questão do vetor for maior que o maior atual, o maior atual recebe o elemento do vetor. - término: a iteração termina quando terminam os elementos do vetor (ou seja, i excede n), e o último elemento será o maior do vetor. Análise da complexidade: O algoritmo não se altera no caso do elemento máximo ser o primeiro, último ou estar no meio do vetor. De qualquer forma o algoritmo precisa percorrer uma vez todos os elementos do vetor, isto caracteriza uma função linear, logo a complexidade é O(n), TETA(n) e Omega(n). 5. Considere o problema de somar dois inteiros binários de n bits, armazenados em dois arrays de n elementos A e B. A soma dos dois inteiros deve ser armazenada em forma binária em um array de (n + 1) elementos C. Apresente o pseudocódigo para somar os dois inteiros. RESP: SOMA(A, B): C For i=0 até n, faça: C[i] = A[i]+ B[i]; A complexidade é linear, pois passa uma vez por cada elemento do array. O(n). 6. Considere o algoritmo de Euclides para o cálculo do Máximo Divisor Comum visto em sala. Apresente uma análise de sua complexidade. RESP: Pseudo-código EUCLIDES(a,b):c If (b=0) Return a; Else Return EUCLIDES(b, a mod b); A complexidade de EUCLIDES é O(log b) Conforme demonstra lema 31.10 e teorema 31.11 de Cormen. 7. São dados 2n números distintos distribuídos em dois arrays de n elementos A e B ordenados de modo que A[1] > A[2] > ::: > A[n] e B[1] > B[2] > ::: > B[n] O problema é achar o n-ésimo maior número dentre estes 2n elementos. Imaginemos n=4, por exemplo, conforme abaixo O algoritmo consiste em dividir os dois vetores ao meio, caso n seja potência de 2, ou ao meio menos um, caso contrário, descartando as duas metades onde, sabidamente, não se encontre o n-ésimo maior elemento desejado. Isto pode ser feito comparando os elementos médios dos dois vetores e analisando quais os elementos que não atingem os critérios do alvo procurado. O 4º maior elemento tem que ser no maior do que 4 e menor do que 3 elementos, e se a2 > b2 , teremos que: a1 e a2 são, no mínimo, maiores que 5 elementos b3 e b4 são, no mínimo, menores que 4 elementos Possuímos agora 4 elementos, 2 que são os 3º e 4º maiores e dois que são os 3º e 4º menores, o elemento alvo é, portanto, menor do 1 e maior do 2 elementos, e se a3 > b1 , teremos que: a3 é, no mínimo, maior que 3 elementos b2 é, no mínimo, menor que 3 elementos E nesta situação, por comparação simples, o elemento procurado será o maior entre a4 > b1 (a) Obtenha o limite inferior para o número de comparações necessárias para resolver este problema Como o algoritmo divide a o problema em um conjunto menor pela metade a cada iteração, sua complexidade será de f(n) = O(log n). (b) Apresente um algoritmo cuja complexidade no pior caso seja igual ao valor obtido acima, ou seja um algoritmo ótimo. int Nmax(int p1, int q1, int p2, int q2, int A[n], int B[n]){ int i,j; if (p1==q1 && p2==q2){ // p e q índices de início e fim dos vetores if(A[p1]>B[p2]) return A[p1]; else return B[p2]; } else { i=(int)(q1-p1-1)/2 + p1; // Particiona A j=(int)(q2-p2-1)/2 + p2; // Particiona B if(A[i]>B[j]) // Mantém < A[i] e >= B[j] if ((q1-p1+1)%2==0){ p1=i+1; q2=j; }else { // Mantém < A[i+1] e >= B[j] p1=i+1; q2=j+1; // Caso particular em que n != potência de 2 } else // Mantém < B[j] e >= A[i] if ((q2-p2+1)%2==0){ p2=j+1; q1=i; }else { // Mantém < B[j+1] e >= A[i] p2=j+1; q1=i+1; // Caso particular em que n != potência de 2 } return Nmax(p1,q1,p2,q2,A,B); //Faz a recursão } }//fim de Nmax