Вы находитесь на странице: 1из 27

Estruturas de Dados

Introduo

Este material tem como objetivo apresentar aos alunos de computao as estruturas de dados mais utilizadas e sugeridas como abordagem pela SBC. Sero desenvolvidos os conceitos de listas lineares e suas generalizaes como pilhas, filas e listas, alm de rvores, rvore binria de busca, AVL, e uma rpida passagem por arvores B. O desenvolvimento dos conceitos ser feito atravs da explicao terica do assunto, exemplos de utilizao de estruturas, desenvolvimento dos exemplos e ao final de cada captulo exerccios propostos que visam no s a fixao do conhecimento, mas tambm o desenvolvimento do raciocnio do aluno. A linguagem escolhida para a abordagem destas estruturas o Pascal, e foi escolhida por ser uma linguagem didtica. Os programas iro ser propostos atravs de TADs, ou seja, a criao de tipos abstratos de dados como units para que os cdigos possam ser reutilizados durante a leitura e mesmo aps o termino do curso. Os conceitos necessrios para desenvolvimento dos algoritmos em pascal sero apresentados no inicio, para que no haja duvidas com relao linguagem. necessrio um conhecimento intermedirio de pascal para o acompanhamento dos algoritmos.

1. Conceitos de Pascal
Para a utilizao de estruturas de dados iremos precisar saber como declarar variveis, como manipular ponteiros, registros e units.

1.1 Units Units definidas pelo usurio so como units j definidas como a CRT, podero ser usadas em qualquer programa que voc fizer. A estrutura de uma unit a seguinte: unit nome_da_unit; interface type var procedure teste(var i : integer); implementation procedure teste(var i : integer); begin end; end. O arquivo da unit deve ser salvo com o mesmo nome que o escolhido como nome da unit. Na parte interface devem ser colocados todos os tipos e variveis que os procedimentos utilizam e apenas o cabealho do procedimento. Na parte implementation os procedimentos so declarados normalmente e desenvolvidos normalmente e devem estar com o mesmo cabealho que foi declarado em cima. Um programa teste para uma unit deve ser feito normalmente, e como inclumos units definidas, inclumos tambm units criadas, porm estas devem estar na mesma pasta do programa. Feito isso, os procedimentos podem ser utilizados normalmente como se fossem procedimentos do programa principal. A unit deve ser compilada. Uma maneira de se esconder procedimentos, ou seja, declarar procedimentos para utilizao apenas pela unit, fazendo-os normalmente na parte implementation sem declar-los na interface. As variveis declaradas na unit devem ser usadas apenas internamente. A seguir temos um exemplo de unit e programa de teste para a implementao de vetores :

unit vetor; // deve ser salvo como vetor.pas interface type vet = array[1..10] of integer;//vetor 10 posicoes de inteiros var numero_insercoes,i : integer; // variaveis usadas no programa procedure iniciaVetor(var novo:vet); procedure insereVetor(var novo:vet; x,pos : integer); procedure deletaVetor(var novo:vet; pos:integer); procedure imprimeVetor(var novo:vet);

implementation function testaPosicao(var pos : integer):boolean;//procdimento local que begin //testa se a posicao existe if pos > 10 then begin testaPosicao := false; end else begin testaPosicao := true; end; end; procedure insereVetor(var novo:vet; x,pos : integer);// insere valores no vetor begin if testaPosicao(pos) then begin if novo[pos]<>0 then begin writeln('A posicao esta ocupada'); end else begin novo[pos] := x; numero_insercoes := numero_insercoes + 1; writeln('o numero de insercoes : ',numero_insercoes); end; end else begin writeln('nao foi possivel inserir');

end; end;

procedure iniciaVetor(var novo:vet); // inicia o vetor begin for i:=1 to 10 do begin novo[i] := 0; end; end; procedure deletaVetor(var novo:vet; pos:integer);//atribui 0 a uma posicao begin //do vetor if testaPosicao(pos) then begin novo[pos] := 0; end else begin writeln('nao foi possivel remover'); end; end; procedure imprimeVetor(var novo:vet);// imprime o vetor begin for i := 1 to 10 do begin writeln(novo[i]); end; end; end. Programa teste em um arquivo diferente: program teste; uses vetor,crt; var vetor1 : vet;

