Você está na página 1de 34

Tpascal - Trabalhos em Pascal

ecv2001@zipmail.com.br

Aplicaes de Listas

www2.50megs.com/tpascal

LISTAS LINEARES

1- INTRODUO

A lista linear uma forma de representao, como estrutura linear, onde o objetivo
que a representao de dados de um problema no computador seja de tal maneira, que o
algoritmo que os utilize seja auxiliado em sua tarefa de obter uma soluo de forma
confivel e eficiente.
Para a compreenso do funcionamento da lista, necessrio compreendermos o
funcionamento da memria do computador.
A memria do computador um recurso que pode ser acessado de duas formas
por um programa:
Primeiro, um algoritmo pode alocar estruturas de dados no que chamaremos de

memria esttica, alocao esta que deve ser feita antes de sua execuo;

Segundo, um algoritmo pode utilizar-se da memria dinmica do computador,

alocando estruturas na medida do necessrio durante a execuo do algoritmo.

Em ambos os casos, podemos imaginar que a memria organizada como uma


srie seqencial de clulas. Associados a cada clula esto dois atributos: o endereo do
inicio da clula e seu tamanho. As clulas no precisam ser de tamanho uniforme.
O tamanho de uma clula dado numa unidade peculiar ao equipamento em
questo, mas geralmente a unidade fundamental o byte, que o espao necessrio para
representar um caractere, por exemplo a letra a. Um byte composto de 8 bits, sendo
que um bit um digito binrio (0 ou 1). Tudo que representvel num computador
fundamental uma seqncia de bits.
A maioria dos programadores est acostumada a trabalhar com a alocao esttica
de memria, que nos obriga a definir com antecedncia o tamanho mximo das estruturas
de dados. A segunda forma nos desobriga dessa definio e, portanto, muito mais
flexvel, embora esteja sujeita a perigos que lhe so caractersticos.
2-LISTAS LINEARES
A lista linear a mais simples estrutura de dados que existe na maioria das
linguagens de programao. conhecida mais comumente como vetor ou array (em
ingls), e implementada na memria esttica.
Formalmente representamos a lista A, contendo n elementos, da seguinte forma:

A = (a1,...,an), n 0.
Chamamos de aks de ns, e geralmente impomos a condio de que todos os ns
de uma lista devem pertencer ao mesmo conjunto, por exemplo, todos os a ks devem ser
nmeros inteiros. Os ns podem ser listas tambm, produzindo assim o que conhecemos
por matrizes de duas ou mais dimenses. A lista A pode ser tambm vazia, correspondendo
ao caso especial em que n=0. Ns representamos esse caso especial assim:
A = ( ).
Em virtude da maneira como a maioria das linguagens de programao os
implementa, os ns de uma lista linear so armazenados de forma contgua. Ou seja, na
memria do computador, o primeiro n imediatamente seguido pelo segundo, o segundo
pelo terceiro e assim por diante, at o final da lista. Essa forma de armazenamento
obviamente compacta, mas, mais importante, permite acesso rpido a qualquer elemento,
pois o processo de endereamento extremamente simples: o prprio compilador da
linguagem que utilizamos se encarrega de fornecer o endereo correto. Por exemplo, para
indicarmos que o quinto caixa est ocupado num dado instante da simulao de um banco,
utilizaramos o seguinte segmento de cdigo:
caixa_ocupado[5] verdadeiro;
Similarmente, o segmento de cdigo abaixo encontraria o primeiro caixa
disponvel:
var i : int;
i 1;
enquanto caixa_ocupado[i] falso faa
i i+1;
fim enquanto;
Em nenhum desses dois casos foi necessrio preocuparmo-nos com o acesso aos
ns da lista. O compilador da linguagem se encarregaria de gerar os endereos das clulas
contendo os membros de caixa_ocupado.
Caso desejemos adicionarmos um n a este tipo de lista, deveremos deslocar os
ns de tal forma que possamos encaix-lo entre dois ns j existentes. Supomos que
deseja-se colocar o dado M na posio 3 da lista abaixo:
Posio
Dado

1
A

2
B

3
C

4
D

5
E

6
F

7
G

Nota-se que a lista comea na posio 1 e termina na posio 7. Para encaixarmos


o M entre B e C, ou seja, na posio 3, necessrio que desloquemos de C at G uma
posio para a direita. Logo, G passa para a posio 8, F para a posio 7, e assim
sucessivamente at C para a posio 4. necessrio que faamos um algoritmo que
troque estes valores desde G at C, pois da forma contrria quando pusermos C na
posio 4, ao lermos o dado da posio 4 para colocarmos na 5 posio, acharemos o
3

prprio C, ao invs do D. E na posio 5 acharemos C, e assim at o final da lista. Abaixo


ser apresentado o algoritmo que faz este deslocamento:
fim 7;
para i de fim at 3 faa
dado[i+1] dado[i];
fim para;
fim fim +1;

Aps a execuo desta rotina, a lista ficar da seguinte forma:


Posio
Dado

1
A

