11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 1/18
amador programa
blog para programadores amadores que amam programar!
LINGUAGEM C
Listas encadeadas em C: conceitos, criação e manipulação de
listas simples
por Anderson Freixo • 30 out 2020 • 1 Comentário
Nessa série de posts, veremos como implementar o tipo abstrato lista em C utilizando uma estrutura de dados chamada de lista encadeada (linked
list). Depois de entender como funciona

uma lista encadeada (https://pt.wikipedia.org/wiki/Lista_ligada), fica muito fácil implementar outros dois tipos abstratos de dados: pilhas (stacks) e
filas (queues).
Começaremos com as listas encadeadas simples, depois com as listas duplamente encadeadas, e, por fim, as listas circulares. Então, não deixe de
acompanhar os posts!
Qual a diferença entre tipo abstrato de dados e

estrutura de dados?
Muita gente usa os termos tipo abstrato de dados (https://pt.wikipedia.org/wiki/Tipo_abstrato_de_dado) (TAD, para os íntimos) e estrutura de dados
(https://pt.wikipedia.org/wiki/Estrutura_de_dados) de forma intercambiável. Mas existe uma diferença fundamental entre os dois. Resumidamente,
o

TAD é uma ideia, um modelo que descreve as características de determinado objeto e que tipo de operações podem ser feitas sobre ele. Já a
estrutura de dados é a implementação real desse tipo abstrato numa linguagem de programação. Essa estrutura é implementada utilizando-se
outros tipos de dados mais básicos, como inteiros, ponteiros, etc., em conjunto.

11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 2/18
Quando implementamos um tipo abstrato, é importante que aqueles que utilizam nosso código não tenham que se preocupar com a forma como
esse tipo foi implementado. Basta que ele saiba como utilizá-lo, ou seja, o usuário se utiliza de uma abstração. Enquanto nós, que implementamos
esse tipo abstrato através de algoritmos e estruturas de dados, devemos fornecer a esse usuário uma interface para manipular esse tipo abstrato. A
interface é o conjunto de objetos e funções que fornecemos ao usuário para que ele possa usufruir dessa abstração. Essa interface geralmente é
estruturada na forma de uma biblioteca.
O que é uma lista?
No caso em questão, o tipo abstrato de dados que queremos implementar é uma lista. Uma lista é um agrupamento de valores. Diferente de um
conjunto, os elementos de uma lista são ordenados e

seus valores podem se repetir. Quando digo ordenados, não quero dizer que os elementos se encontram necessariamente em ordem crescente ou
decrescente, mas sim que existe um primeiro elemento, seguido por um segundo elemento e assim por diante. Ou seja, os elementos são dispostos
de forma sequencial, numa ordem fixa.
Mas para que essa lista tenha alguma utilidade é preciso que exista a possibilidade de realizar certas operações na mesma. Por exemplo, adicionar
itens, remover itens, contar a quantidade de

itens, verificar o valor de determinado item, etc. Contanto que a  lista cumpra esses requisitos, você pode implementá-la das mais variadas formas.
Entretanto, as duas formas mais comuns de

implementação de uma lista são através de vetores ou de listas encadeadas.
O que são listas encadeadas
Listas encadeadas são estruturas de dados formadas pelo agrupamento de outras estruturas menores chamadas de nós ou células.
Os nós de uma lista encadeada simples precisam armazenar apenas duas informações. A primeira é o valor do elemento da lista, que pode ser de
qualquer tipo (caractere, inteiro, etc). A segunda informação é o endereço de memória do nó referente ao próximo elemento da lista.
11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 3/18
Anatomia do nó, ou célula, de uma lista encadeada simples.
A lista encadeada é basicamente isso. Um grupo de nós, no qual cada nó aponta para o próximo. Para percorrer a lista, você só precisa saber o
endereço do primeiro nó, e a partir dele, você

acha o endereço do próximo, que terá o endereço do seguinte, e por aí vai. Precisamos também marcar o fim da lista de algum modo.
Convencionalmente, delimitamos o fim da lista encadeada fazendo com que o ponteiro do último elemento aponte para NULL, a constante que
indica um ponteiro nulo, em C.
11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 4/18
Uma lista encadeada simples vista ao microscópio.
Implementando uma lista encadeada em C
Como já disse anteriormente, uma lista encadeada é composta por nós. Para implementar esses nós, utilizamos uma struct com duas variáveis. Uma
armazenará o valor do elemento da lista, e a

outra variável será um ponteiro para o próximo nó. Em nosso exemplo, faremos uma lista para armazenar inteiros. Então o nosso código vai ficar
assim:
typedef struct _lista_no{

int dado;

struct _lista_no * prox;

} lista_no;
11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 5/18
No exemplo acima, utilizamos typedef para que possamos declarar nossos nós utilizando a sintaxe
lista_no novo_no;
Sem o typedef, teríamos que declarar os nós com a sintaxe
struct lista_no novo_no;
E a vida é muito curta pra a gente escrever struct toda hora. Geralmente, não precisamos dar um nome para um struct se definimos o tipo com
typedef, mas nesse caso é necessário, pois declaramos um ponteiro para um nó dentro da própria struct do nó, logo, precisamos saber o nome do
tipo. Por isso, chamamos a struct de _lista_no.
Esse é um nome temporário que será utilizado apenas nesse momento. A partir de agora, utilizaremos apenas o nome de tipo lista_no para criar
novos nós.
Agora que já temos a estrutura básica de nossa lista, precisamos implementar as funções a serem utilizadas para manipulá-la.
Criando uma lista nova
Para facilitar as coisas, vamos definir para nossa estrutura um nó chamado de “cabeça” da lista. A cabeça da lista não armazenará nenhum dado.
Ela serve apenas para apontar para o primeiro elemento propriamente dito. Caso não utilizássemos um nó fixo para apontar para o início da lista, o
ponteiro para o início da lista seria alterado toda vez que o primeiro elemento fosse removido. Para contornar isso, precisaríamos utilizar ponteiros
para ponteiros (double indirection), o que seria uma complicação a mais nesse momento. Entretanto, uma “lista sem cabeça” funciona muito bem
para implementar pilhas, então voltarei nesse assunto no futuro.
Nosso código para iniciar a lista vai ficar assim:
11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 6/18
lista_no * lista_cria(void){

lista_no * cabeca = malloc(sizeof(lista_no));

cabeca -> prox = NULL;

return cabeca;

}
Primeiro, alocamos um espaço na memória (https://pt.wikipedia.org/wiki/Aloca%C3%A7%C3%A3o_din%C3%A2mica_de_mem%C3%B3ria_em_C)
para armazenar um nó, que chamei de cabeca. A função malloc() retornará um ponteiro para um espaço de memória de tamanho suficientemente
grande para armazenar os valores de uma struct do tipo lista_no. Como disse anteriormente, por convenção, o valor NULL significa “fim da lista”,
por isso definimos prox (ponteiro para o próximo) como NULL.
Agora, para criar uma nova lista, basta definirmos uma variável do tipo lista_no * com o valor retornado por lista_cria(), assim:
lista_no * lista = lista_cria();
Não se esqueça de incluir o arquivo de cabeçalho <stdlib.h> para podermos utilizar a função malloc() .
Inserindo elementos na lista encadeada
Os três tipos de inserção tradicionais em uma lista consistem em:
Inserir no início da lista;
Inserir no final da lista;
Inserir numa posição específica da lista.
De todas essas, inserir elementos no início da lista é certamente o mais trivial:
11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 7/18
void lista_insere(lista_no * lista, int val){

lista_no * novo_no = malloc(sizeof(lista_no));

novo_no -> dado = val;

novo_no -> prox = lista -> prox;

lista -> prox = novo_no;

}
Trocando em miúdos o processo é o seguinte:
1. Cria um novo nó e define o valor do elemento;
2. O novo nó aponta para o nó para o qual a cabeça da lista aponta;
3. Agora a cabeça da lista aponta para o novo nó.
Com essa simples dança das cadeiras de ponteiros, conseguimos inserir um nó no início da lista, sem precisar reordenar todos os outros elementos!
Processo de inserção de um nó no início de uma lista encadeada com cabeça.
Interlúdio: imprimindo a lista encadeada
11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 8/18
Antes de continuarmos com as outras funções de inserção, vamos logo implementar a função de imprimir a lista na tela, para que você possa ver
seu código funcionando.
Para imprimir cada elemento, precisamos bolar um jeito de percorrer nossa lista. Na verdade, isso é muito simples, e utilizaremos o mesmo
algoritmo para percorrer a lista em diferentes funções, com pequenas modificações. Como é certo que nossa lista termina com NULL, para passear
por cada item da lista, basta o seguinte código:
while(lista){

lista = lista -> prox;

}
Quando fazemos comparações, a constante NULL equivale a 0, então while(lista) equivale a while(lista != NULL). O que estamos fazendo é
simplesmente passar para o próximo item da lista a cada iteração, e então paramos quando chegamos no ponteiro nulo. Agora basta inserirmos
dentro do laço o que queremos fazer a cada iteração. Em nosso caso, queremos imprimir cada elemento. Podemos fazer isso com um comando
como:
printf("[%d]->", lista -> dado);
Mas como nossa lista tem uma “cabeça” cuja variável dado não foi definida, antes de começarmos a iteração, precisamos pular para o primeiro nó
válido da lista. Nossa função completa fica assim:
void lista_imprime(lista_no * lista){

lista = lista -> prox;

while(lista){

printf("[%d]->", lista -> dado);
lista = lista -> prox;

}

printf("NULLn");

}
11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 9/18
Vale lembrar que quando alteramos o valor de lista dentro da função, perdemos a referência ao início da lista. O que significa que não temos mais
como acessar o início da lista depois do laço while dentro da função. Isso não importa já que retornaremos para main() logo depois, e as alterações
na variável lista não modificam a variável original. Mas caso você não queira perder a referência ao início da lista (talvez para percorrê-la
novamente), basta declarar uma variável auxiliar:
void lista_imprime(lista_no * lista){

lista_no * aux = lista -> prox;

while(aux){

printf("[%d]->", aux -> dado); 

aux = aux -> prox;

}

printf("NULLn");

}
Agora que já podemos criar a lista, inserir elementos e imprimir, podemos fazer o nosso primeiro teste. No momento, nosso código para
manipulação de listas já tem o seguinte:
11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 10/18
#include <stdio.h> /*lista_imprime */

#include <stdlib.h> /*malloc() */

typedef struct _lista_no{

int dado;

struct _lista_no * prox;

} lista_no;

lista_no * lista_cria(void){

lista_no * cabeca = malloc(sizeof(lista_no));

cabeca -> prox = NULL;

return cabeca;

}

void lista_insere(lista_no * lista, int val){

lista_no * novo_no = malloc(sizeof(lista_no));

novo_no -> dado = val;

novo_no -> prox = lista -> prox;

lista -> prox = novo_no;

}

void lista_imprime(lista_no * lista){

lista = lista -> prox;

while(lista){

printf("[%d]->", lista -> dado);
lista = lista -> prox;

}

printf("NULLn");

}
Agora já podemos testar nosso programa. Vamos definir nosso main() e utilizar as funções que acabamos de criar. O código abaixo:
11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 11/18
int main(void){

lista_no * lista = lista_cria();

lista_insere(lista, 1);

lista_insere(lista, 4);

lista_insere(lista, 2);

lista_imprime(lista);

}
Deve mostrar a seguinte saída:
[2]->[4]->[1]->NULL
Como inserimos cada item no início, a ordem dos elementos é inversa à ordem em que os adicionamos. Agora vamos ver como inserir itens no fim
da lista.
Inserindo itens no final da lista encadeada
Numa lista encadeada simples, tudo que temos é um ponteiro para o início da lista. Desse modo, para inserir itens no fim da lista precisamos
percorrer toda a lista até encontrar o ponteiro nulo e

então “encaixar” o novo elemento. Evidentemente, esse é um processo muito mais “caro” em termos de processamento e vai ficando cada vez mais
caro à medida que novos itens vão sendo acrescentados à lista. Nos próximos posts, vamos ver como podemos contornar esse fato, mas por
enquanto, vamos nos resignar e seguir em frente.
O início da nossa função lista_apensa() será igual ao da função lista_insere(), exceto em um ponto: como nosso novo item será o último da lista,
então o valor de novo_no -> prox deverá ser NULL.

Além disso, vamos modificar um pouco nosso algoritmo para percorrer listas. No caso da função de imprimir, chegamos até o valor NULL, depois
de passar pelo último item válido da lista. Nesse caso, não queremos que o valor da variável lista chegue a ser NULL. Queremos que ela pare a
iteração no último item válido da lista, para que possamos “ajustar nossos ponteiros” (entendeu o  trocadilho?). Vejamos como fica nossa função:
11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 12/18
void lista_apensa(lista_no * lista, int val){

lista_no * novo_no = malloc(sizeof(lista_no));

novo_no -> dado = val;

novo_no -> prox = NULL; /*O novo elemento vai ser o ultimo*/

while(lista -> prox){

lista = lista -> prox;

}

lista -> prox = novo_no;

}
Perceba que agora não precisamos pular a cabeça da lista explicitamente. Nesse código iteramos sobre cada item a partir do segundo nó (como a
cabeça é o primeiro nó, o segundo nó é o primeiro que armazena efetivamente um valor). Caso a lista esteja vazia, lista -> prox será igual a NULL,
então o código do laço não chega a ser executado. Caso a lista não esteja vazia, ele percorre toda a lista até que o prox do nó atual seja igual NULL.
Em outras palavras, a variável lista para quando armazena o nó do último elemento válido.
Nesse ponto, tudo que precisamos fazer é alterar a variável prox desse nó para que aponte para o nó recém criado.
Utilizando essa mesma lógica e com o auxílio de uma variável funcionando como contador, podemos criar uma função com o protótipo:
void lista_insere_indice(lista_no * lista, int indice, int val);
que armazene o novo nó num índice específico da lista. Para inserir o item 5 no início da lista, devemos chamar a função assim:
lista_insere_indice(lista, 0, 5);
Nesse caso, a função deve se comportar exatamente como lista_insere(lista, 5). Para inserir um item depois do primeiro elemento, devemos indicar:
lista_insere_indice(lista, 1, 5);
11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 13/18
E assim por diante. A implementação dessa função fica como dever de casa! O outro dever de casa é implementar as funções:
int lista_pega(lista_no * lista, int indice);

void lista_muda(lista_no * lista, int indice, int val);
A primeira função deve retornar o valor armazenado em determinado índice da lista. Já a segunda deve alterar o valor de determinado índice. A
implementação dessa função será muito semelhante à função lista_insere_indice().
Removendo itens da lista encadeada
O processo de remover itens da lista é muito semelhante ao de adicionar. Entretanto, teremos que ter o cuidado adicional de liberar o espaço da
memória alocado com o malloc() utilizando free(). Vejamos o código seguinte:
void lista_remove_prox(lista_no * lista){

	 lista_no * seguinte = lista -> prox;

	 if (seguinte){

	 	 lista -> prox = seguinte -> prox;

	 	 free(seguinte);

	 }

}
Assim como adicionar itens no início da lista, remover também exige pouco mais que ajustar alguns ponteiros. A lógica é a seguinte: a lista aponta
para o próximo elemento; para remover o próximo, basta fazer com que a lista passe a apontar para o próximo do próximo, que atualmente é o
segundo elemento.
11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 14/18
Processo de remoção de um nó do início de uma lista com cabeça.
Aqui, criamos uma variável seguinte para armazenar o endereço de memória que precisamos liberar (o próximo da lista). Se não fizéssemos isso, ao
ajustar o ponteiro lista -> prox para apontar para o próximo do próximo (lista -> prox = lista-> prox -> prox), perderíamos a referência ao elemento
antes de liberá-lo. A função continuaria funcionando e cumprindo seu objetivo, mas o espaço alocado para o nó a ser eliminado ficaria inutilizado. É
como se o nó removido continuasse

existindo, “perdido” do resto da lista porque ninguém aponta mais pra ele. Para evitar esse fim trágico para nosso querido nó, devemos libertá-lo
com a função free(), evitando assim que ele se torne uma alma penada.
11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 15/18
O fenômeno da célula penada. Como ninguém aponta para ela, ninguém sabe que ela existe.
Perceba o uso do if na terceira linha. Ele serve para
nos certificarmos de que seguinte não é NULL. Pois
se tentassemos acessar NULL -> prox, nosso
programa daria erro!
Utilizando esse código na cabeça da lista encadeada,
removemos o primeiro item da lista  (lembrando
outra vez que como a cabeça não armazena nada, os
itens da lista são armazenados a partir do segundo
nó desta). Entretanto, a mesma função serve para
remover qualquer nó da lista, desde que passemos
para a função o nó anterior ao que desejamos
remover. Então, podemos reaproveitar esse código
para implementar uma função que remova o último item da lista, ou determinado item baseado em seu índice, ou em seu valor.
Para removermos um item baseado em seu valor, podemos fazer o seguinte:
void lista_remove_val(lista_no * lista, int val){

	 lista_no * anterior = lista;

	 lista_no * atual = lista -> prox;

	 while(atual){

	 	 if (atual -> dado == val){

	 	 	 lista_remove_prox(anterior);

	 	 	 return;

	 	 }

	 	 anterior = atual;	 	 

	 	 atual = atual -> prox;

	 }

}
Bom, talvez esse negócio de “atual é igual ao próximo do atual” e “anterior é igual a atual” dê um nó na cabeça num primeiro momento. Mas a
lógica é bem simples. O nosso laço while é bem semelhante ao que já utilizamos anteriormente para percorrer a  lista. A diferença é que agora, a
cada iteração, salvamos o endereço do nó que está sendo processado no momento, antes de passar para a próxima iteração (na iteração seguinte, a
11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 16/18
variável anterior terá o valor do nó da iteração anterior, antes que alteremos novamente seu valor). Assim, quando encontrarmos o valor que
desejamos no nó atual, enviamos o anterior para nossa função de remover o próximo nó.
Você pode utilizar um raciocínio semelhante para implementar uma função que remova o último item da lista, ou que remova um item baseado no
índice da lista. Esse vai ser seu dever de casa do post de hoje!
Nossa interface para listas utilizando a estrutura de listas encadeadas simples já está ficando bem robusta. Para concluí-la, vamos desenvolver nossa
última função: void lista_limpa(lista_no *lista).

Esta função será utilizada para remover todos os nós de determinada lista, com exceção da cabeça.
Vejamos:
void lista_limpa(lista_no *lista){

	 lista_no * seguinte = lista -> prox;

	 while(seguinte){

	 	 lista -> prox = seguinte -> prox;

	 	 free(seguinte);	

	 	 seguinte = lista -> prox;

	 }

}

Quase nada de novo no front. A lógica da função é: enquanto a variável prox da cabeça não apontar para NULL, a variável prox da cabeça passa a
apontar para o elemento seguinte ao próximo, liberando a memória alocada para o elemento para o qual a cabeça inicialmente apontava.
Perceba que essa função guarda muito da mecânica da nossa conhecida…
void lista_remove_prox(lista_no * lista){

	 lista_no * seguinte = lista -> prox;

	 if (seguinte){

	 	 lista -> prox = seguinte -> prox;

	 	 free(seguinte);

	 }

}
11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 17/18
Na verdade, lista_limpa() faz a mesma coisa, só que repetidamente. Podemos então utilizar

nossa lista_remove_prox() dentro de lista_limpa(), ao invés de reescrever o código todo.
void lista_limpa(lista_no *lista){

	 while(lista -> prox)

	 	 lista_remove_prox(lista);

}

Simples, não?
Depois de utilizar essa função, a lista terá apenas a cabeça, que poderá ser reutilizada depois. Caso o usuário não precise mais da cabeça da lista, ele
mesmo deve manualmente liberar a cabeça da lista chamando free() e se comprometer a alterar o valor da variável para NULL, já que agora ela
aponta pra lixo de memória.
Claro que essa é uma abordagem perigosa, o correto seria que nossa própria função fizesse esse trabalho de limpeza. Mas, como vimos
anteriormente, se modificarmos o valor da variável que aponta para a cabeça da lista dentro de uma função, esse valor permanece intacto fora dela.
Se quiséssemos mudar efetivamente o endereço contido em nossa variável lista, precisaríamos utilizar os temidos ponteiros para ponteiros. A
questão é que criamos uma lista com cabeça justamente pra fugirmos deles! Por isso é que vou tratar desse assunto no próximo post sobre listas
encadeadas, quando vamos conhecer a lenda das listas sem cabeça (https://amadorprograma.com/2021/07/16/listas-encadeadas-sem-cabeca/)!
 
 
 Tags: estrutura de dados linguagem c listas encadeadas
← Turbinando vetores e structs em C99
DFS Sudoku Solver: um resolvedor de jogos de sudoku em Python →
 
1 comment for “Listas encadeadas em C: conceitos, criação e manipulação de
listas simples”
11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa
https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 18/18
1. 
Pingback: Listas encadeadas sem cabeça – amador programa
Blog no WordPress.com.

Mais conteúdo relacionado

PDF
Usar explicação 01
PDF
Usar explicação 0
PDF
Usar explicação
PPTX
Estrutura de dados em Java - Filas
PPTX
PDF
Lista de inteiros
PDF
Lista encadeada de inteiros
ODP
Lista Duplamente Encadeada
Usar explicação 01
Usar explicação 0
Usar explicação
Estrutura de dados em Java - Filas
Lista de inteiros
Lista encadeada de inteiros
Lista Duplamente Encadeada

Mais procurados (19)

PDF
Estrutura de Dados - Listas Encadeadas
PDF
Pilha e Fila Dinamica
PDF
Estrutura de dados - Implementação de filas com listas
PDF
Lpiii dp-apostila
PPTX
Estrutura de dados em Java - Filas
PPTX
Estrutura de dados em Java - Filas com lista encadeada
PPTX
Explicando Estruturas/Registros no C#
PDF
Estrutura de dados - Filas
PDF
Comandos basicos
PDF
10 alocacao dinamica - listas ligadas
ODP
O comando SELECT (JOIN)
PPT
Estruturas de Dados em C#
PPTX
PPTX
BDI - Aula 09 - SQL e Algebra Relacional
PDF
Aula 07 - lista linear
PPT
5.II SACIC - 2010 - Desenvolvimento de Aplicações para TVDigital com NCLUA
PPTX
Algoritmos - Aula 16 - Registros
PDF
Relatório agenda
PPTX
Structs em C
Estrutura de Dados - Listas Encadeadas
Pilha e Fila Dinamica
Estrutura de dados - Implementação de filas com listas
Lpiii dp-apostila
Estrutura de dados em Java - Filas
Estrutura de dados em Java - Filas com lista encadeada
Explicando Estruturas/Registros no C#
Estrutura de dados - Filas
Comandos basicos
10 alocacao dinamica - listas ligadas
O comando SELECT (JOIN)
Estruturas de Dados em C#
BDI - Aula 09 - SQL e Algebra Relacional
Aula 07 - lista linear
5.II SACIC - 2010 - Desenvolvimento de Aplicações para TVDigital com NCLUA
Algoritmos - Aula 16 - Registros
Relatório agenda
Structs em C
Anúncio

Semelhante a Top0 (20)

PDF
Usar explicação 01
PDF
Pged 04
PDF
listas-encadeads-estaticas-fabio-rocha.pdf
PDF
Lista Encadeada: Inserção no Início
PPT
Listas duplamente encadeadas
PDF
Aula apontadores
PDF
Lista Encadeada Simples: Inserção no Final
PPSX
Estruturas de Dados: Listas, fundamentos.
PDF
Lista duplamente encadeada
PPTX
Estrutura de dados
PDF
Estrutura de Dados - Aula 12 - Listas Duplamente Encadeadas
PDF
Estrutura de Dados Aula 12 - Listas Duplamente Encadeadas
PDF
Listas Estáticas Encadeadas usando linguagem C
PPTX
Estrutura de Dados Aula 09 - Listas simplesmente encadeadas
PDF
Listas: conceito e estáticas
PDF
Estrutura de Dados - Aula 09 - Listas Simplesmente Encadeadas
PPTX
PPTX
listasfilaepilhasapresentacaosoftware123
PPTX
Alexandre Camargo Maia - Trabalho de Conclusão da Disciplina Estrutura de Dados
PDF
Slides listas encadeadas
Usar explicação 01
Pged 04
listas-encadeads-estaticas-fabio-rocha.pdf
Lista Encadeada: Inserção no Início
Listas duplamente encadeadas
Aula apontadores
Lista Encadeada Simples: Inserção no Final
Estruturas de Dados: Listas, fundamentos.
Lista duplamente encadeada
Estrutura de dados
Estrutura de Dados - Aula 12 - Listas Duplamente Encadeadas
Estrutura de Dados Aula 12 - Listas Duplamente Encadeadas
Listas Estáticas Encadeadas usando linguagem C
Estrutura de Dados Aula 09 - Listas simplesmente encadeadas
Listas: conceito e estáticas
Estrutura de Dados - Aula 09 - Listas Simplesmente Encadeadas
listasfilaepilhasapresentacaosoftware123
Alexandre Camargo Maia - Trabalho de Conclusão da Disciplina Estrutura de Dados
Slides listas encadeadas
Anúncio

Mais de Ademar Trindade (20)

PPTX
AULA_CONCEITOS_APLIUCAÇÃO_INDICES_PARTE_2.pptx
PDF
AULA_INDICES_BANCO_DE_DADOS_RELACIONAIS_PARTE_2.pdf
PDF
AULA_INDICES_BANCO_DE_DADOS_RELACIONAISPARTE_1.pdf
PDF
texto_explicativo com o mapa mental para a disciplina de AOC
PDF
texto_explicativo com o mapa mental para a disciplina de AOC
PDF
507579230-9-1-Capitulo-3-Kotlin-Intermediario.pdf
PDF
507579287-10-1-Capitulo-2-Kotlin-e-Orientacao-a-Objetos.pdf
PPT
pesquisa-mercadolc3b3gica-aula-2-2017.ppt
PPT
pesquisacientifica.ppt
PPT
aula-091.ppt
PPT
va_Arte_Pesquisar_II_Estratégia_busca_fontes_informação_2019.ppt
PPTX
AULA_ORIENTATIVO_TCC.pptx
PPTX
AULA_INTRODUÇÃO_PARTE_1.pptx
PPTX
AULA_INTRODUÇÃO_PARTE_0.pptx
PDF
TCC Tiago Barreto de Lima.pdf
PDF
Simulando infraestruturas-computacionais-para-a-ubicomp
PDF
Isa madapt tese
PDF
Internet das-coisas
PDF
Artigo ihc1
PDF
63924715 xxi-simposio-brasileiro-de-redes-de-computadores
AULA_CONCEITOS_APLIUCAÇÃO_INDICES_PARTE_2.pptx
AULA_INDICES_BANCO_DE_DADOS_RELACIONAIS_PARTE_2.pdf
AULA_INDICES_BANCO_DE_DADOS_RELACIONAISPARTE_1.pdf
texto_explicativo com o mapa mental para a disciplina de AOC
texto_explicativo com o mapa mental para a disciplina de AOC
507579230-9-1-Capitulo-3-Kotlin-Intermediario.pdf
507579287-10-1-Capitulo-2-Kotlin-e-Orientacao-a-Objetos.pdf
pesquisa-mercadolc3b3gica-aula-2-2017.ppt
pesquisacientifica.ppt
aula-091.ppt
va_Arte_Pesquisar_II_Estratégia_busca_fontes_informação_2019.ppt
AULA_ORIENTATIVO_TCC.pptx
AULA_INTRODUÇÃO_PARTE_1.pptx
AULA_INTRODUÇÃO_PARTE_0.pptx
TCC Tiago Barreto de Lima.pdf
Simulando infraestruturas-computacionais-para-a-ubicomp
Isa madapt tese
Internet das-coisas
Artigo ihc1
63924715 xxi-simposio-brasileiro-de-redes-de-computadores

Último (10)

PPTX
SLIDE 1 PARTE 2 Fund da Informatica .pptx
PPTX
cap1-Kurose (1)- redes de computadores.pptx
PPTX
redes de computadores e internet - kurose.pptx
PDF
Pinealle - Aceleradora de Negócios em Canais Digitais
PPTX
organizaoefuncionamentodeunidadedeenfermagem-240414190344-a21272a1 (1).pptx
PPTX
Vida de Sao José Maria Tomasi, Teatino e Cardeal
DOCX
Cópia de ACOMPANHAMENTO PARA A RECOMPOSIÇÃO DA APRENDIZAGEM 8 ano História.docx
PPTX
Questionario-Fundamentos-de-Informatica-e-Design.pptx
PPTX
slide preparativo para lingua portuguesa
PPTX
SLIDE 1 PARTE 1 Fund da Informatica .pptx
SLIDE 1 PARTE 2 Fund da Informatica .pptx
cap1-Kurose (1)- redes de computadores.pptx
redes de computadores e internet - kurose.pptx
Pinealle - Aceleradora de Negócios em Canais Digitais
organizaoefuncionamentodeunidadedeenfermagem-240414190344-a21272a1 (1).pptx
Vida de Sao José Maria Tomasi, Teatino e Cardeal
Cópia de ACOMPANHAMENTO PARA A RECOMPOSIÇÃO DA APRENDIZAGEM 8 ano História.docx
Questionario-Fundamentos-de-Informatica-e-Design.pptx
slide preparativo para lingua portuguesa
SLIDE 1 PARTE 1 Fund da Informatica .pptx

Top0

  • 1. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 1/18 amador programa blog para programadores amadores que amam programar! LINGUAGEM C Listas encadeadas em C: conceitos, criação e manipulação de listas simples por Anderson Freixo • 30 out 2020 • 1 Comentário Nessa série de posts, veremos como implementar o tipo abstrato lista em C utilizando uma estrutura de dados chamada de lista encadeada (linked list). Depois de entender como funciona uma lista encadeada (https://pt.wikipedia.org/wiki/Lista_ligada), fica muito fácil implementar outros dois tipos abstratos de dados: pilhas (stacks) e filas (queues). Começaremos com as listas encadeadas simples, depois com as listas duplamente encadeadas, e, por fim, as listas circulares. Então, não deixe de acompanhar os posts! Qual a diferença entre tipo abstrato de dados e estrutura de dados? Muita gente usa os termos tipo abstrato de dados (https://pt.wikipedia.org/wiki/Tipo_abstrato_de_dado) (TAD, para os íntimos) e estrutura de dados (https://pt.wikipedia.org/wiki/Estrutura_de_dados) de forma intercambiável. Mas existe uma diferença fundamental entre os dois. Resumidamente, o TAD é uma ideia, um modelo que descreve as características de determinado objeto e que tipo de operações podem ser feitas sobre ele. Já a estrutura de dados é a implementação real desse tipo abstrato numa linguagem de programação. Essa estrutura é implementada utilizando-se outros tipos de dados mais básicos, como inteiros, ponteiros, etc., em conjunto. 
  • 2. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 2/18 Quando implementamos um tipo abstrato, é importante que aqueles que utilizam nosso código não tenham que se preocupar com a forma como esse tipo foi implementado. Basta que ele saiba como utilizá-lo, ou seja, o usuário se utiliza de uma abstração. Enquanto nós, que implementamos esse tipo abstrato através de algoritmos e estruturas de dados, devemos fornecer a esse usuário uma interface para manipular esse tipo abstrato. A interface é o conjunto de objetos e funções que fornecemos ao usuário para que ele possa usufruir dessa abstração. Essa interface geralmente é estruturada na forma de uma biblioteca. O que é uma lista? No caso em questão, o tipo abstrato de dados que queremos implementar é uma lista. Uma lista é um agrupamento de valores. Diferente de um conjunto, os elementos de uma lista são ordenados e seus valores podem se repetir. Quando digo ordenados, não quero dizer que os elementos se encontram necessariamente em ordem crescente ou decrescente, mas sim que existe um primeiro elemento, seguido por um segundo elemento e assim por diante. Ou seja, os elementos são dispostos de forma sequencial, numa ordem fixa. Mas para que essa lista tenha alguma utilidade é preciso que exista a possibilidade de realizar certas operações na mesma. Por exemplo, adicionar itens, remover itens, contar a quantidade de itens, verificar o valor de determinado item, etc. Contanto que a  lista cumpra esses requisitos, você pode implementá-la das mais variadas formas. Entretanto, as duas formas mais comuns de implementação de uma lista são através de vetores ou de listas encadeadas. O que são listas encadeadas Listas encadeadas são estruturas de dados formadas pelo agrupamento de outras estruturas menores chamadas de nós ou células. Os nós de uma lista encadeada simples precisam armazenar apenas duas informações. A primeira é o valor do elemento da lista, que pode ser de qualquer tipo (caractere, inteiro, etc). A segunda informação é o endereço de memória do nó referente ao próximo elemento da lista.
  • 3. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 3/18 Anatomia do nó, ou célula, de uma lista encadeada simples. A lista encadeada é basicamente isso. Um grupo de nós, no qual cada nó aponta para o próximo. Para percorrer a lista, você só precisa saber o endereço do primeiro nó, e a partir dele, você acha o endereço do próximo, que terá o endereço do seguinte, e por aí vai. Precisamos também marcar o fim da lista de algum modo. Convencionalmente, delimitamos o fim da lista encadeada fazendo com que o ponteiro do último elemento aponte para NULL, a constante que indica um ponteiro nulo, em C.
  • 4. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 4/18 Uma lista encadeada simples vista ao microscópio. Implementando uma lista encadeada em C Como já disse anteriormente, uma lista encadeada é composta por nós. Para implementar esses nós, utilizamos uma struct com duas variáveis. Uma armazenará o valor do elemento da lista, e a outra variável será um ponteiro para o próximo nó. Em nosso exemplo, faremos uma lista para armazenar inteiros. Então o nosso código vai ficar assim: typedef struct _lista_no{ int dado; struct _lista_no * prox; } lista_no;
  • 5. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 5/18 No exemplo acima, utilizamos typedef para que possamos declarar nossos nós utilizando a sintaxe lista_no novo_no; Sem o typedef, teríamos que declarar os nós com a sintaxe struct lista_no novo_no; E a vida é muito curta pra a gente escrever struct toda hora. Geralmente, não precisamos dar um nome para um struct se definimos o tipo com typedef, mas nesse caso é necessário, pois declaramos um ponteiro para um nó dentro da própria struct do nó, logo, precisamos saber o nome do tipo. Por isso, chamamos a struct de _lista_no. Esse é um nome temporário que será utilizado apenas nesse momento. A partir de agora, utilizaremos apenas o nome de tipo lista_no para criar novos nós. Agora que já temos a estrutura básica de nossa lista, precisamos implementar as funções a serem utilizadas para manipulá-la. Criando uma lista nova Para facilitar as coisas, vamos definir para nossa estrutura um nó chamado de “cabeça” da lista. A cabeça da lista não armazenará nenhum dado. Ela serve apenas para apontar para o primeiro elemento propriamente dito. Caso não utilizássemos um nó fixo para apontar para o início da lista, o ponteiro para o início da lista seria alterado toda vez que o primeiro elemento fosse removido. Para contornar isso, precisaríamos utilizar ponteiros para ponteiros (double indirection), o que seria uma complicação a mais nesse momento. Entretanto, uma “lista sem cabeça” funciona muito bem para implementar pilhas, então voltarei nesse assunto no futuro. Nosso código para iniciar a lista vai ficar assim:
  • 6. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 6/18 lista_no * lista_cria(void){ lista_no * cabeca = malloc(sizeof(lista_no)); cabeca -> prox = NULL; return cabeca; } Primeiro, alocamos um espaço na memória (https://pt.wikipedia.org/wiki/Aloca%C3%A7%C3%A3o_din%C3%A2mica_de_mem%C3%B3ria_em_C) para armazenar um nó, que chamei de cabeca. A função malloc() retornará um ponteiro para um espaço de memória de tamanho suficientemente grande para armazenar os valores de uma struct do tipo lista_no. Como disse anteriormente, por convenção, o valor NULL significa “fim da lista”, por isso definimos prox (ponteiro para o próximo) como NULL. Agora, para criar uma nova lista, basta definirmos uma variável do tipo lista_no * com o valor retornado por lista_cria(), assim: lista_no * lista = lista_cria(); Não se esqueça de incluir o arquivo de cabeçalho <stdlib.h> para podermos utilizar a função malloc() . Inserindo elementos na lista encadeada Os três tipos de inserção tradicionais em uma lista consistem em: Inserir no início da lista; Inserir no final da lista; Inserir numa posição específica da lista. De todas essas, inserir elementos no início da lista é certamente o mais trivial:
  • 7. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 7/18 void lista_insere(lista_no * lista, int val){ lista_no * novo_no = malloc(sizeof(lista_no)); novo_no -> dado = val; novo_no -> prox = lista -> prox; lista -> prox = novo_no; } Trocando em miúdos o processo é o seguinte: 1. Cria um novo nó e define o valor do elemento; 2. O novo nó aponta para o nó para o qual a cabeça da lista aponta; 3. Agora a cabeça da lista aponta para o novo nó. Com essa simples dança das cadeiras de ponteiros, conseguimos inserir um nó no início da lista, sem precisar reordenar todos os outros elementos! Processo de inserção de um nó no início de uma lista encadeada com cabeça. Interlúdio: imprimindo a lista encadeada
  • 8. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 8/18 Antes de continuarmos com as outras funções de inserção, vamos logo implementar a função de imprimir a lista na tela, para que você possa ver seu código funcionando. Para imprimir cada elemento, precisamos bolar um jeito de percorrer nossa lista. Na verdade, isso é muito simples, e utilizaremos o mesmo algoritmo para percorrer a lista em diferentes funções, com pequenas modificações. Como é certo que nossa lista termina com NULL, para passear por cada item da lista, basta o seguinte código: while(lista){ lista = lista -> prox; } Quando fazemos comparações, a constante NULL equivale a 0, então while(lista) equivale a while(lista != NULL). O que estamos fazendo é simplesmente passar para o próximo item da lista a cada iteração, e então paramos quando chegamos no ponteiro nulo. Agora basta inserirmos dentro do laço o que queremos fazer a cada iteração. Em nosso caso, queremos imprimir cada elemento. Podemos fazer isso com um comando como: printf("[%d]->", lista -> dado); Mas como nossa lista tem uma “cabeça” cuja variável dado não foi definida, antes de começarmos a iteração, precisamos pular para o primeiro nó válido da lista. Nossa função completa fica assim: void lista_imprime(lista_no * lista){ lista = lista -> prox; while(lista){ printf("[%d]->", lista -> dado); lista = lista -> prox; } printf("NULLn"); }
  • 9. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 9/18 Vale lembrar que quando alteramos o valor de lista dentro da função, perdemos a referência ao início da lista. O que significa que não temos mais como acessar o início da lista depois do laço while dentro da função. Isso não importa já que retornaremos para main() logo depois, e as alterações na variável lista não modificam a variável original. Mas caso você não queira perder a referência ao início da lista (talvez para percorrê-la novamente), basta declarar uma variável auxiliar: void lista_imprime(lista_no * lista){ lista_no * aux = lista -> prox; while(aux){ printf("[%d]->", aux -> dado); aux = aux -> prox; } printf("NULLn"); } Agora que já podemos criar a lista, inserir elementos e imprimir, podemos fazer o nosso primeiro teste. No momento, nosso código para manipulação de listas já tem o seguinte:
  • 10. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 10/18 #include <stdio.h> /*lista_imprime */ #include <stdlib.h> /*malloc() */ typedef struct _lista_no{ int dado; struct _lista_no * prox; } lista_no; lista_no * lista_cria(void){ lista_no * cabeca = malloc(sizeof(lista_no)); cabeca -> prox = NULL; return cabeca; } void lista_insere(lista_no * lista, int val){ lista_no * novo_no = malloc(sizeof(lista_no)); novo_no -> dado = val; novo_no -> prox = lista -> prox; lista -> prox = novo_no; } void lista_imprime(lista_no * lista){ lista = lista -> prox; while(lista){ printf("[%d]->", lista -> dado); lista = lista -> prox; } printf("NULLn"); } Agora já podemos testar nosso programa. Vamos definir nosso main() e utilizar as funções que acabamos de criar. O código abaixo:
  • 11. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 11/18 int main(void){ lista_no * lista = lista_cria(); lista_insere(lista, 1); lista_insere(lista, 4); lista_insere(lista, 2); lista_imprime(lista); } Deve mostrar a seguinte saída: [2]->[4]->[1]->NULL Como inserimos cada item no início, a ordem dos elementos é inversa à ordem em que os adicionamos. Agora vamos ver como inserir itens no fim da lista. Inserindo itens no final da lista encadeada Numa lista encadeada simples, tudo que temos é um ponteiro para o início da lista. Desse modo, para inserir itens no fim da lista precisamos percorrer toda a lista até encontrar o ponteiro nulo e então “encaixar” o novo elemento. Evidentemente, esse é um processo muito mais “caro” em termos de processamento e vai ficando cada vez mais caro à medida que novos itens vão sendo acrescentados à lista. Nos próximos posts, vamos ver como podemos contornar esse fato, mas por enquanto, vamos nos resignar e seguir em frente. O início da nossa função lista_apensa() será igual ao da função lista_insere(), exceto em um ponto: como nosso novo item será o último da lista, então o valor de novo_no -> prox deverá ser NULL. Além disso, vamos modificar um pouco nosso algoritmo para percorrer listas. No caso da função de imprimir, chegamos até o valor NULL, depois de passar pelo último item válido da lista. Nesse caso, não queremos que o valor da variável lista chegue a ser NULL. Queremos que ela pare a iteração no último item válido da lista, para que possamos “ajustar nossos ponteiros” (entendeu o  trocadilho?). Vejamos como fica nossa função:
  • 12. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 12/18 void lista_apensa(lista_no * lista, int val){ lista_no * novo_no = malloc(sizeof(lista_no)); novo_no -> dado = val; novo_no -> prox = NULL; /*O novo elemento vai ser o ultimo*/ while(lista -> prox){ lista = lista -> prox; } lista -> prox = novo_no; } Perceba que agora não precisamos pular a cabeça da lista explicitamente. Nesse código iteramos sobre cada item a partir do segundo nó (como a cabeça é o primeiro nó, o segundo nó é o primeiro que armazena efetivamente um valor). Caso a lista esteja vazia, lista -> prox será igual a NULL, então o código do laço não chega a ser executado. Caso a lista não esteja vazia, ele percorre toda a lista até que o prox do nó atual seja igual NULL. Em outras palavras, a variável lista para quando armazena o nó do último elemento válido. Nesse ponto, tudo que precisamos fazer é alterar a variável prox desse nó para que aponte para o nó recém criado. Utilizando essa mesma lógica e com o auxílio de uma variável funcionando como contador, podemos criar uma função com o protótipo: void lista_insere_indice(lista_no * lista, int indice, int val); que armazene o novo nó num índice específico da lista. Para inserir o item 5 no início da lista, devemos chamar a função assim: lista_insere_indice(lista, 0, 5); Nesse caso, a função deve se comportar exatamente como lista_insere(lista, 5). Para inserir um item depois do primeiro elemento, devemos indicar: lista_insere_indice(lista, 1, 5);
  • 13. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 13/18 E assim por diante. A implementação dessa função fica como dever de casa! O outro dever de casa é implementar as funções: int lista_pega(lista_no * lista, int indice); void lista_muda(lista_no * lista, int indice, int val); A primeira função deve retornar o valor armazenado em determinado índice da lista. Já a segunda deve alterar o valor de determinado índice. A implementação dessa função será muito semelhante à função lista_insere_indice(). Removendo itens da lista encadeada O processo de remover itens da lista é muito semelhante ao de adicionar. Entretanto, teremos que ter o cuidado adicional de liberar o espaço da memória alocado com o malloc() utilizando free(). Vejamos o código seguinte: void lista_remove_prox(lista_no * lista){ lista_no * seguinte = lista -> prox; if (seguinte){ lista -> prox = seguinte -> prox; free(seguinte); } } Assim como adicionar itens no início da lista, remover também exige pouco mais que ajustar alguns ponteiros. A lógica é a seguinte: a lista aponta para o próximo elemento; para remover o próximo, basta fazer com que a lista passe a apontar para o próximo do próximo, que atualmente é o segundo elemento.
  • 14. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 14/18 Processo de remoção de um nó do início de uma lista com cabeça. Aqui, criamos uma variável seguinte para armazenar o endereço de memória que precisamos liberar (o próximo da lista). Se não fizéssemos isso, ao ajustar o ponteiro lista -> prox para apontar para o próximo do próximo (lista -> prox = lista-> prox -> prox), perderíamos a referência ao elemento antes de liberá-lo. A função continuaria funcionando e cumprindo seu objetivo, mas o espaço alocado para o nó a ser eliminado ficaria inutilizado. É como se o nó removido continuasse existindo, “perdido” do resto da lista porque ninguém aponta mais pra ele. Para evitar esse fim trágico para nosso querido nó, devemos libertá-lo com a função free(), evitando assim que ele se torne uma alma penada.
  • 15. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 15/18 O fenômeno da célula penada. Como ninguém aponta para ela, ninguém sabe que ela existe. Perceba o uso do if na terceira linha. Ele serve para nos certificarmos de que seguinte não é NULL. Pois se tentassemos acessar NULL -> prox, nosso programa daria erro! Utilizando esse código na cabeça da lista encadeada, removemos o primeiro item da lista  (lembrando outra vez que como a cabeça não armazena nada, os itens da lista são armazenados a partir do segundo nó desta). Entretanto, a mesma função serve para remover qualquer nó da lista, desde que passemos para a função o nó anterior ao que desejamos remover. Então, podemos reaproveitar esse código para implementar uma função que remova o último item da lista, ou determinado item baseado em seu índice, ou em seu valor. Para removermos um item baseado em seu valor, podemos fazer o seguinte: void lista_remove_val(lista_no * lista, int val){ lista_no * anterior = lista; lista_no * atual = lista -> prox; while(atual){ if (atual -> dado == val){ lista_remove_prox(anterior); return; } anterior = atual; atual = atual -> prox; } } Bom, talvez esse negócio de “atual é igual ao próximo do atual” e “anterior é igual a atual” dê um nó na cabeça num primeiro momento. Mas a lógica é bem simples. O nosso laço while é bem semelhante ao que já utilizamos anteriormente para percorrer a  lista. A diferença é que agora, a cada iteração, salvamos o endereço do nó que está sendo processado no momento, antes de passar para a próxima iteração (na iteração seguinte, a
  • 16. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 16/18 variável anterior terá o valor do nó da iteração anterior, antes que alteremos novamente seu valor). Assim, quando encontrarmos o valor que desejamos no nó atual, enviamos o anterior para nossa função de remover o próximo nó. Você pode utilizar um raciocínio semelhante para implementar uma função que remova o último item da lista, ou que remova um item baseado no índice da lista. Esse vai ser seu dever de casa do post de hoje! Nossa interface para listas utilizando a estrutura de listas encadeadas simples já está ficando bem robusta. Para concluí-la, vamos desenvolver nossa última função: void lista_limpa(lista_no *lista). Esta função será utilizada para remover todos os nós de determinada lista, com exceção da cabeça. Vejamos: void lista_limpa(lista_no *lista){ lista_no * seguinte = lista -> prox; while(seguinte){ lista -> prox = seguinte -> prox; free(seguinte); seguinte = lista -> prox; } } Quase nada de novo no front. A lógica da função é: enquanto a variável prox da cabeça não apontar para NULL, a variável prox da cabeça passa a apontar para o elemento seguinte ao próximo, liberando a memória alocada para o elemento para o qual a cabeça inicialmente apontava. Perceba que essa função guarda muito da mecânica da nossa conhecida… void lista_remove_prox(lista_no * lista){ lista_no * seguinte = lista -> prox; if (seguinte){ lista -> prox = seguinte -> prox; free(seguinte); } }
  • 17. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 17/18 Na verdade, lista_limpa() faz a mesma coisa, só que repetidamente. Podemos então utilizar nossa lista_remove_prox() dentro de lista_limpa(), ao invés de reescrever o código todo. void lista_limpa(lista_no *lista){ while(lista -> prox) lista_remove_prox(lista); } Simples, não? Depois de utilizar essa função, a lista terá apenas a cabeça, que poderá ser reutilizada depois. Caso o usuário não precise mais da cabeça da lista, ele mesmo deve manualmente liberar a cabeça da lista chamando free() e se comprometer a alterar o valor da variável para NULL, já que agora ela aponta pra lixo de memória. Claro que essa é uma abordagem perigosa, o correto seria que nossa própria função fizesse esse trabalho de limpeza. Mas, como vimos anteriormente, se modificarmos o valor da variável que aponta para a cabeça da lista dentro de uma função, esse valor permanece intacto fora dela. Se quiséssemos mudar efetivamente o endereço contido em nossa variável lista, precisaríamos utilizar os temidos ponteiros para ponteiros. A questão é que criamos uma lista com cabeça justamente pra fugirmos deles! Por isso é que vou tratar desse assunto no próximo post sobre listas encadeadas, quando vamos conhecer a lenda das listas sem cabeça (https://amadorprograma.com/2021/07/16/listas-encadeadas-sem-cabeca/)!      Tags: estrutura de dados linguagem c listas encadeadas ← Turbinando vetores e structs em C99 DFS Sudoku Solver: um resolvedor de jogos de sudoku em Python →   1 comment for “Listas encadeadas em C: conceitos, criação e manipulação de listas simples”
  • 18. 11/10/21, 12:44 Listas encadeadas em C: conceitos, criação e manipulação de listas simples – amador programa https://amadorprograma.com/2020/10/30/listas-encadeadas-em-c/ 18/18 1.  Pingback: Listas encadeadas sem cabeça – amador programa Blog no WordPress.com.