begin iniciaVetor(vetor1); insereVetor(vetor1,1,1);

insereVetor(vetor1,2,2); insereVetor(vetor1,3,3); insereVetor(vetor1,4,4); insereVetor(vetor1,5,5); insereVetor(vetor1,5,5); insereVetor(vetor1,6,6); insereVetor(vetor1,7,7); insereVetor(vetor1,8,8); insereVetor(vetor1,9,9); imprimeVetor(vetor1); readkey; end. 1.2 Ponteiros Como a partir de agora j sabemos desenvolver units, o prximo passo aprender como programar utilizando ponteiros. Ponteiros nada mais so que espao de memria que apontam para outros, e exibem a informao do local para onde esto apontando. Para declararmos uma varivel ponteiro em pascal utilizamos:

p: ^integer;
LEIA : P PONTEIRO PARA UM INTEIRO, onde integer pode ser substitudo por qualquer tipo de dados como vetores, registros, strings, etc. Para criarmos uma varivel dinmica usamos o comando:

new(p);
onde p o nome da varivel que ponteiro para alguma coisa. No caso de registros podemos definir da seguinte maneira : ( a seguir temos a declarao dos tipos e como nos referimos aos campos do registro que so apontados) type pUnidade = ^unidade; unidade = record x : integer; y : integer; end;

procedure inicioVarivael(var t: pUnidade); begin new(t);//aloca um espao na memria do tipo de t t^.x :=0;// leia - t ponteiro ponto x 6

t^.y :=0; end; No caso acima, t^.x um inteiro, e queremos dizer com a linha que o espao de memria para um inteiro armazenado recebe 0. E dessa forma acessamos todas as posies do registro que fizemos o ponteiro apontar. Abaixo temos um exemplo de programa com os conceitos vistos acima: program teste_ponteiro; uses crt;

type pUnidade = ^unidade; unidade = record x : integer; y : integer; end; var t : pUnidade; begin new(t); t^.x := 2; t^.y := 4; writeln(t^.x,' ',t^.y); readkey; end. Para que o ponteiro receba um valor nulo, usamos a seguinte forma:

P := nil;
isso faz com que o ponteiro aponte para lugar nenhum. Outro comando que importante o comando :

dispose(p);
que desaloca o espao de memria alocado pelo comando new. Termina aqui a abordagem sobre pascal, junto aos conceitos bsicos, estes so suficientes para o desenvolvimento dos algoritmos que sero apresentados.

2. Estruturas Dinmicas
O estudo de estruturas dinmicas de dados ser iniciado com Listas e depois ir passar por pilhas e filas, e por fim, rvores. Comearemos por listas, pois o caso mais generalizado, depois de definidas todas as operaes com listas ser fcil introduzir e comentar o conceito de pilhas e filas. 2.1 Listas As listas lineares nada mais so que uma coleo de ns, uns interligados aos outros com ponteiros, que possui um primeiro elemento, um ultimo elemento e uma ordem unidimensional, o que permite uma definio segura do comeo e do final. Existem varias operaes que podemos fazer com listas, porm no utilizamos todas elas em todos os programas que fazemos, havendo assim a necessidade da escolha das melhores operaes a fim de proporcionar uma maior eficincia. As listas tm varias aplicaes em programao destacando-se nas reas de manipulaes simblicas, gerncia de memria, simulao e compiladores. Existem duas formas bsicas para implementao de listas lineares: com arrays e com ponteiros. A primeira forma de implementao mais recomendada para estruturas cujo tamanho conhecido previamente e no h muita manipulao de arquivos no interior da estrutura. A segunda forma destaca-se pela flexibilidade e pelo fato de no ser necessrio o conhecimento prvio do espao necessrio. A primeira parte no ser implementada no texto pelo fato de que se trata apenas de um vetor facilmente manipulvel para realizar todas as operaes bsicas. A implementao de listas com ponteiros no difcil quando feita com ateno. Como dito no inicio, iremos criar uma UNIT listas para tratar o assunto e que poder ser utilizada futuramente em qualquer programa bastando apenas algumas modificaes. Uma lista, como foi dito, uma coleo de ns. Ns nada mais so que registros que contm as informaes que sero armazenadas e um ponteiro que ira apontar para o no seguinte da lista ou para NIL como definido na seo 1. Exemplo de um no:

