• Nenhum resultado encontrado

Implementação em C – inserção pelo início da lista

N/A
N/A
Protected

Academic year: 2019

Share "Implementação em C – inserção pelo início da lista"

Copied!
11
0
0

Texto

(1)

Lista Simplesmente Encadeada

Numa lista encadeada, para cada novo elemento inserido na estrutura,

alocamos um espaço de memória para armazená-lo. Dessa forma, o espaço

total de memória gasto pela estrutura é proporcional ao número de elementos

armazenados.

No entanto, não podemos garantir que os elementos armazenados na lista

ocuparão um espaço de memória contíguo; portanto, não temos acesso direto

aos elementos da lista. Para percorrer todos os elementos da lista, devemos

explicitamente guardar o seu encadeamento, o que é feito armazenando-se,

junto com a informação de cada elemento, um ponteiro para o próximo

elemento da lista.

A Figura 1 ilustra o arranjo da memória de uma lista encadeada (inserção pelo

final da lista) e a Figura 2 ilustra o arranjo da memória de uma lista encadeada

(inserção pelo início da lista).

Figura 1 – Arranjo da memória de uma lista encadeada (inserção pelo final)

Figura 2 – Arranjo da memória de uma lista encadeada (inserção pelo início)

A estrutura consiste de uma seqüência encadeada de elementos, em geral

chamados de nós da lista. Um nó da lista é representado por uma estrutura que

contém, conceitualmente, dois campos: a informação armazenada e o ponteiro

para o próximo elemento da lista.

A lista é representa por um ponteiro para o primeiro elemento (ou nó). Do

primeiro elemento, podemos alcançar o segundo, seguindo o encadeamento, e

assim por diante. O último elemento da lista armazenada, como o próximo

elemento, um ponteiro inválido, com valor NULL, e sinaliza, assim, que não

existe próximo elemento.

valor1 prox valor2 prox valor3 prox

(2)

Características das Listas Encadeadas:

• São implementadas através de variáveis dinâmicas;

• Os nós que compõem a lista devem ser agregados do tipo registro contendo,

pelo menos, dois campos: um campo de tipo simples ou construído para

abrigar as informações armazenadas na lista e um campo do tipo ponteiro

para abrigar o endereço do nó subseqüente da lista;

• O acesso aos nós componentes da lista é seqüencial (para se acessar o 4o

elemento, é necessário passar antes pelo 3o, para se acessar o 3o elemento,

é necessário passar antes pelo 2o e assim sucessivamente);

• As estruturas de representação de Listas Ligadas devem obrigatoriamente

suportar conceitos como ponteiros e alocação dinâmica;

• As Listas Ligadas podem ser simplesmente encadeadas (um único ponteiro

por nó) ou duplamente encadeadas (dois ponteiros por nó).

Vantagens e Desvantagens:

• Maior complexidade inerente à manipulação de ponteiros (desvantagem);

• O fato de nem todas as linguagens de programação permitirem a construção

de estruturas para a representação de Listas Ligadas (desvantagem);

• A possibilidade de se trabalhar com listas de tamanhos indefinidos, que

podem crescer e decrescer conforme a necessidade (vantagem);

• Maior facilidade para a realização de operações de inserção e remoção, que

consistem basicamente no rearranjo de alguns ponteiros (vantagem).

Principais Operações:

• Inserção de elementos em qualquer posição da lista (início ou final);

• Retirar elemento de qualquer posição lista;

• Impressão da lista;

• Busca de elementos na lista;

Implementação em C – inserção pelo início da lista

Para exemplificar a implementação de listas encadeadas em C, vamos

(3)

em uma lista encadeada. O nó da lista pode então ser representado pela

estrutura a seguir:

struct no {

int valor;

struct no* prox; };

typedef struct no lista;

Devemos notar que se trata de uma estrutura auto-referenciada, pois, além do

campo para armazenar a informação (no caso, um número inteiro), há um