2
B

3
C

4
C

5
D

6
E

7
F

8
G

Agora poderemos colocar o dado M na posio 3, tendo a certeza que o restante


da lista foi preservado. Para isto:
dado[3] M;
Logo, teremos:
Posio
Dado

1
A

2
B

3
M

4
C

5
D

6
E

7
F

8
G

Nota-se tambm, que quanto maior a lista e quanto menor for o valor da posio
em que desejamos fazer a insero, mais tempo ser necessrio para o processamento.
Este problema pode ser solucionado se colocarmos o incio como sendo uma varivel.
Assim, podemos deslocar tanto os elementos da esquerda como os da direita. Este
procedimento est esquematizado abaixo:
Pos.
Dad
o

3
A

4
B

5
C

6
D

7
E

8
F

9
G

10

11

incio 3;
fim 9;
Assim, poderamos incluir M entre B e C, deslocando somente A e B para a
esquerda. Para esta, verifica-se tambm a necessidade de comearmos com A, na posio
de 3 para 2, por 2 se tratar de uma posio vazia.
Para excluirmos um n, o procedimento mais fcil, pois basta deslocarmos todos
os ns a sua direita, at o fim, uma posio para a esquerda. Suponhamos que desejemos
retirar a letra D da lista abaixo:

Posio
Dado

1
A

2
B

3
M

4
C

5
D

6
E

7
F

8
G

O procedimento :
fim 8;
para i de 6 at fim faa
dado[i-1] dado[i];
fim para;
fim fim - 1;
A lista ficar:
Posio
1
2
3
4
5
6
7
8
Dado
A
B
M
C
E
F
G
G
Podemos observar que a posio 8 ficar marcada com o dado G, porm ns
remarcamos o final da lista de 8 para 7.
LISTAS ENCADEADAS
A lista encadeada uma generalizao da lista linear que introduz vrias
alteraes:
Os ns da lista no esto necessariamente armazenados seqencialmente;
Dependendo da forma de implementao, pode no haver um tamanho mximo

predefinido da lista;

E os ns podem ser de tipos heterogneos. Por exemplo, alguns podem conter

nmeros inteiros e outros podem ser listas de nmeros inteiros.

A perda da contigidade de armazenamento nos fora a armazenar junto a cada n


a informao de onde acessar o n seguinte. Devemos tambm armazenar, separadamente
da lista, o endereo do primeiro n da lista. Graficamente, o n de uma lista encadeada
homognea ser uma dupla contendo o dado armazenado e um ponteiro ao n seguinte:

Esta caracterizao do n de uma lista encadeada bastante flexvel, embora


sejamos forados a ter um tipo de n diferente declarado para cada tipo de dado que
desejarmos armazenar e um conjunto de rotinas para manipular cada tipo de lista.
A figura abaixo mostra a estrutura tpica de uma lista encadeada homognea. Nela
vemos um ponteiro ao inicio da lista, bem como a conectividade entre ns da lista por
meio dos ponteiros. Note que o ltimo elemento da lista distinguido dos outros pelo fato
de seu ponteiro ter o valor especial / , que adotaremos como conveno grfica para
indicar que o ponteiro no aponta para lugar algum. O valor / equivalente ao NIL, do
Pascal.

No caso de uma lista encadeada heterognea, mostrada na figura acima, sua


estrutura parece-nos bem mais complexa, mas apenas estamos manipulando um agregado
de listas, nada mais.
O DESCRITOR
O elemento descritor de uma lista encadeada armazena as referencias ao incio e ao
fim da lista. Todo acesso a lista ser sempre efetuado atravs do descritor.
O n descritor de uma lista pode conter outras informaes sobre a lista como a
quantidade de ns na lista (como nos modelos apresentados neste trabalho), descrio dos
dados contidos nos ns, etc.

LISTAS ENCADEADAS SIMPLES

Uma lista encadeada simples aquela que em cada n possui apenas uma
referncia. Esta referncia serve para indicar seu n sucessor.
LISTAS DUPLAMENTE ENCADEADAS
Uma lista duplamente encadeada aquela que em cada n possui duas referncias.
Estas referncias servem para indicar seu n sucessor e seu predecessor.
Uma lista duplamente encadeada tem a seguinte propriedade:
(p^.predecessor)^.sucessor = (p^.sucessor)^.predecessor = p
OS OPERADORES DE LISTAS
Imaginemos que as operaes abaixo fossem de interesse na utilizao de listas
encadeadas:
Visitar todos os ns da lista;
inserir um novo dado no fim (ou inicio da lista);
remover o primeiro (ou ltimo) n da lista;
buscar um n na lista.

Chamaremos as funes e os procedimentos que manipulam uma estrutura de