Exemplo de uma lista:

As operaes bsicas de uma lista so as seguintes :

1. 2. 3. 4. 5.

Criar Inserir Remover Imprimir Buscar

dentro dos itens 2,3 temos varias operaes embutias pois podemos trabalhar tanto no inicio/final da lista como em seu interior. As listas podem ser implementadas tambm contendo uma cabea, ou seja, um registro com informaes sobre a data de criao, numero de elementos, qualquer informao que o programado julgar necessria, e um ponteiro que seria o inicio da lista. A seguir temos toda a implementao da estrutura de dados em Pascal, aconselho a digitao e o estudo dos algoritmos com testes de mesa para melhor aprendizagem. Nesta implementao temos inicialmente a definio do novo tipo de dados, do registro dos ns que possuem dois campos inteiros (nome um campo inteiro tambm, modifiquem na hora de implementar) e um ponteiro para o n seguinte. Os nomes dos procedimentos indicam a ao que cada um executa, alguns so procedimentos, outros funes, estas decises foram tomadas de acordo com a necessidade, porm podem ser mudados facilmente. unit listas;

interface uses crt; type pUnidade = ^unidade; lista = pUnidade; unidade = record valor : integer; nome : integer; seguinte : pUnidade; end;

procedure criaLista(var nova:lista); function criaElemento(numero : integer; sujeito : integer):pUnidade; procedure insereInicioLista(var lugar : lista; elemento : pUnidade); procedure insereFinalLista(var lugar : lista; elemento : pUnidade); procedure insereAntesLista(var lugar : lista; elemento: pUnidade; numero : integer); procedure insereAposLista(var lugar : lista; elemento: pUnidade; numero : integer); function removeInicioLista(var lugar : lista):pUnidade;

function removeFinalLista(var lugar : lista):pUnidade; function removeElemento(var lugar : lista; numero : integer):pUnidade; procedure apagaLista(var morta : lista); procedure imprimeLista(poplista : lista);

implementation procedure criaLista(var nova:lista); begin nova:= nil; end; function criaElemento(numero : integer; sujeito : integer):pUnidade; var aux : pUnidade; begin new(aux); aux^.valor := numero; aux^.nome := sujeito; aux^.seguinte := nil; criaElemento := aux; end; function verificaElemento(var localz : lista ; valor2 : integer):boolean; var aux : pUnidade; begin if localz = nil then begin verificaElemento := false; end else begin aux := localz; if aux^.valor = valor2 then begin verificaElemento := true; end else begin while (aux <> nil) do begin if aux^.valor = valor2 then begin verificaElemento := true; aux := nil; end else begin

10

aux := aux^.seguinte; verificaElemento := false; end; end; end; end; end; procedure insereInicioLista(var lugar : lista; elemento : pUnidade); begin if lugar = nil then begin lugar := elemento; end else begin elemento^.seguinte := lugar; lugar := elemento; end; end; procedure insereFinalLista(var lugar : lista; elemento : pUnidade); var aux : pUnidade; begin if lugar = nil then begin lugar := elemento; end else begin aux := lugar; while aux^.seguinte <> nil do begin aux := aux^.seguinte; end; aux^.seguinte := elemento; end; end; procedure insereAntesLista(var lugar : lista; elemento : pUnidade; numero : integer); var auxfrente,auxtras : pUnidade; begin if verificaElemento(lugar,numero) then begin if lugar = nil then begin writeln('nao h elementos na lista'); end else

11

begin auxfrente := lugar; if lugar^.valor = numero then begin insereInicioLista(lugar,elemento); end else begin auxtras := auxfrente; while (auxfrente^.valor <> numero) do begin auxfrente := auxfrente^.seguinte; end; while auxtras^.seguinte <> auxfrente do begin auxtras := auxtras^.seguinte; end; auxtras^.seguinte := elemento; elemento^.seguinte := auxfrente; end; end; end else begin writeln('o elemento nao esta na lista'); end; end;

