Transcript
  • Recursividade e Iterao (cont.) Processamento de TextoPedro BarahonaDI/FCT/UNLAbril 2005

    Recursividade e Iterao

  • Recursividade para Resoluo de ProblemasA recursividade pode ser usada na resoluo de problemas, difceis de resolver por outras tcnicas de programao. Tal o caso das Torres de Hanoi: dadas trs torres (estacas) pretende-se passar uma pirmide de peas ordenadas de uma torre para outra, movendo-se uma pea de cada vez, para o topo de uma torre encimada por uma pea menor.

    Recursividade e Iterao

  • Torres de Hanoi - Recursividade Apesar de aparentemente complicado, este problema tem uma soluo recursiva simples.Para passar n peas de uma torre (A) para outra (C)Passar n-1 peas da torre inicial (A) para a torre livre (B)Mover a ltima pea, para a torre final (C)Passar as n-1 peas da torre B para a torre final (C).

    Recursividade e Iterao

  • Torres de Hanoi: Movimentos NecessriosBaseados nesta resoluo recursiva podemosDeterminar o nmero de movimentos necessriosDeterminar os movimentos necessriosO nmero de movimentos necessrios bastante simples de determinar, na verso recursivahanoi_count(n) = hanoi_count(n-1)+1+ hanoi_count(n-1) Neste caso, pode-se evitar a dupla recursividade (ver adiante) de uma forma muito simpleshanoi_count(n) = 2*hanoi_count(n-1) + 1Finalmente, h que especificar a condio de paragem (n=1)hanoi_count(1) = 1

    Recursividade e Iterao

  • Torres de Hanoi: Movimentos NecessriosUm programa Octave para resolver o programa imediatofunction c = hanoi_count(n) if n == 1 c = 1; else c = 2*n_hanoi_count(n-1)+1; end;endfunction;De notar o aumento exponencial do nmero de movimentos necessrios

    Recursividade e Iterao

    Sheet1

    n123456789101112131415

    count13715316312725551110232047409581911638332767

    Sheet2

    Sheet3

  • Torres de HanoiO problema propriamente dito pode ser resolvido com base num vector T, com 3 nmeros, correspondentes ao nmero de peas em cada uma das torres.

    Notar que no necessrio indicar o tamanho de cada pea, porque o algoritmo nunca coloca uma pea sobre uma menor!O movimento de uma s pea da torre A para a torre B, usado no corpo da recurso e na sua terminao, pode ser feito com uma funo auxiliar, move_hanoi(T,A,B), especificada da forma bvia (tira uma pea de A e aumenta em B).

    Recursividade e Iterao

  • Torres de Hanoifunction T = hanoi(T,N,A,B) % move N peas de A para B if N == 1 T = hanoi_move(T,A,B); % move a pea de A para B else C = 6-A-B; % C a outra torre! T = hanoi(T,N-1,A,C); % move N-1 peas de A para C T = hanoi_move (T,A,B);% move 1 pea de A para B T = hanoi(T,N-1,C,B); % move N-1 peas de C para B end;endfunction;

    function T = hanoi_move(T,A,B) T(A) = T(A) - 1; T(B) = T(B) + 1; disp(T);endfunction;

    Recursividade e Iterao

  • Torres de HanoiO funcionamento do programa pode ser visto com a chamada>> hanoi([4,0,0],4,1,3);400310211202112211220130031022112211202112013004move(_,1,3)

    Recursividade e Iterao

  • Recurso e IteraoEm geral, uma funo ou procedimento definidos recursivamente podem-no ser tambem de uma forma iterativa (atravs de ciclos).Em geral, a definio recursiva mais declarativa na medida em que explicita o que se pretende obter e no a forma como se obtem (ou seja, um determinado programa que usado).Por outro lado, uma definio iterativa, embora no permita uma compreenso to imediata, geralmente mais eficiente, j que as instrues de programao de baixo nvel para a iterao so mais eficientes que as de chamadas de funes.No entanto, estas diferenas so geralmente pouco importantes, excepto em casos de recurso mltipla, em que a ineficincia pode ser catastrfica.

    Recursividade e Iterao

  • Recurso e Iteraofunction f = fib(n); % verso recursiva if n
  • Recurso e IteraoEsta a situao da funo de Fibonacci, em que o seu valor depende de 2 chamadas recursivas. Como as chamadas so independentes, a mesma funo acaba por ser recalculada vrias (muitas !) vezes.Na realidade, o nmero de funes chamadas o prprio nmero de fibonacci (7:1, 6:1, 5:2, 4:3, 3:5, 2:8) que aumenta exponencialmente com o valor de n.

    Recursividade e Iterao

  • Recurso e IteraoPara se ter uma ideia do aumento, podemos notar que apesar de inicialmente pequenos

    os nmeros tornam-se rapidamente enormes

    tornando proibitiva a sua computao recursiva (normal).

    Recursividade e Iterao

    Sheet1

    n1234567891011

    fib(n)1123581321345589

    Sheet2

    Sheet3

    Sheet1

    n26272829303132

    fib(n)12139319641831781151422983204013462692178309

    Sheet2

    Sheet3

    Sheet1

    n454647484950

    fib(n)1134903170183631190329712150734807526976777874204912586269025

    Sheet2

    Sheet3

  • MemorizaoPor vezes possvel aliar a declaratividade da verso recursiva, com a eficincia da verso iterativa, atravs da memorizao dos valores j computados.Por exemplo se se pretenderem os primeiros 100 nmeros de fibonacci, pode criar-se uma tabela, fib_m, com os valores j computados. Se fib_m(n) ainda no contiver o valor de fib(n), ento determina-se fib(n) e escreve-se em fib_m(n).Caso contrrio, apenas se retorna o valor de fib_m(n).Para que este esquema seja possvel, conveniente que a tabela fib_m seja visvel por todas as instncias da funo fib(n). Para evitar pass-la como parmetro deve declarar-se como uma varivel global.

    Recursividade e Iterao

  • Variveis Globais em OctaveEm Octave, para que uma varivel seja global, ela deve ser declarada no programa principal com a declarao global. No caso actual, se se pretende um vector linha com 100 elementos inicializados a zero, devemos declarar a varivel globalfib_m = zeros(1,100);global fib_m;Uma vez declarada uma varivel global, ela pode ser eliminada atravs da declarao clear. Se pretendermos um vector com 200 elementos deveremos fazerclear fib_m fib_m = zeros(1,200)

    Recursividade e Iterao

  • MemorizaoPara que, na funo, a varivel fib_m considerada seja a varivel global e no uma varivel local, a varivel deve ser identificada novamente como global.function f = fib_mem(n); %verso recursiva c/ memria global fib_m; if fib_m(n) > 0 f = fib_m(n); else if n
  • Processamento de TextoMuita informao til, nomeadamente em tarefas de gesto, no do tipo numrico.Por exemplo, variadas entidades (pessoas, empresas, disciplinas, departamentos, etc...) tm associado um nome que se pode querer processar (por exemplo ordenar).Este apenas um exemplo de situaes em que se pretende que os programas efectuem processamento de texto.Todas as linguagens de programao prevem pois tipos de dados para este fim, nomeadamente Caracteres;Cadeias de caracteres (strings).

    Recursividade e Iterao

  • CaracteresOs caracteres mais utilizados (representados no cdigo ASCII - American Standard Code for Information Interchange) incluemLetras (52), maisculas (26) e minsculas (26)Dgitos (10)Espao e outros caracteres visveis (34) ( ) [ ] { } , . : ; = < > + - * \ | / ^ ~ ` # $ % & _ ! ? @Caracteres de controle (32)horizontal tab (\t), new line (\n), alert (\a), ...Outros caracteres, (, , , , , , , , , , , ) s podem ser representados em cdigos mais avanados e no so suportados em algumas linguagens de programao (em Octave, uma varivel no pode ter o nome aco)

    Recursividade e Iterao

  • Cadeias de CaracteresCadeias de caracteres (strings) so sequncias (ordenadas) de caracteres. Em quase todas as linguagens, dados do tipo caracter e cadeia (incluindo simples caracteres) so representados entre delimitadores, que podem ser aspas ( ) ou plicas ( ).Devem sempre abrir-se e fechar-se com o mesmo tipo de delimitadores.Quando se pretende incluir um dos delimitadores no texto, podem usar-se sequncias de escapenome = Maria Martins d\Albuquerqueou usar-se o outro delimitador nome = Maria Martins dAlbuquerquefrase = Ele exclamou: ptimo e fugiu

    Recursividade e Iterao

  • Cadeias de Caracteres e VectoresEm geral, e Octave no foge regra, cadeias de caracteres so implementadas como vectores dos cdigos dos caracteres.Muitas funes e operaes em Octave exigem a utilizao do tipo correcto. Duas funes permitem transformarVectores em cadeias : toascii: >> a = toascii(ABC) a = [65,66,67] Cadeias em vectores : setstr: >> b = setstr([97,98,99]) b = abc O Octave no muito estrito no que se refere aos tipos de dados. Por exemplo, permite operaes numricas com cadeias, fazendo a converso de tipos necessria>> c = abc* 1 c = [97,98,99]Nota: Estas facilidades tornam difcil a deteco de erros de programao e no devem ser usadas (ou apenas com muito cuidado)

    Recursividade e Iterao

  • Converso de Cadeias de CaracteresCadeias de caracteres podem ser processados de vrias formas. Para as mais comuns, existem funes pr-definidas.Algumas dessas funes permitem converter cadeias de caracteres que representam nmeros para os prprios nmeros.Exemplo: Dada a cadeia 23.76 (com espaos), a sua converso para um nmero obtida com a funo str2num.>> s = 23.76 ; a = str2num(s); b = 2*a b = 47.52 interessante comparar o resultado acima com (porqu???)>> s = 23.76 ; b = 2*s s = [64,100,102,92,110,108,64,64]A converso oposta, pode fazer-se com a funo num2str.

    Recursividade e Iterao

  • Concatenao de Cadeias de CaracteresAs cadeias podem ser concatenadas. Esta operao utilizada para juntar numa s cadeia a informao que est dispersa por vrias cadeias. Por exemplo, para juntarO(s) nome(s) prprio(s) ao(s) apelido(s)Os vrios campos de um enedereo (rua, n, andar, local, etc.)O Octave tem uma funo strcat, para esse efeito.Exemplo: Juntar um nome prprio e um apelido.>> np = Rui; ap = Lopes; nome= strcat(np, ,ap) nome = Rui LopesDe notar a utilizao da cadeia com um branco ( ) para espaar o nome prprio e o apelido.

    Recursividade e Iterao

  • Partio de Cadeias de CaracteresAs cadeias podem ser partidas noutras mais simples. Neste caso pode haver vrias formas de fazer a partio. Uma possvel atravs de caracteres que funcionam como separadores (tipicamente espaos). O Octave tem uma funo, split, para esse efeito, criando uma matriz de cadeias, cada cadeia na sua linha, com brancos acrescentados se necessrioExemplo: Separar os nomes (prprios e apelidos) de uma pessoa.>> nome = Rui da Costa Pina; nms = split(nome, ) nms = Rui da Costa Pina

    Recursividade e Iterao

  • Extraco de Cadeias de CaracteresPor vezes estamos interessados apenas em partes de uma cadeia. Uma forma comum de o fazer indicar o ndice do primeiro caracter pretendido para a subcadeia; e o comprimento da subcadeia. O Octave tem uma funo, substr, para esse efeito. Por exemplo: Separar os nomes (prprios e apelidos) de uma pessoa.>> nome = Rui da Costa Pina; nm1 = substr(nome,1,3), nm2 = substr(nome,5,2), nm3 = substr(nome,8,5), nm4 = substr(nome,14,4), nm1= Rui, nm2= da, nm3= Costa, nm4= PinaOs ndices variam de 1 ao comprimento da cadeia. Este comprimento obtido pela funo length.>> nome = Rui da Costa Pina; x = length(nome) x= 17

    Recursividade e Iterao

  • Comparao de CaracteresUma operao vulgar no processamento de texto a ordenao por ordem alfabtica. Esta ordenao requer a comparao alfabtica de caracteres. Esta pode ser feita atravs da comparao numrica dos cdigos dos caracteres. A comparao s fcil se os cdigos usados respeitam a ordem alfabtica, o que acontece em todos os cdigos. Por exemplo em ASCII, o cdigo dos caracteres A e B , respectivamente, 65 e 66, pelo que se pode fazer a correspondncia pretendidao caracter c1 vem antes do caracter c2 c1 < c2Exemplo: >> teste = a < b teste = 1

    Recursividade e Iterao

  • Comparao de Cadeias de CaracteresA comparao literal pode ser obtida a partir da comparao caracter a caracter. O Octave tem uma funo, strcmp, para verificar se duas cadeias so idnticas. >> nm1 = Rui Costa; nm2 = Rui Costa; t = strcmp(nm1,nm2) t = 1Para o teste de precedncia alfabtica (designado por
  • Comparao de Cadeias de Caracteresfunction t = my_str_tail(s) c = length(s); if c == 1 t =""; else t = substr(s,2,c-1); endif;endfunction;Dada a natureza recursiva da funo my_before, esta utiliza uma funo auxiliar, my_str_tail, para obter a cauda da cadeia (isto , sem o seu primeiro caracter).A funo my_before compara os primeiros caracteres das cadeias (se existirem). Se estes forem iguais, compara as caudas das cadeias (chamada recursiva).

    Recursividade e Iterao

  • Comparao de Cadeias de Caracteresfunction b = my_str_before(s1,s2) c1 = length(s1); c2 = length(s2); if c1 == 0 & c2 == 0 b = 0; elseif c1 == 0 & c2 > 0 b = 1; elseif c1 > 0 & c2 == 0 b = -1; else % c1 > 0 & c2 > 0 if s1(1) < s2(1) b = 1; elseif s1(1) > s2(1) b = -1; else t1 = my_str_tail(s1); t2 = my_str_tail(s2); b = my_str_before(t1,t2); endif; endif;endfunction;

    Recursividade e Iterao

  • Comparao de Cadeias de CaracteresA comparao de cadeias de caracteres interpretveis (por exemplo, de texto em portugus) mais complexa.Os problemas mais frequentes so de 3 tipos:Ocorrncia de espaos (e outros caracteres brancos)Rui Santos = Rui Santos ???Tratamento de letras maisculas e minsculasRui Santos = RUI SANTOS ???Caracteres especiais (com acentos e cedilhas)Joo Frana = Joao Franca ???Estes problemas tm de ser considerados no contexto apropriado (Franca e Frana so apelidos diferentes, ou o terminal (telemvel) no tinha o caracter ?), e requerem algoritmos dedicados.

    Recursividade e Iterao

  • Comparao de Cadeias com BrancosOs caracteres brancos servem para separar os significativos. Os mais vulgares so os espaos, mas existem outros para mudana de linha (\n, \r ou \f), ou tabulao (\t e \v).No cdigo ASCII todos tm cdigos inferiores a 32 (espao).A comparao de cadeias pode simplificar-se se a comparao fr feita aps normalizao. Esta normalizao, consiste em eliminar todos os brancos prefixos/sufixos, i.e. antes/depois do primeiro/ltimo caracter significativo. Substituir todos os separadores (grupos de brancos, tabs, mudanas de linha, etc. por um s branco).Algumas funes pre-definidas podem auxiliar na normalizao, mas o Octave no tem esta funo predefinida.

    Recursividade e Iterao

  • Substituio de Brancos por EspaosAssumindo que todos os caracteres brancos tm cdigo inferior a 32, podemos utilizar a funo my_str_remctr, indicada abaixo, para substituir todos os caracteres brancos por espaos.function t = my_str_remctr(s) for i = 1:length(s) if toascii(s(i)) < 32 t(i) = " "; else t(i) = s(i); endif; endfor;endfunction;

    Recursividade e Iterao

  • Eliminao de Brancos Prefixos e Sufixos O Octave dispe de uma funo (deblank) que elimina todos os espaos sufixos. A eliminao dos brancos prefixos pode igualmente usar essa funo se se inverter (pass-la de trs para a frente) a cadeia. Essa inverso pode usar a funo my_str_rev, indicada abaixo

    function r = my_str_rev(s) c = length(s); for i = 1:c r(i) = s(c-i+1); endforendfunction;

    Recursividade e Iterao

  • Eliminao de Espaos Repetidos A eliminao dos espaos repetidos pode ser feita usando a funo my_str_remrep, indicada abaixo. A funo percorre toda a cadeia mantendo a informao (na varivel booleana ultimo_branco) sobre se o ltimo caracter era branco. Nesse caso, se o caracter fr espao no o copia (seria repetido).

    function t = my_remrep(s) j = 1; ultimo_branco = 0; for i = 1:length(s) if s(i) != " " t(j) = s(i); j = j+1; ultimo_branco = 0; elseif !ultimo_branco t(j) = s(i); j = j+1; ultimo_branco = 1; endif; endfor;endfunction;

    Recursividade e Iterao

  • Normalizao de Cadeias de Caracteres A normalizao de cadeias de caracteres pode ser feita usando a funo my_str_norm, indicada abaixo, que utiliza todas as funes anteriores, da forma esperada. Primeiro, substitui os brancos por espaos. Depois elimina os espaos sufixos. Em terceiro lugar elimina os brancos prefixos (eliminando os brancos sufixos da cadeia invertida, invertendo de novo o resultado). Finalmente, os espaos repetidos so removidos.

    function sn = my_str_norm(s) s1 = my_str_remctr(s) s2 = deblank(s1); s3 = my_str_rev(deblank(my_str_rev(s2))); sn = my_str_remrep(s3);endfunction;

    Recursividade e Iterao

  • Comparao de Cadeias com Brancos function b = my_str_norm_before(s1,s2) sn1 = my_str_norm(s1); sn2 = my_str_norm(s2); b = my_str_before(sn1,sn2);endfunction;A comparao de cadeias de caracteres pode ser feita usando a funo my_str_norm_before, indicada abaixo, que no considera os caracteres brancos.As diferenas podem ser exemplificadas em baixo.>> t = my_str_before(Rui Lopes, Rui Lopes) t = -1>> t = my_str_norm_before(Rui Lopes, Rui Lopes) t = 0

    Recursividade e Iterao

  • Comparao com Maisculas/MinsculasA comparao de cadeias de caracteres pode ser igualmente prejudicada pela existncia de letras maisculas e minsculas.O Octave tem algumas funes que facilitam o tratamento deste tipo de situaes, nomeadamente as funes tolower e toupper, que convertem os caracteres maisculos / minsculos em caracteres minsculos / maisculos.>> s1 = \n Rui \t Lopes; s2 = RUI lopes; sn1 = toupper(s1), sn2 = toupper(s2), t1 = my_str_norm_before(s1,s2), t2 = my_str_norm_before(sn1,sn2) sn1 = \n RUI \t LOPES sn2 = RUI LOPES t1 = -1 t2 = 0

    Recursividade e Iterao

  • Converso entre Maisculas/MinsculasAs funes anteriores assumem um cdigo ASCII, em que os caracteres brancos tm cdigos abiaxo de 32. Nesse cdigo ASCII, a converso entre maisculas e minsculas pode ser feita adicionando ou subtraindo a sua diferena aos cdigos respectivos. Esta diferena 32, como pode ser verificado em>> dif = toascii(A) toascii(a) dif = -32No entanto, a utilizao destes valores pode ser problemtica, se forem usados outros cdigos. da responsabilidade da implementao da linguagem interpretar ter em ateno os cdigos usados (que podem no ser ASCII) e disponibilizar primitivas independentes desses cdigos.

    Recursividade e Iterao

  • Converso independente do CdigoAlgumas dessas primitivas soisalpha(s) 1 se s fr alfabtico (maiscula ou minscula)islower(s)1 se s fr uma minsculaisupper(s)1 se s fr uma maisculaisdigit(s)1 se s fr um dgitoisalnum(s)1 se s fr dgito ou alfabticoispucnt1 se s fr um caracter de pontuaoiscntrl(s)1 se s fr caracter de controle Desta forma as funes podero ser rectificadas para se tornarem independentes do cdigo usado para representao dos caracteres. Em particular, o testetoascii(s(i)) < 32 pode/deve ser substituido poriscntrl(s2)

    Recursividade e Iterao

  • Cadeias com Caracteres EspeciaisOs caracteres com cedilhas e acentos, tpicos do portugus, no fazem parte do cdigo ASCII bsico, e os seus cdigos em ASCII estendido no respeitam a ordem natural. Por exemplo, como os cdigos dos caracteres a, s e so, respectivamente 97, 115 e 227, o nome Joo est alfabeticamente aps Jos, ao contrrio do que acontece com Joao. Uma forma de manter a ordenao pretendida utilizar, para efeitos de ordenao, as cadeias com os caracteres acentuados substitudos pelos caracteres no acentuados. O Octave dispe de uma funo (strrep) que substitui numa cadeia base, todas as de uma (sub)cadeia por outra. >> s1 = Joo; s2 = strrep(s1,,a) s2 = Joao

    Recursividade e Iterao


Recommended