dados de operadores daquela estrutura, em analogia aos operadores disponveis para os
tipos de dados bsicos de uma linguagem de programao.
A definio completa de uma estrutura de dados inclui tanto sua forma estrutural
como a disciplina de acesso, o que define sua coleo de operadores vlidos.
Por questo de disciplina e boa forma de programao, uma estrutura de dados
deve ser manipulada apenas por meio de seus operadores. Esse , em parte, o grande
segredo do valor do uso de estrutura de dados para promover o correto funcionamento de
programas.
Operaes tais como impresso ou somatrio de todos os elementos de uma lista
envolvem o manuseio de todos os ns de uma lista da lista encadeada. O processo de
visitao de um n to particular a uma dada aplicao que difcil generaliz-lo na
forma de um procedimento. Esquematicamente, porm, visitar os ns de uma lista muito
esclarecedor quanto manipulao dessa estrutura de dados.
A seguir demonstraremos e comentaremos os principais operadores de listas
simples e duplamente encadeadas atravs de programas modelos em Pascal*.
* A escolha da linguagem Pascal foi feita pelo motivo de ser uma linguagem simples, que
possui a manipulao de variveis tipo ponteiro e tambm por ser conhecida amplamente.
Esses modelos (Modelo1.pas e Modelo2.pas) esto em linguagem Pascal no disquete do

trabalho e mais dois exemplos de aplicaes de listas (Exemplo1.pas - arranjar em ordem


alfabtica um grupo de palavras; e Exemplo2.pas - um pequeno exemplo de manipulao
de banco de dados).

PROGRAM modelo_lista_linear_simples;
TYPE pont = ^no;

{Define o tipo pont como um ponteiro para


n da lista}

no = RECORD
{Definio do tipo de dado do n.
STRING[20];}

Exemplo: nome

{ nesta linha que o programador define a


estrutura de dados do n}

proximo : pont;

{Como a lista simplesmente encadeada,


s poder haver ponteiro em uma direo}

END;
TYPE tipo_descritor = RECORD
nos : INTEGER;
inicio, fim : pont;

{Definio do registro do descritor, onde


nos a quantidade de ns da lista; inicio e
fim, respectivamente so os ponteiros para
incio e fim da lista}

END;
VAR descritor : tipo_descritor;

PROCEDURE inicializa;

{Declarao global da varivel descritor}

{Esta PROCEDURE serve para inicializar


o descritor da lista}

BEGIN
descritor.nos:=0;

descritor.inicio:=NIL;
descritor.fim:=NIL;

{Como a lista est vazia o nmero de ns


dever ser 0(zero)}

{Se a lista est vazia, obviamente o incio e


fim da lista no existem}

END;

PROCEDURE insere_direita;

VAR p : pont;

BEGIN
NEW(p);

{Inserir a direita significa, inserir o n na


ltima posio da lista}

{Declara p como um ponteiro para o novo


n da lista}

{Aloca memria para o n apontado por p}

{Rotina para entrada de dados, exemplo READLN(p^.nome);}


p^.proximo:=NIL;

{Como o novo n est sendo inserido na


ltima posio da lista, no existe nenhum
n a sua frente}

IF descritor.nos=0 THEN descritor.inicio:=p

{Se no existia nenhum n antes da


insero ento isso significa que este n
tambm o primeiro da lista}

ELSE
(descritor.fim)^.proximo:=p;

descritor.fim:=p;

INC(descritor.nos);

{Seno, esta linha faz com que o n


prximo ao ltimo n da lista aponte para
o novo}

{J esta linha define que o novo n


inserido o ltimo da lista}

{Aumenta o nmero de ns existentes no


descritor em 1}

END;

PROCEDURE insere_esquerda;

VAR p : pont;

{Inserir a esquerda significa, inserir o n


na primeira posio da lista}

{Declara p como um ponteiro para o novo


n da lista}

BEGIN
NEW(p);
10

{Aloca memria para o n apontado por p}

{Rotina para entrada de dados, exemplo READLN(p^.nome);}


p^.proximo:=descritor.inicio;

descritor.inicio:=p;

{Faz com que o n seguinte ao novo n


(apontado por p) aponte para o antigo
primeiro n da lista}

{Define o novo n como o primeiro da


lista}

IF descritor.nos=0 THEN descritor.fim:=p;

{Se no existia nenhum n antes da


insero ento isso significa que este n
tambm o ltimo da lista}

INC(descritor.nos);

{Aumenta o nmero de ns existentes no


descritor em 1}

END;

PROCEDURE insere_posicao (n : INTEGER);

{Inserir em uma posio n qualquer


significa inserir um n em uma posio
intermediria da lista}

VAR p,q : pont;

{Declara p e q como ponteiros para n.


Onde p apontar para o novo n da lista; e
q percorrer a lista}

BEGIN
NEW(p);

{Aloca memria para o n apontado por p}

IF ((n<1) OR (n>descritor.nos+1)) THEN {Rotina de erro};


{Esta linha prev um erro na entrada da
posio. O limite superior uma unidade
acima do total de ns existentes da lista
porque o usurio poder inserir um n na
ltima posio}

IF n=1 THEN BEGIN


insere_esquerda;

{Caso especial onde o usurio estar


inserindo o n no incio da lista, por isso
chama-se
a
PROCEDURE
insere_esquerda}