procedure imprimeLista(poplista : lista); var aux : pUnidade; begin if poplista = nil then begin writeln('a lista esta vazia '); end else begin aux := poplista; while aux <> nil do begin writeln(aux^.valor,'',aux^.nome,''); aux := aux^.seguinte; end; end; writeln('-----------------------'); end; procedure insereAposLista(var lugar : lista; elemento: pUnidade; numero : integer);

12

var aux : pUnidade; begin if verificaElemento(lugar,numero) then begin aux := lugar; if aux^.valor = numero then begin elemento^.seguinte := aux^.seguinte; aux^.seguinte := elemento; end else begin while aux^.valor <> numero do begin aux := aux^.seguinte; end; elemento^.seguinte := aux^.seguinte; aux^.seguinte := elemento; end; end else begin writeln('o elemento nao esta na lista'); end; end;

function removeInicioLista(var lugar : lista):pUnidade; var aux : pUnidade; begin if lugar = nil then begin writeln('a lista esta vazia'); end else begin aux := lugar; lugar:= lugar^.seguinte; removeInicioLista := aux; end; end; function removeFinalLista(var lugar : lista):pUnidade; var auxinicio,auxfinal : pUnidade; begin if lugar = nil then begin

13

writeln('a lista esta vazia'); end else begin auxinicio := lugar; auxfinal := auxinicio; while auxinicio^.seguinte<>nil do begin auxinicio := auxinicio^.seguinte; end; if auxinicio = auxfinal then begin removeFinalLista := auxinicio; lugar := nil; end else begin while auxfinal^.seguinte <> auxinicio do begin auxfinal := auxfinal^.seguinte; end; auxfinal^.seguinte := nil; removeFinalLista := auxinicio; end; end; end; procedure apagaLista(var morta : lista); var auxinicio,auxfinal : pUnidade; begin if morta<>nil then begin repeat if morta^.seguinte = nil then begin auxinicio := morta; morta := nil; dispose(auxinicio); end else begin auxfinal := morta; auxinicio := auxfinal; while auxfinal^.seguinte <> nil do begin auxfinal := auxfinal^.seguinte; end; while auxinicio^.seguinte <> auxfinal do begin

14

auxinicio := auxinicio^.seguinte; end; auxinicio^.seguinte := nil; dispose(auxfinal); end; until morta = nil ; end; end; function removeElemento(var lugar : lista; numero : integer):pUnidade; var auxinicio,auxfinal : pUnidade; begin if verificaElemento(lugar,numero) then begin if lugar^.valor = numero then begin auxinicio := lugar; lugar := lugar^.seguinte; removeElemento := auxinicio; end else begin auxinicio := lugar; auxfinal := lugar; while auxinicio^.valor <> numero do begin auxinicio := auxinicio^.seguinte; end; while auxfinal^.seguinte <> auxinicio do begin auxfinal := auxfinal^.seguinte; end; auxfinal^.seguinte := auxinicio^.seguinte; removeElemento := auxfinal; end; end else begin writeln('o elemento nao esta na lista'); end; end; end. Agora um programa simples para teste do algoritmo: program teste;

15

uses LISTAS;

var primeira : lista; aux : pUnidade;

begin criaLista(primeira); imprimeLista(primeira); insereInicioLista(primeira,criaElemento(9,0)); imprimeLista(primeira); insereInicioLista(primeira,criaElemento(10,4)); imprimeLista(primeira); insereFinalLista(primeira,criaElemento(11,6)); imprimeLista(primeira); insereAntesLista(primeira,criaElemento(12,6),11); imprimeLista(primeira); insereAntesLista(primeira,criaElemento(12,6),10); imprimeLista(primeira); insereAntesLista(primeira,criaElemento(12,6),9); imprimeLista(primeira); insereAntesLista(primeira,criaElemento(12,6),70); imprimeLista(primeira); insereAposLista(primeira,criaElemento(1,1),12); imprimeLista(primeira); insereAposLista(primeira,criaElemento(1,1),9); imprimeLista(primeira); insereAposLista(primeira,criaElemento(1,1),11); imprimeLista(primeira); removeElemento(primeira,12); imprimeLista(primeira); removeElemento(primeira,9); imprimeLista(primeira); removeElemento(primeira,11); imprimeLista(primeira); removeElemento(primeira,1); removeElemento(primeira,1); removeElemento(primeira,1); removeElemento(primeira,12); removeElemento(primeira,10); removeElemento(primeira,12); imprimeLista(primeira); end. Sempre lembrando que o programa teste deve estar no mesmo diretrio da unit para que a mesma possa ser utilizada pelo programa.