campo que é um ponteiro para uma próxima estrutura do mesmo tipo. Embora

não seja essencial, é uma boa estratégia definir o tipo lista como sinônimo de

struct lista. O tipo lista representa um nó da lista, e a estrutura da lista

encadeada é representada pelo ponteiro para seu primeiro elemento (tipo

lista*).

Função de criação

A função que cria uma lista vazia deve ter como valor de retorno uma lista sem

nenhum elemento. Como a lista é representada pelo ponteiro para o primeiro

elemento, uma lista vazia é representada pelo ponteiro NULL, pois não existem

elementos na lista. A função tem como valor de retorno a lista vazia

inicializada, isto é, o valor de retorno é NULL.

/* função de criação de lista: retorna lista vazia*/ lista* cria(void)

{

return NULL; }

Função de inserção

Uma vez criada a lista vazia, podemos inserir nela novos elementos. Para cada

elemento inserido, devemos alocar dinamicamente a memória necessária para

armazenar o elemento e encadeá-lo na lista existente. A função de inserção

mais simples insere o novo elemento no início da lista, porém não existe

obrigatoriedade na disciplina de acesso aos dados, isto é, a inserção pode ser

(4)

Uma possível implementação dessa função é mostrada a seguir. Devemos

notar que o ponteiro que representa a lista deve ter seu valor atualizado, pois a

lista deve passar a ser representada pelo ponteiro para o novo primeiro

elemento. Por essa razão, a função de inserção recebe como parâmetros de

entrada a lista na qual será inserido o novo elemento e a informação do novo

elemento e tem como valor de retorno a nova lista, representada pelo ponteiro

para o novo elemento.

/* função que insere elemento no início da lista*/ lista* insere(lista* l, int i)

{

lista* novo = (lista*) malloc(sizeof(lista)); novo->valor = i;

novo->prox = l; return novo; }

Essa função aloca dinamicamente o espaço para armazenar o novo nó da lista,

guarda informação no novo nó e faz ele apontar (isto é, tenha como próximo

elemento) para o elemento que era o primeiro da lista. A função então tem

como valor de retorno a nova lista, representada pelo ponteiro para o novo

primeiro elemento.

A Figura 3 ilustra a operação de inserção de um novo elemento no início da

lista.

Figura 3 – Inserção de um novo elemento no início da lista

Função que verifica se a lista está vazia

Pode ser útil implementar uma função para verificar se uma lista está vazia ou

não. A função recebe a lista e retorna 1 se estiver vazia ou 0 se não estiver

vazia. Como sabemos, uma lista está vazia se seu valor é NULL. Uma

implementação dessa função é mostrada a seguir:

valor3 prox valor2 prox valor1 prox

(5)

/* função vazia: retorno 1 se vazia ou 0 se não vazia*/ int lista_vazia(lista* l)

{

if(l == NULL) return 1; else return 0; }

Função que percorre os elementos da lista

Para ilustrar a implementação de uma função que percorre todos os elementos

da lista, vamos considerar a criação de uma função que imprime os valores dos

elementos armazenados em uma lista. Uma possível implementação dessa

função é mostrada a seguir.

/* função que imprime elementos da lista*/ lista* imprime(lista* l)

{

if(!lista_vazia(l)) {

lista* aux;

for(aux=l; aux != NULL; aux=aux->prox) printf("valor = %d\n",aux->valor); }

else

printf("\nTentou imprimir uma lista vazia"); }

Função de busca

Uma outra função útil consiste em verificar se um determinado elemento está

presente na lista. A função recebe a informação referente ao elemento que

queremos buscar e fornece como valor de retorno o ponteiro do nó da lista que

representa o elemento. Caso o elemento não seja encontrado na lista, o valor

retornado é NULL.

/* função que busca um elemento na lista*/ lista* busca(lista* l, int busca)

{

lista* aux;

if(!lista_vazia(l)) {

(6)

if(aux->valor == busca) {

printf("Valor encontrado.\n"); return aux;

} } } else