11

EXIT;

{Sai da PROCEDURE }

END;
IF n=descritor.nos+1 THEN BEGIN
insere_direita;

EXIT;

{Caso especial onde o usurio estar


inserindo o n no fim da lista, por isso
chama-se a PROCEDURE insere_direita}

{Sai da PROCEDURE}

END;
{Rotina de entrada de dados, exemplo: READLN(p^.nome);}
q:=descritor.inicio;

{Faz com que o ponteiro q aponte para o


primeiro n da lista}

FOR n:=n-1 DOWNTO 2 DO q:=q^.proximo;

{Esta linha faz com que o ponteiro q


percorra a lista at chegar ao n anterior a
posio do novo n a ser inserido}

p^.proximo:=q^.proximo;

q^.proximo:=p;

INC(descritor.nos);

{O n seguinte ao novo n(p) aponta para


o n seguinte do anterior(q)}

{O n seguinte ao n apontado pelo


ponteiro q aponta para o novo n
(apontado por p)}

{Aumenta o nmero de ns existentes no


descritor em 1}

END;

PROCEDURE remove_direita;

VAR p,q : pont;

{Remover a direita significa remover o


ltimo n da lista}

{Declara p e q como ponteiros para n.


Onde q apontar para o n que ir ser
removido; e p percorrer a lista}

12

i : INTEGER;

{ndice para a instruo FOR}

BEGIN
CASE descritor.nos OF
0 : {Rotina de erro};

1 : BEGIN
p:=descritor.inicio;

inicializa;

DISPOSE(p);

EXIT;

{Se no existirem ns na lista, no ser


possvel a remoo, da chama-se uma
rotina de manipulao do erro}
{Se existir apenas um n na lista ento:}

{O ponteiro p aponta para o primeiro n da


lista}

{J que a lista ficar vazia podemos fazer o


mesmo procedimento de inicializar o
descritor}

{Desaloca a memria
apontado por p}

criada

do n

{Sai do PROCEDURE}

END;
END;
p^.proximo:=descritor.inicio;

{O proximo do ponteiro p aponta para o


primeiro n da lista}

FOR i:=1 TO descritor.nos-1 DO p:=p^.proximo;

{Esta linha faz com que p percorra a lista


at chegar a um n anterior ao que vai ser
removido}

q:=p^.proximo;

p^.proximo:=NIL;

{Agora q aponta para o n seguinte em


relao a p, ou seja, aponta para o n que
vai ser removido}

{Como a lista linear o ponteiro p(o


ltimo) aponta para NIL}

13

descritor.fim:=p;

DISPOSE(q);

DEC(descritor.nos);

{Indica que o n apontado por p ser o


ltimo da lista}

{Desaloca a memria
apontado por q}

criada

de

{Diminui a varivel do descritor de


quantidade de ns em uma unidade}

END;

PROCEDURE remove_esquerda;

VAR p : pont;

{Remover a esquerda significa remover o


primeiro n da lista}

{Declara p como ponteiro para o n que


vai ser removido}

BEGIN
CASE descritor.nos OF
0 : {Rotina de erro};

1 : BEGIN
p:=descritor.inicio;

inicializa;

DISPOSE(p);

EXIT;

{Se no existirem ns na lista, no ser


possvel a remoo, da chama-se uma
rotina de manipulao do erro}
{Se existir apenas um n na lista ento:}

{O ponteiro o aponta para o primeiro n da


lista}

{J que a lista est vazia podemos fazer o


mesmo procedimento de inicializar o
descritor}

{Desaloca a memria
apontado por p}

criada

do n

{Sai do PROCEDURE}

END;

14

END;
p:=descritor.inicio;

descritor.inicio:=p^.proximo;

p^.proximo:=NIL;

DISPOSE(p);

DEC(descritor.nos);

{O ponteiro p aponta para o primeiro n da


lista, este ser removido}

{O primeiro n da lista ser o n seguinte


a p}

{Por questes de segurana fazemos com


que o n seguinte a p aponte para NIL}

{Desaloca a memria
armazenar o primeiro n}

criada

para

{Diminui o nmero de ns da lista em 1}

END;

PROCEDURE remove_posicao(n : INTEGER);

{Remover uma posio n qualquer


significa remover um n em uma posio
intermediria da lista}

VAR p,q : pont;

i : INTEGER;

{Declara p e q como ponteiros para n.


Onde q apontar para o n que ser
removido da lista; e p que percorrer a
lista}

{ndice para ser utilizado na instruo


FOR}

BEGIN
IF ((n<1) OR (n>descritor.nos)) THEN {Rotina de erro};

{Esta linha prev um erro na entrada da


posio}

IF n=1 THEN BEGIN


remove_esquerda;

{Caso especial onde o usurio estar


removendo o primeiro n da lista, por isso
chama-se
a
PROCEDURE
remove_esquerda}

15

EXIT;

{Sai do PROCEDURE}

END;
IF n=descritor.nos THEN BEGIN
remove_direita;

EXIT;