16

Podemos utilizar as listas para criar vetores de listas, arvores de listas, tabelas de listas, qualquer estrutura que precisarmos dependendo da necessidade. EXERCICIOS 1. Criar uma unit para utilizao de listas com cabea, que possua todas as operaes definidas no texto. 2. Sabendo que uma lista duplamente encadeada uma lista cujos ns tm dois ponteiros um para o seguinte e outro para o anterior, defina a unit lista duplamente encadeada, e aponte alguns casos onde tal implementao seja mais vantajosa. 3. Matrizes Esparsas: Matrizes esparsas so matrizes em que a maioria de suas posies so preenchidas com 0. Para uma otimizao com relao a memria, estas matrizes so implementadas com Listas. Estas listas no armazenam os elementos 0, apenas os <> de 0. Sabendo que uma lista circular uma lista cujo ultimo elemento aponta para o primeiro, utilizando listas circulares dever ser feita uma unit que implementa matrizes esparsas. No final da descrio do exerccio haver um desenho de como a estrutura de uma matriz esparsa. As operaes que devem ser implementadas so as seguintes : procedure imprimeMatriz procedimento imprime a matriz com os 0 inclusive procedure leMatriz este procedimento l de um arquivo primeiramente o tamanho da matriz depois os elementos que so diferentes de 0 e insere na matriz tais elementos um exemplo de entrada : 44 tamanho da matriz 124 posicao 1 2 o valor 4 , e assim por diante . Um arquivo diferente para cada matriz. . . procedure apagaMatriz procedimento que desaloca toda a memria alocada para construo da estrutura function somaMatriz funcao que soma duas matrizes esparsas e retorna o resultado function multiplicaMatriz funo que multiplica duas matrizes e retorna o resultado, lembrando que preciso testar a validade da multiplicao. procedure insereMatriz - procedimento que ser usado no momento de construo da estrutura

deve ser apresentado como resoluo do exerccio o cdigo, o executvel, um relatrio completo do desenvolvimento do programa, e uma sntese dos testes executados, sendo necessria a implementao de um programa teste e sua apresentao juntamente ao restante do que foi exigido. Seguem abaixo ilustraes para facilitar o entendimento. Temos a matriz : 17

o desenho da matriz seria :

18

2.2 Pilhas Listas so vistas primeiro a fim de facilitar o estudo de pilhas e filas, j que as duas estruturas nada mais so que listas que seguem um protocolo. No caso de pilhas, temos listas que so vistas como se fossem uma pilha de pratos por exemplo, enxergamos o topo porm o resto no pode ser visualizado, sendo necessrio para esta visualizao a retirada de todos os pratos de cima, ou seja, teramos que desempilhar os pratos. No pargrafo acima definimos, sem perceber, o protocolo da estrutura de dados pilha. Esta estrutura uma estrutura LIFO(last-in,first-out), ou seja, o ultimo que entra o primeiro que sai. Temos na pilha um topo que controla a entrada e sada de dados, e a nica parte da pilha a qual temos acesso. Torna-se necessrio na maioria das vezes, que se declare um contador global para a pilha a fim de saber o numero de elementos, ou talvez a criao de um n cabea que iria conter essa informao e qualquer outra e um ponteiro que seria o topo da pilha. Esta estrutura comummente usada em processamento de estruturas aninhadas de profundidade desconhecida e tambm em situaes onde se quer garantir a ordem de execuo de tarefas assim como uma pilha de ativao em um S.O. ou at uma recurso. Vrias operaes so possveis em uma pilha, porm as bsicas sero apresentadas no programa exemplo (uma UNIT pilhas). Os procedimentos podem ser chamados tanto de Desempilha, Empilha, como insereInicio, removeInicio, pois o que importa seguir o protocolo, ou seja, fazer todas as operaes de um extremo apenas que indicado pelo ponteiro pilha ou topo. MUITO IMPORTANTE SEGUIR O PROTOCOLO, POIS A NO UTILIZAO DO MESMO DESCARACTERIZA A ESTRUTURA. A idia de pilha fica um pouco mais clara pelo desenho:

