Listas Lineares Duplamente Encadeada (LLDE) Nas listas com descritores vistas anteriormente a operação de remoção do último nó apresenta a necessidade de percorrer os nós seqüencialmente, a partir do primeiro elemento, até chegarmos ao penúltimo nó. Para se evitar esse percurso, é possível estruturar uma lista de forma que possa ser percorrida em ambos os sentidos (do início até o fim e do fim até o início). Uma organização implementando esse tipo de percurso é denominada lista duplamente encadeada. Esquematicamente podemos representar uma Lista Linear Duplamente Encadeada (LLDE) como: Prim Qtd 3 Últ Maria José Pedro Cada nó de uma lista desse tipo possui pelo menos três campos. Um campo ponteiro indicando o próximo nó, outro ponteiro indicando o nó anterior e o terceiro campo conto os dados. Os tipos em Pascal para manter uma LLDECD podem ser definidos como: Type TInfo=string; PNo=^TNo; TNo=record Esq, Dir: PNo; Info: Tinfo TDescritor=record Prim, Ult: PNo; Qtd: word Lista: TDescritor; Iniciação de uma LLDECD: procedure IniciaLLDECD( L: TDescritor) with L do Prin:=nil; Ult:=nil; Qtd:=0 1
Inserção de um nó no início da lista: Exercícios: procedure InsereInicioLLDECD( L:TDescritor; Val: TInfo); p: PNo; new(p); p^.esq:=nil; p^.info:=val; p^.dir:=l.prim; L.Ult:=p L.Prim^.Esq:=p; L.Prim:=p; inc(l.qtd) Responda: numa representação de uma LLDE sempre é possível se dizer que: p é igual a p^.dir^.esq e é igual a p^.esq^.dir.? Faça uma rotina para inserir um nó no fim da lista. Rotina para remover o primeiro nó da lista: function RemoveInicioLLDECD( L: TDescritor; Val: TInfo): boolean; p: PNo; RemoveInicioLLDECD:=false p:=l.prim; L.Prim:=p^.Dir; dec(l.qtd); L.Ult:=nil L.Prim^.Esq:=nil; Val:=p^.Info; dispose(p); RemoveInicioLLDECD:=true Trecho da inclusão de um nó entre dois nós (o nó antes do ponto de inclusão é indicado pelo ponteiro q): new(p); p^.esq:=q; p^.info:=val; p^.dir:=q^.dir; q^.dir:=p; p^.dir^.esq:=p; 2
Trecho para excluir um nó entre dois outros ( o nó a ser excluído é indicado pelo ponteiro p): p^.esq^.dir:=p^.dir; p^.dir^.esq:=p^.esq; Val:=p^.Info; dispose(p); Remoção do último nó da lista: function RemoveUltimoLLDECD( L: TDescritor; Val: TInfo): boolean; p: PNo; RemoveUltimoLLDECD:=false p:=l.ult; L.Ult:=p^.Esq; dec(l.qtd); L.Prim:=nil L.Ult^.Dir:=nil; Val:=p^.Info; dispose(p); RemoveUltimoLLDECD:=true Obs.: note que na rotina acima não há mais a necessidade de se percorrer a lista desde o início para se encontrar o penúltimo nó. Listas Circulares Duplamente Encadeadas com Descritor (LCDECD) Neste tipo de lista o campo Dir do último nó indica o ereço do primeiro nó e o campo da Esq do primeiro nó contém o ereço do último nó. O descritor para este tipo de lista tem o seguinte formato: Type TInfo=string; PNo=^TNo; TNo=record Esq, Dir: PNo; Info: Tinfo TDescritor=record Prim: PNo; Qtd: word Lista: TDescritor; Note acima que não há necessidade do campo Ult. 3
Inicia uma LCDECD vazia: procedure InicioLCDECD( L: TDescritor); with L do Qtd:=0; Prim:=nil Prim Qtd 0 Representação de LCDECD com apenas um nó: Prim Qtd 1 Representação de LCDECD com três nós: Prim Qtd 3 Maria José Pedro Exercícios: 1. Crie as rotinas para manipular LCDECD. 2. Polinômios podem ser representados por listas, cujos nós são registros com 3 campos: coeficiente, expoente e referência ao nó seguinte. Por exemplo, o polinômio 3x 5 +2x+1=0 pode ser representado por: Poli1 3 5 2 1 1 0 Crie uma rotina para ler um polinômio em uma lista a partir do teclado. Crie uma rotina que some dois polinômios. Crie uma rotina para multiplicar dois polinômios. 3. Faça um programa que leia um arquivo texto e carregue cada linha em um nó de uma lista linear duplamente encadeada com descritor. Após o arquivo estar completamente lido, as setas sobe e desce podem ser usadas para mostrar uma linha do texto armazenado na lista. A tecla sobe serve para mostrar a linha acima da linha atualmente so mostrada, a tecla desce mostra a abaixo da linha atual. 4
Alocação dinâmica com GetMem Alocação de um vetor com tamanho determinado durante a execução. uses WinCRT; (*$R-*) const MaximoIndice=65528; type TipoElementoVetor=longint; TVet= array [1..1] of TipoElementoVetor; Vet: ^TVet; N, i: 1..MaximoIndice; Write('Digite o numero de elementos do vetor: '); ReadLn(N); (* Aloca memoria dinamicamente *) GetMem(Vet, N*SizeOf(TipoElementoVetor)); for i:=1 to N do Vet^[i]:=i; for i:=1 to N do WriteLn(Vet^[i]); (* Libera memoria *) FreeMem(Vet, N*SizeOf(TipoElementoVetor));. Alocação de uma matriz com tamanho determinado durante a execução. uses WinCRT; const MaxIndice=1000; type Indice= 1..MaxIndice; TipoElementoMatriz= real; Vetor= array [Indice] of TipoElementoMatriz; Matriz= array [Indice] of ^Vetor; Mat: ^Matriz; m, n, i, j: Indice; EspacoNecessario: longint; Write('Digite o numero de linhas da matriz: '); ReadLn(m); Write('Digite o numero de colunas da matriz: '); ReadLn(n); Writeln(MemAvail); if n*sizeof(tipoelementomatriz) mod 4 > 0 then (* verifica alinhamento *) EspacoNecessario:=2 (* ajusta o alinhamento *) EspacoNecessario:=0; (* já está alinhado *) EspacoNecessario:=longint(m)*(n*SizeOf(TipoElementoMatriz)+4+EspacoNecessario)+12; 5
if EspacoNecessario > MaxAvail then WriteLn('Nao existe memoria suficiente para esta matriz!'); Halt(4); (* Aloca o espaço para os ponteiros de cada linha *) GetMem(Mat, m*sizeof(mat)); (* Aloca o espaço para os dados de cada linha *) for i:=1 to m do GetMem(Mat^[i], n*sizeof(tipoelementomatriz)); (* Atribui dados *) for i:=1 to m do for j:=1 to n do Mat^[i]^[j]:=i*1000+j; (* Mostra os dados *) for i:=1 to m do for j:=1 to n do Write(Mat^[i]^[j]:15:0); Writeln (* Libera as linhas *) for i:=1 to m do FreeMem(Mat^[i], n*sizeof(tipoelementomatriz)); (* Libera os ponteiros para as linhas *) FreeMem(Mat, m*sizeof(mat)); Writeln(MemAvail);. Exercício: faça um programa que leia um arquivo e o coloque em uma lista duplamente encadeada. Cada nó da lista deve ter além dos ponteiros normais (próximo e anterior) um outro ponteiro do tipo PString (ponteiro para string). Cada linha quando for lida do arquivo deve ser colocada em uma String normal, em seguida deve-se proceder a alocação dinâmica do nó da lista e da área para alojar tal String. Veja abaixo a representação de uma lista desse tipo criada a partir de um arquivo com três linhas de texto. Observe que o tamanho do espaço de memória de cada linha depe no número de caracteres lidos. Linha 1 do arquivo Linha 2 Última linha 6