{Caso especial onde o usurio estar


removendo o ltimo n da lista, por isso
chama-se a PROCEDURE remove_direita}

{Sai do PROCEDURE}

END;
p^.proximo:=descritor.inicio;

{Nesta linha o prximo do ponteiro p


aponta para o primeiro n da lista}

FOR i:=1 TO n-1 DO p:=p^.proximo;

{Esta rotina faz com que p percorra a lista


at o n anterior lista}

q:=p^.proximo;

p^.proximo:=q^.proximo;

q^.proximo:=NIL;

DISPOSE(q);

DEC(descritor.nos);

{O ponteiro q aponta para o n que vai ser


removido}

{O n seguinte ao ponteiro p aponta para o


n seguinte do n seguinte apontado por q}

{Por questes de segurana fazemos q


apontar para NIL}

{Desaloca a memria
apontado por q}

criada

do n

{Diminui o nmero de ns da lista em 1}

END;

PROCEDURE consulta(n : INTEGER);

{Rotina para a consulta dos


armazenados no n da posio n}

dados

VAR p : pont;

16

{Declarao do ponteiro que ir percorrer a


lista}

BEGIN
IF ((n<1) OR (n>descritor.nos)) THEN {Rotina de erro};

{Esta linha prev um erro na entrada da


posio}

p^.proximo:=descritor.inicio;

{O prximo do ponteiro p aponta para o


primeiro n da lista}

FOR n:=n DOWNTO 1 DO p:=p^.proximo;

{Esta rotina faz com que p percorra a lista


at o n desejado}

{Rotina de impresso dos dados do n na tela, , exemplo:


WRITELN(p^.nome);}
END;

PROCEDURE modifica(n : INTEGER);

{Rotina para a modificao dos dados


armazenados no n da posio n}

VAR p : pont;

{Declarao do ponteiro que ir percorrer a


lista}

BEGIN
IF ((n<1) OR (n>descritor.nos)) THEN {Rotina de erro};

{Esta linha prev um erro na entrada da


posio}

p^.proximo:=descritor.inicio;

{O prximo do ponteiro p aponta para o


primeiro n da lista}

FOR n:=n DOWNTO 1 DO p:=p^.proximo;

{Esta rotina faz com que p percorra a lista


at o n desejado}

{Rotina de entrada dos dados do n na tela, , exemplo:


READLN(p^.nome);}
END;

17

PROGRAM
modelo_lista_linear_duplamente_encadeada;
TYPE pont = ^no;

{Define o tipo pont como um ponteiro para


n da lista}

no = RECORD
{Definio do tipo de dado do n.
STRING[20];}

Exemplo: nome

{ nesta linha que o programador define a


estrutura de dados do n}

proximo, anterior : pont;

{Como a lista duplamente encadeada


cada n dever apontar para um n
anterior e um posterior}

END;
TYPE tipo_descritor = RECORD
nos : INTEGER;
inicio, fim : pont;

{Definio do registro do descritor, onde


nos a quantidade de ns da lista; incio e
fim, respectivamente so ponteiros para
incio e fim da lista}

END;
VAR descritor : tipo_descritor;

PROCEDURE inicializa;

BEGIN
descritor.nos:=0;

descritor.inicio:=NIL;
descritor.fim:=NIL;

{Declarao global da varivel descritor}

{Esta PROCEDURE serve para inicializar


o descritor da lista}

{Como a lista est vazia o nmero de ns


dever ser 0(zero)}

{Se a lista est vazia obviamente o incio e


o fim da lista no existem}

18

END;

PROCEDURE insere_direita;

VAR p : pont;

{Inserir a direita significa inserir o n na


ltima posio da lista}

{Declara p como um ponteiro para o novo


n da lista}

BEGIN
NEW(p);

{Aloca memria para o n apontado por p}

{Rotina de entrada de dados, exemplo: READLN(p^.nome);}


p^.proximo:=NIL;

p^.anterior:=descritor.fim;

IF descritor.nos<>0 THEN BEGIN


(descritor.fim)^.proximo:=p;

END ELSE BEGIN


descritor.inicio:=p;

{Como a lista linear , o ltimo n da lista


tem que apontar para NIL}

{Como o novo n ser o ltimo ele dever


ser precedido do ltimo n antigo}

{Se a lista no estiver vazia ento o n


seguinte ao ltimo n antigo dever
apontar para o novo}

{Seno, estar sendo inserido o primeiro


n da lista, da a necessidade de defini-lo
tambm como o primeiro n da lista}

END;
descritor.fim:=p;

INC(descritor.nos);

{Esta linha define que o novo n inserido


estar na ltima posio da lista}

{Aumenta o nmero de ns existentes em


1}

END;

PROCEDURE insere_esquerda;
19

{Inserir a esquerda significa, inserir o n


na primeira posio da lista}

VAR p : pont;

{Declara p como um ponteiro para o novo


n da lista}

BEGIN
NEW(p);

{Aloca memria para o n apontado por p}

{Rotina de entrada de dados, exemplo: READLN(p^.nome);}