O protocolo permite apenas operaes com o topo no sendo permitido percorrer uma pilha, sendo assim para acessarmos um elemento, procurar um elemento ou ate mesmo imprimir a pilha necessrio que desempilhemos item por item e que seja feita a operao desejada. Em termos de ns como visto em listas teramos o seguinte:

19

Agora o programa exemplo que trata o problema de pilhas com listas encadeadas: unit pilhas; interface uses CRT; type pUnidade = ^unidade; pilha = pUnidade; unidade = record valor : integer; nome : integer; seguinte : pUnidade; end; procedure criaPilha(var nova: pilha); function criaElemento(numero : integer; sujeito : integer):pUnidade; procedure inserePilha(var lugar:pilha ;elemento : pUnidade); function removePilha(var lugar:pilha):pUnidade; procedure apagaPilha(var morta : pilha); procedure imprimePilha(poppilha : pilha); implementation procedure criaPilha(var nova: pilha); begin nova := nil; end; 20

function criaElemento(numero : integer; sujeito : integer):pUnidade; var aux : pUnidade; begin new(aux); aux^.valor := numero; aux^.nome := sujeito; aux^.seguinte := nil; criaElemento := aux; end; procedure inserePilha(var lugar:pilha ;elemento : pUnidade); begin if lugar = nil then begin lugar := elemento; end else begin elemento^.seguinte := lugar; lugar := elemento; end; end; function removePilha(var lugar:pilha):pUnidade; var aux : pUnidade; begin if lugar = nil then begin removePilha := nil; end else begin new(aux); aux := lugar; lugar := lugar^.seguinte; removePilha := aux; end; end;

procedure apagaPilha(var morta : pilha); var aux : pUnidade; begin if morta = nil then begin Writeln('a pilha esta vazia');

21

end else begin aux := removePilha(morta); while aux <> nil do begin dispose(aux); aux := removePilha(morta); end; end; end; procedure imprimePilha(poppilha : pilha); var aux : pUnidade; begin if poppilha = nil then begin writeln(' a pilha esta vazia' ); end else begin while poppilha <> nil do begin aux := removePilha(poppilha); writeln(aux^.valor,' ',aux^.nome,' '); end; end; end; end. E abaixo um programa teste para a unit: program teste; uses pilhas; var nova,aux : pilha; begin criaPilha(nova); imprimePilha(nova); inserePilha(nova,criaElemento(3,4)); imprimePilha(nova); inserePilha(nova,criaElemento(4,6)); imprimePilha(nova); aux := removePilha(nova); imprimePilha(nova); dispose(aux); end.

22

Assim como em listas, podemos criar listas de pilhas, vetores de pilhas, arvores com pilhas, enfim, qualquer estrutura dependendo da necessidade. Pilhas com vetores devem ser implementadas como vetores normais, porm a posio v[0], por exemplo, deve ser usada para ser o topo, e as inseres sempre na posio um, empurrando todos os elementos para trs, e as outras operaes no mesmo estilo.

EXERCICIOS 1. 2. 3. 4. Refazer a unit, utilizando uma pilha com cabea. Implementar uma unit pilha utilizando vetores. Criar um programa teste para as units. Escreva um programa que seja capaz de ler uma srie de solicitaes para: Incluir processos na pilha de ativao. Localizar o processo que tem mais urgncia e coloca-lo no inicio da pilha. Imprimir os processos a qualquer momento no programa. Cada processo um n com o ponteiro e um campo de identificao onde consta nvel de urgncia e sua descrio. Fazer um procedimento que a cada passagem do tempo executa o processo do topo. Avaliao de expresses A avaliao de expresses uma conhecida aplicao de pilhas. Avaliar expresses uma tarefa executada pelo computador a todo momento. Para facilitar utilizaremos: Identificadores com letra maiscula Operadores aritmticos binrios Parnteses

2.2.1