printf("\nTentou buscar de uma lista vazia"); return NULL; }

Função que retira um elemento da lista

Devemos agora considerar a implementação de uma função que permita retirar

um elemento da lista. A função tem como parâmetros de entrada a lista e o

valor do elemento que desejamos retirar, e deve atualizar o valor da lista, pois,

se o elemento removido for o primeiro da lista, o valor da lista deve ser

atualizado.

A função para retirar um elemento da lista é mais complexa. Se descobrirmos

que o elemento a ser retirado é o primeiro da lista, devemos fazer o novo valor

da lista passar a ser o ponteiro para o segundo elemento, e então podemos

liberar o espaço alocado para o elemento que queremos retirar. Se o elemento

a ser removido estiver no meio da lista, devemos fazer o elemento anterior a

ele passar a apontar para o seguinte, e então podemos liberar aquele que

queremos retirar.

Devemos notar que, no segundo caso, precisamos do ponteiro para o elemento

anterior a fim de acertar o encadeamento da lista. A Figura 4 e 5 ilustram as

operações de remoção.

Figura 4 – Remoção do primeiro elemento da lista

valor3 prox valor2 prox valor1 prox

prim

prim

(7)

Figura 5 – Remoção de um elemento no meio da lista

Uma possível implementação da função para retirar um elemento da lista é

mostrada a seguir. Inicialmente busca-se o elemento que se deseja retirar, mas

guarda-se uma referência para o elemento anterior. De modo análogo à função

insere, optamos por implementar a função retira tendo como valor de retorno o

eventual novo valor da lista.

lista* retira(lista* l, int valor) {

lista* ant = NULL; /* ponteiro para elemento anterior */ lista* aux = l; /* ponteiro para percorrer a lista */ if(!lista_vazia(l))

{

/* procura elemento na lista, guardando anterior */ while(aux!= NULL && aux->valor != valor)

{

ant = aux;

aux = aux->prox; }

/* verifica se achou o elemento */ if(aux == NULL)

return l;

/* retira elemento */ if(ant == NULL) l = aux->prox; else

ant->prox = aux->prox; free(aux);

return l; }

else {

printf("\nTentou remover de uma lista vazia"); return l;

} }

Obs: A implementação completa do programa encontra-se na pasta programas desta aula de Lista Simplesmente Encadeada.

Implementação em C – Inserção pelo Final da Lista

A implementação de Listas Dinâmicas também pode ser realizada com a inserção pelo final da Lista. No programa abaixo, não é utilizado a função

(8)

encadeamento) e final (responsável por guardar o último elemento encadeado do encadeamento). Todas as funções são semelhantes as apresentadas anteriormente, com exceção da função de inserção (linsere final()). Abaixo o programa completo:

#include <stdio.h> #include <conio.h> #include <cstdlib>

struct Registro {

int valor;

struct Registro *prox; };

struct Registro *aux, *inicio = NULL, *final = NULL;

/*função responsável por criar a lista*/ struct Registro* cria(void)

{

return NULL; }

/* função com tipo de retorno ponteiro para estrutura, realizando inserção pelo final*/

struct Registro* insere_final() {

int x;

printf("Entre com um numero inteiro: "); scanf("%i",&x);

aux = (struct Registro*) malloc (sizeof(struct Registro)); aux->valor = x;

aux -> prox = (struct Registro *) NULL;

if(inicio == NULL) inicio = final = aux; else

{

final -> prox = aux; final = aux;

}

return inicio; }

/* função que verifica o estado da lista: retorno 1 se vazia ou 0 se não vazia*/

int lista_vazia(struct Registro *lista) {

if(lista == NULL) return 1;

(9)

return 0; }

/* função responsável por imprimir o conteúdo da lista*/ void visualiza_lista_final(struct Registro *lista)