p^.proximo:=descritor.inicio;

p^.anterior:=NIL;

{Faz com que o n seguinte ao novo n


(apontado por p aponte para o antigo
primeiro n da lista}

{Como o n est sendo inserido na direita,


ele no estar sendo precedido por nenhum
outro n}

IF descritor.nos<>0 THEN
(descritor.inicio)^.anterior:=p

{Se a lista no estiver vazia o n anterior


ao antigo primeiro ser o novo}

ELSE
descritor.fim:=p;

descritor.inicio:=p;

INC(descritor.nos);

{Seno, como a lista est vazia o novo n


tambm ser o ltimo da lista}

{Define o novo n como o primeiro da


lista}

{Aumenta o nmero de ns existentes em


1}

END;

PROCEDURE insere_posicao (n : INTEGER);

{Inserir em uma posio n significa inserir


um n em uma posio intermediria da
lista}

VAR p,q : pont;

20

{Declara p e q como ponteiros para n.


Onde p apontar para o novo n da lista; e
q percorrer a lista}

BEGIN
NEW(p);

{Aloca memria para o n apontado por p}

IF ((n<1) OR (n>descritor.nos+1)) THEN {Rotina de erro}

{Esta linha prev um erro na entrada da


posio. O limite superior uma unidade
acima do total de ns existentes da lista
porque o usurio poder inserir um n na
ltima posio}

IF n=1 THEN BEGIN


insere_esquerda;

EXIT;

{Caso especial onde o usurio estar


inserindo o n no incio da lista, por isso
chama-se
a
PROCEDURE
insere_esquerda}

{Sai da PROCEDURE }

END;
IF n=descritor.nos+1 THEN BEGIN
insere_direita;

EXIT;

{Caso especial onde o usurio estar


inserindo o n no fim da lista, por isso
chama-se a PROCEDURE insere_direita}

{Sai da PROCEDURE }

END;
{Rotina de entrada de dados, exemplo: READLN(p^.nome);}
q^.proximo:=descritor.inicio;

{Faz com que o prximo do ponteiro q


aponte para o primeiro n da lista}

FOR n:=n DOWNTO 2 DO q:=q^.proximo;

{Esta linha faz com que q percorra a lista


at chegar ao n anterior a posio do novo
n a ser inserido}

p^.proximo:=q^.proximo;

21

{O n seguinte ao novo n(p) aponta para


onde o n seguinte do anterior(q) aponta}

p^.anterior:=q;

q^.proximo:=p;

(p^.proximo)^.anterior:=p;

{O n anterior ao n apontado por p


aponta para q}

{O n seguinte ao n apontado pelo


ponteiro q aponta para o novo n(apontado
por p)}

{Para fechar a cadeia, o n seguinte ao


novo dever estar conectado com o novo
n}

END;

PROCEDURE remove_direita;

VAR p,q : pont;

{Remover a direita significa remover o


ltimo n da lista}

{Declara p e q como ponteiros para n.


Onde q apontar para o n que ir ser
removido; e p percorrer a lista}

BEGIN
CASE descritor.nos OF
0 : {Rotina de erro};

1 : BEGIN
p:=descritor.inicio;

inicializa;

DISPOSE(q);

{Se no existirem ns na lista, no ser


possvel a remoo, da chama-se a rotina
de manipulao do erro}

{Se existir apenas um n da lista ento:}

{O ponteiro aponta para o primeiro n da


lista}

{J que a lista ficar vazia, podemos fazer


o mesmo procedimento de inicializar o
descritor}

{Desaloca a memria
apontado por p}

criada

do n

22

EXIT

{Sai da PROCEDURE}

END;
END;
p:=(descritor.fim)^.anterior;

p^.proximo:=NIL;

(descritor.fim)^.anterior:=NIL;

q:=descritor.fim;

DISPOSE(q);

descritor.fim:=p;

DEC(descritor.nos);

{O ponteiro p aponta para o penltimo n


da lista}

{Como a lista linear o ponteiro p(o


ltimo) aponta para NIL}

{Como agora o penltimo n ser o ltimo,


no existe nenhum outro n seguinte, da
porque proximo aponta para NIL}

{Faz com que q aponte para o n a ser


removido, ou seja, o ltimo da lista}

{Desaloca a memria
apontado por q}

criada

do n

{Indica que o n apontado por p ser o


ltimo da lista}

{Diminui o nmero de ns da lista em 1 }

END;

PROCEDURE remove_esquerda;

VAR p : pont;

{Remover a esquerda significa remover o


primeiro n da lista}

{Declara p que ser o n removido}

BEGIN
CASE descritor.nos OF
0 : {Rotina de erro};

23

{Se no existirem ns na lista, no ser


possvel a remoo, da chama-se uma
rotina de manipulao do erro}

1 : BEGIN
p:=descritor.inicio;

p^.anterior:=NIL;
p^.proximo:=NIL;

inicializa;

DISPOSE(p);

EXIT

{Se existir apenas um n na lista ento:}

{O ponteiro p aponta para o primeiro n da


lista, este ser removido}

{Por questes de segurana, fazemos com


que o n apontado por p esteja
completamente isolado}

{J que a lista est vazia podemos fazer o


mesmo procedimento de inicializar o
descritor}

{Desaloca a memria
apontado por p}

criada

do n

{Sai da PROCEDURE}

END;
END;
p:=descritor.inicio;

descritor.inicio:=p^.proximo;

{O ponteiro p aponta para o primeiro n da


lista}

{Agora o segundo n da lista torna-se o


primeiro}

(descritor.inicio)^.anterior:=NIL;

{O n anterior do primeiro n de uma lista


linear no existe, por isso seu anterior
nulo}

p^.proximo:=NIL;
DISPOSE(p);

{Por segurana aterra-se o ponteiro p}

{Desaloca
a memria criada
armazenar o antigo primeiro n}

para

24

DEC(descritor.nos);

{Diminui o nmero de ns da lista em 1 }

END;

PROCEDURE remove_posicao(n : INTEGER);


VAR p: pont;
i : INTEGER;
BEGIN
IF ((n<1) OR (n>descritor.nos)) THEN {Rotina de erro};

{Esta linha prev um erro na entrada da


posio}

IF n=1 THEN BEGIN


remove_esquerda;

EXIT;

{Caso especial onde o usurio estar


removendo o primeiro n da lista, por isso
chama-se
a
PROCEDURE
remove_esquerda}

{Sai do PROCEDURE}

END;
IF n=descritor.nos THEN BEGIN
remove_direita;

EXIT;

{Caso especial onde o usurio estar


removendo o ltimo n da lista, por isso
chama-se a PROCEDURE remove_direita}

{Sai do PROCEDURE}

END;
p^.proximo:=descritor.inicio;

FOR i:=1 TO n DO p:=p^.proximo;

{Nesta linha o prximo do ponteiro p


aponta para o primeiro n da lista}

{Esta rotina faz com que p percorra a lista


at o n que ser removido}

(p^.anterior)^.proximo:=p^.proximo;

{Esta rotina faz com que o n seguinte ao


anterior do apontado por p aponte para o
seguinte de p}

25

(p^.proximo)^.anterior:=p^.anterior;

{Esta rotina faz com que o n seguinte ao


anterior do apontado por p aponte para o
anterior a p}

p^.proximo:=NIL;
p^.anterior:=NIL;

DISPOSE(p);

DEC(descritor.nos);

{Aterramos o n apontado por p por


questes de segurana}

{Desaloca a memria cria do n apontado


por p}

{Diminui o nmero de ns da lista em 1}

END;

PROCEDURE consulta(n : INTEGER);

{Rotina
para a consulta dos dados
armazenados no n da posio n}

VAR p : pont;

{Declarao do ponteiro que ir percorrer a


lista}

BEGIN
IF ((n<1) OR (n>descritor.nos)) THEN {Rotina de erro};

{Esta linha prev um erro na entrada da


posio}

p^.proximo:=descritor.inicio;

{O prximo do ponteiro p aponta para o


primeiro n da lista}

FOR n:=n DOWNTO 1 DO p:=p^.proximo;

{Esta rotina faz com que p percorra a lista


at o n desejado}

{Rotina de impresso dos dados do n na tela, , exemplo:


WRITELN(p^.nome);}
END;

PROCEDURE modifica(n : INTEGER);

{Rotina para a modificao dos dados


armazenados no n da posio n}

26

VAR p : pont;

{Declarao do ponteiro que ir percorrer a


lista}

BEGIN
IF ((n<1) OR (n>descritor.nos)) THEN {Rotina de erro};

{Esta linha prev um erro na entrada da


posio}

p^.proximo:=descritor.inicio;

{O prximo do ponteiro p aponta para o


primeiro n da lista}

FOR n:=n DOWNTO 1 DO p:=p^.proximo;

{Esta rotina faz com que p percorra a lista


at o n desejado}

{Rotina de entrada dos dados do n na tela, , exemplo:


READLN(p^.nome);}
END;

27

28

APNDICE - LISTAS CIRCULARES


Mesmo no sendo parte do contedo, bom se comentar um pouco sobre listas
circulares. Nas pginas seguintes se encontra um modelo de lista circular simples (sem
restries de tamanho) que tambm se encontra no disquete(Modelo3.pas).
PROPRIEDADES
A propriedade de uma lista circular simples a seguinte:
(descritor.fim)^.sucessor = descritor.incio;
J as propriedades de uma lista circular duplamente encadeada so as seguinte:
(descritor.fim)^.sucessor = descritor.incio;
(descritor.incio)^.predecessor = descritor.incio;

29

PROGRAM modelo_lista_circular_simples;
TYPE pont = ^no;
no = RECORD
{Definio do tipo de dado do n.
STRING[20];}
proximo : pont;
END;
TYPE tipo_descritor = RECORD
nos : INTEGER;
inicio, fim : pont;
END;
VAR descritor : tipo_descritor;

Exemplo: nome

PROCEDURE inicializa;
BEGIN
descritor.nos:=0;
descritor.inicio:=NIL;
descritor.fim:=NIL;
END;

PROCEDURE insere_direita;
VAR p : pont;
BEGIN
NEW(p);
{Rotina para entrada de dados, exemplo READLN(p^.nome);}
p^.proximo:=NIL;
IF descritor.nos=0 THEN
descritor.inicio:=p
ELSE
(descritor.fim)^.proximo:=p;
descritor.fim:=p;
p^.proximo:=descritor.inicio;
INC(descritor.nos);
END;

PROCEDURE insere_esquerda;
VAR p : pont;
BEGIN
NEW(p);
{Rotina para entrada de dados, exemplo READLN(p^.nome);}
p^.proximo:=descritor.inicio;
descritor.inicio:=p;
IF descritor.nos=0 THEN descritor.fim:=p;
(descritor.fim)^.proximo:=p;
INC(descritor.nos);
30

END;

PROCEDURE insere_posicao (n : INTEGER);


VAR p,q : pont;
BEGIN
NEW(p);
IF ((n<1) OR (n>descritor.nos+1)) THEN {Rotina de erro}
IF n=1 THEN BEGIN
insere_esquerda;
EXIT;
END;
IF n=descritor.nos+1 THEN BEGIN
insere_direita;
EXIT;
END;
{Rotina para entrada de dados, exemplo READLN(p^.nome);}
q^.proximo:=descritor.inicio;
FOR n:=n DOWNTO 2 DO q:=q^.proximo;
p^.proximo:=q^.proximo;
q^.proximo:=p;
END;

PROCEDURE remove_direita;
VAR p,q : pont;
i : INTEGER;
BEGIN
CASE descritor.nos OF
0 : {Rotina de erro};
1 : BEGIN
p:=descritor.inicio;
inicializa;
DISPOSE(p);
EXIT;
END;
END;
p^.proximo:=descritor.inicio;
FOR i:=1 TO descritor.nos-1 DO p:=p^.proximo;
q:=p^.proximo;
p^.proximo:=descritor.inicio;
descritor.fim:=p;
DISPOSE(q);
DEC(descritor.nos);
END;

PROCEDURE remove_esquerda;
VAR p : pont;

31

BEGIN
CASE descritor.nos OF
0 : {Rotina de erro};
1 : BEGIN
p:=descritor.inicio;
inicializa;
DISPOSE(p);
EXIT;
END;
END;
p:=descritor.inicio;
descritor.inicio:=p^.proximo;
(descritor.fim)^.proximo:=descritor.inicio;
p^.proximo:=NIL;
DISPOSE(p);
DEC(descritor.nos);
END;

PROCEDURE remove_posicao(n : INTEGER);


VAR p,q : pont;
i : INTEGER;
BEGIN
IF ((n<1) OR (n>descritor.nos)) THEN {Rotina de erro};
IF n=1 THEN BEGIN
remove_esquerda;
EXIT;
END;
IF n=descritor.nos THEN BEGIN
remove_direita;
EXIT;
END;
p^.proximo:=descritor.inicio;
FOR i:=1 TO n-1 DO p:=p^.proximo;
q:=p^.proximo;
p^.proximo:=NIL;
DISPOSE(q);
DEC(descritor.nos);
END;

PROCEDURE consulta(n : INTEGER);


VAR p : pont;
BEGIN
IF ((n<1) OR (n>descritor.nos)) THEN {Rotina de erro};
p^.proximo:=descritor.inicio;
FOR n:=n DOWNTO 1 DO p:=p^.proximo;
{Rotina para impresso dos dados do n na tela, exemplo:

32

WRITELN(p^.nome);}
END;

PROCEDURE modifica(n : INTEGER);


VAR p : pont;
BEGIN
IF ((n<1) OR (n>descritor.nos)) THEN {Rotina de erro};
p^.proximo:=descritor.inicio;
FOR n:=n DOWNTO 1 DO p:=p^.proximo;
{Rotina de entrada dos dados do n na tela, exemplo:
READLN(p^.nome);}
END;

FUNCTION procura(p : pont) : INTEGER;


VAR q : pont;
i : INTEGER;
BEGIN
IF descritor.nos=0 THEN {Rotina de erro};
q:=descritor.inicio;
i:=1;
WHILE q<>NIL DO BEGIN
{Rotina que checa a igualdade, exemplo:
IF p^.nome=q^.nome THEN ...}
{Caso a expresso acima for verdadeira, a varivel i
fornece em que posio a informao foi encontrada e
sai da FUNCTION retornando o valor da varivel i};
q:=q^.proximo;
INC(i);
END;
{Rotina que diz que no foi encontrada a informao};
END;

33

BIBLIOGRAFIA

Veloso, Paulo;

Estruturas de dados
Editora Campus

Kerninghan, Brian W.;

C A linguagem de progrmao pado ANSI


Editora Campus

34

Você também pode gostar