As prioridades sero conservadas e parnteses sero utilizados para modificar a ordem. H uma certa dificuldade em avaliar expresses pois no se pode simplesmente ir percorrendo a expresso e efetuando operaes j que existem prioridades a serem seguidas, e alem disso temos que seguir o parnteses corretamente tambm. Devido a este problema, foram criadas representaes para expresses e so elas: Infixa - (A+B) Ps-Fixa - (+AB) Pr-Fixa - (AB+) Existem vantagens nestas notaes devido a ordem que aparecem os operandos e operadores. Para converter de infixa para pos-fixa devemos primeiramente parentetizar toda a expresso afim de definir a ordem das operaes, e depois d efeito isso temos o algoritmo a seguir: 23

function Npr(E:string) : string; var P:pilha;//supondo implementacao :)pilha de strings S:string; i:integer; begin criaPilha(p); s := ''; for i:= 1 to length(E) do //(vai ateh o final da expressao) case E[i] of 'A'..'Z' : S := S+E[i]; '+','-','*','/' : empilhar(P,E[i]);//empilha em p o valor da string ')' : S:= S + desempilha(p); // funcao que retorne o primeiro da pilha end; Npr := s; end; A EXPRESSO DEVE ESTAR PARENTETIZADA!!!, ou seja, com todos os parnteses necessrios para definir a ordem mesmo que as operaes tenham ordem natural. Para converso de expresses infixa para pos-fixa teremos que criar uma funo que retorna a prioridade do smbolo e aps feito isso o algoritmo de converso: function Prio(S:char) : integer; //retorna prioridades begin case S of '(': Prio := 1; '+','-': Prio := 2; '*', '/' : Prio := 3; end; end; function PosFixa(E:string) : string; var p : pilha; s : string; i : integer; x : char; begin criaPilha(p); s := ''; for i:=1 to length(E) do

24

case E[i] of 'A'..'Z' : s:=s + E[i]; '+','-','*','/': begin while not vazia(p) and //pilha vazia - funcao que retorna true / //quando topo = nil ; (Prio(topo(p))>=Prio(E[i])) do s := s + desempilha(p); end; '(' : empilha(p,E[i]); ')' : begin while topo(p) <> '(' do s:= s + desempilha(p); x := desempilha(p); end; end; while not vazia(p) do s := s + desempilha(p); posFixa := s; end; Aps feita a converso devemos analisar a expresso , e o algoritmo abaixo faz exatamente isto, avalia uma expresso pos-fixa da seguinte maneira: so armazenados os valores das variveis em um vetor cujas indicaes de posies so os tipos validos de variveis A..Z, e a atribuio feita com o valor na posio v[x] onde x a varivel. A funo que avalia a expresso utiliza este vetor para calcular. type valores = array['A'..'Z'] of real; var v:valores; procedure Atribui(var v:valores); var n : char; begin writenln('digite . para finalizar....'); repeat write('variavel: '); readln(n); if n in ['A'..'Z'] then begin write('valor: '); readln(v[n]); end; until n='.'; end;

25

agora o programa que avalia a expresso: function avalia(e:string; v:valores) :real; var p : pilha; x,y : real; i : integer; begin criaPilha(p); for i:= 1 to length(e) do if e(i) in ['A'..'Z'] then desempilha(p,v[e[i]]) else if e[i] in ['+','-','*','/'] then begin y := desempilha(p); x := desempilha(p); case e[i] of '+' : empilha(p,x+y); '-' : empilha(p,x-y); '*' : empilha(p,x*y); '/' : empilha(p,x/y); end; end; Avalia := desempilha(p); end; Estes algoritmos necessitam de uma unit pilha implementada e incluida no cdigo como pode ser visto. EXERCICIOS 1. Fazer um programa calculadora que utiliza os procedimentos e funes presentes no texto. 2. Fazer procedimentos para todas as converses de expresso possveis como de pos-fixa para pr-fixa, pr fixa para infixa e assim por diante, utilizando o conceito de pilha. 3. Modifique os algoritmos acima para que trabalhem com varias operaes alem das 4 bsicas. 4. Desenvolva um procedimento que confere a sintaxe de uma expresso infixa. Primeiro smbolo no pode ser um operador Operador no pode ser imediatamente precedido por outro nem por parntese de fechamento. Um operador no pode ser precedido por outro imediatamente Um parntese de abertura no pode ser precedido por outro de fechamento. O ultimo smbolo no pode ser um operador.

26

27