{

/* verifica se a lista está vazia*/ if(!lista_vazia(lista))

{

aux = lista;

while(aux != (struct Registro *) NULL) {

printf("Valor da Lista: %i\n", aux->valor); aux = aux -> prox;

} }

/* indica que a lista está vazia*/ else

printf("\nTentou imprimir uma lista vazia!"); getch();

}

/* função que busca um elemento na lista*/

struct Registro* busca(struct Registro* lista, int busca) {

bool achou = 0; if(!lista_vazia(lista)) {

for(aux=lista;aux!=NULL;aux=aux->prox) {

if(aux->valor == busca) {

printf("Valor encontrado.\n"); achou = 1;

} }

if(!achou)

printf("Valor nao encontrado.\n"); }

else {

printf("\nTentou buscar de uma lista vazia");

}

(10)

}

/* função para excluir registros da lista*/

struct Registro* excluir(struct Registro *lista, int valor) {

struct Registro *ant = NULL; /* ponteiro para elemento anterior */ aux = lista; /* ponteiro para percorrer a lista */

if(!lista_vazia(lista)) {

/* procura elemento na lista, guardando anterior */ while(aux!= NULL && aux->valor != valor)

{

ant = aux;

aux = aux->prox; }

/* verifica se achou o elemento */ if(aux == NULL)

{

printf("\nNao foi possivel a exclusao. Elemento nao encontrado!"); getche();

return lista; }

/* retira elemento */ if(ant == NULL) lista = aux->prox; else

ant->prox = aux->prox; free(aux);

printf("Elemento removido com sucesso!\n"); getche();

return lista; }

else {

printf("\nTentou remover de uma lista vazia"); getche();

return lista; }

}

main() {

int op, vremover, vbuscar; struct Registro *lista; lista = cria();

while(op != 5) {

(11)

printf("\nPrograma Para Manipulacao de Listas Ligadas"); printf("\n1 - Inserir no Final da Lista");

printf("\n2 - Visualizar Lista");

printf("\n3 - Buscar Elemento na Lista"); printf("\n4 - Excluir Elemento");

printf("\n5 - Sair do Programa");

printf("\nEntre com a Opcao Desejada: "); scanf("%i",&op);

switch(op) {

case 1:

lista = insere_final(); break;

case 2: visualiza_lista_final(lista); break;

case 3:

printf("Entre com o valor que se deseja buscar: "); scanf("%d",&vbuscar);

busca(lista,vbuscar); break;

case 4:

printf("Entre com o valor que deseja remover: "); scanf("%i",&vremover);

lista = excluir(lista, vremover); break;

case 5: exit(1); }

Imagem

Figura 4 – Remoção do primeiro elemento da lista

Referências

Documentos relacionados

Isso não significa, porém, algo negativo, uma vez que, ainda que de forma assimétrica, os esforços brasileiros têm beneficiado outros países em desenvolvimento e com

para uma próxima estrutura do mesmo tipo uma lista encadeada é representada pelo ponteiro para seu primeiro elemento, do tipo Lista*. A palavra reservada typedef nada mais é do que

Processo n.º 906/2012 [Pessoalidade das sanções. Presunção de inocência] [Regime Geral das Infrações Tributárias: art. 8º do Regime Geral das Infrações Tributárias,

No final de 1980, com as descobertas da ação analgésica de opioides na medula espinhal, a analgesia epidural se tornou um mecanismo que trouxe o uso da técnica de

– freenode  inclui um nó no início da lista livre, tornando‐o disponível  para uma nova realocação pelo programa principal Operações getnode e freenode Lista livre

No Tratado dos sistemas (1986), Condillac conduziu sua pesquisa sobre o conhecimento e as sensações através das leituras dos Clássicos, Platão e Aristóteles, e do

Faremos o cálculo do determinante pela regra de Sarrus: replicamos as duas primeiras colunas da matriz, somamos o produto dos termos da. diagonal principal e

A Ferrovia Norte-Sul, integrada ao Porto de São Luis por meio da Estrada de Ferro Carajás e a terminais de alto desempenho, é uma solução logística para o escoamento da