SlideShare uma empresa Scribd logo
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

Mais procurados

Estrutura de Dados - Listas Encadeadas
Estrutura de Dados - Listas EncadeadasEstrutura de Dados - Listas Encadeadas
Estrutura de Dados - Listas Encadeadas
Adriano Teixeira de Souza
 
Pilha e Fila Dinamica
Pilha e Fila DinamicaPilha e Fila Dinamica
Pilha e Fila Dinamica
Sérgio Souza Costa
 
Estrutura de dados - Implementação de filas com listas
Estrutura de dados - Implementação de filas com listasEstrutura de dados - Implementação de filas com listas
Estrutura de dados - Implementação de filas com listas
Adriano Teixeira de Souza
 
Lpiii dp-apostila
Lpiii dp-apostilaLpiii dp-apostila
Lpiii dp-apostila
Jonathan Henrique
 
Estrutura de dados em Java - Filas
Estrutura de dados em Java - Filas Estrutura de dados em Java - Filas
Estrutura de dados em Java - Filas
Adriano Teixeira de Souza
 
Estrutura de dados em Java - Filas com lista encadeada
Estrutura de dados em Java - Filas com lista encadeada Estrutura de dados em Java - Filas com lista encadeada
Estrutura de dados em Java - Filas com lista encadeada
Adriano Teixeira de Souza
 
Explicando Estruturas/Registros no C#
Explicando Estruturas/Registros no C#Explicando Estruturas/Registros no C#
Explicando Estruturas/Registros no C#
Denis Fernandes Gomes
 
Estrutura de dados - Filas
Estrutura de dados - FilasEstrutura de dados - Filas
Estrutura de dados - Filas
Adriano Teixeira de Souza
 
Comandos basicos
Comandos basicosComandos basicos
Comandos basicos
Rafael Copatti Trindade
 
10 alocacao dinamica - listas ligadas
10   alocacao dinamica - listas ligadas10   alocacao dinamica - listas ligadas
10 alocacao dinamica - listas ligadas
Ricardo Bolanho
 
O comando SELECT (JOIN)
O comando SELECT (JOIN)O comando SELECT (JOIN)
O comando SELECT (JOIN)
Graciano Torrão
 
Estruturas de Dados em C#
Estruturas de Dados em C#Estruturas de Dados em C#
Estruturas de Dados em C#
Marcelo Charan
 
Aula 20
Aula 20Aula 20
BDI - Aula 09 - SQL e Algebra Relacional
BDI - Aula 09 - SQL e Algebra RelacionalBDI - Aula 09 - SQL e Algebra Relacional
BDI - Aula 09 - SQL e Algebra Relacional
Rodrigo Kiyoshi Saito
 
Aula 07 - lista linear
Aula 07 - lista linearAula 07 - lista linear
Aula 07 - lista linear
Cristiano Pires Martins
 
5.II SACIC - 2010 - Desenvolvimento de Aplicações para TVDigital com NCLUA
5.II SACIC - 2010 - Desenvolvimento de Aplicações para TVDigital com NCLUA5.II SACIC - 2010 - Desenvolvimento de Aplicações para TVDigital com NCLUA
5.II SACIC - 2010 - Desenvolvimento de Aplicações para TVDigital com NCLUA
Cândido Sales Gomes
 
Algoritmos - Aula 16 - Registros
Algoritmos - Aula 16 - RegistrosAlgoritmos - Aula 16 - Registros
Algoritmos - Aula 16 - Registros
Rodrigo Kiyoshi Saito
 
Relatório agenda
Relatório   agendaRelatório   agenda
Relatório agenda
Jonatas Roberto
 
Structs em C
Structs em CStructs em C
Structs em C
Pablo Silva
 

Mais procurados (19)

Estrutura de Dados - Listas Encadeadas
Estrutura de Dados - Listas EncadeadasEstrutura de Dados - Listas Encadeadas
Estrutura de Dados - Listas Encadeadas
 
Pilha e Fila Dinamica
Pilha e Fila DinamicaPilha e Fila Dinamica
Pilha e Fila Dinamica
 
Estrutura de dados - Implementação de filas com listas
Estrutura de dados - Implementação de filas com listasEstrutura de dados - Implementação de filas com listas
Estrutura de dados - Implementação de filas com listas
 
Lpiii dp-apostila
Lpiii dp-apostilaLpiii dp-apostila
Lpiii dp-apostila
 
Estrutura de dados em Java - Filas
Estrutura de dados em Java - Filas Estrutura de dados em Java - Filas
Estrutura de dados em Java - Filas
 
Estrutura de dados em Java - Filas com lista encadeada
Estrutura de dados em Java - Filas com lista encadeada Estrutura de dados em Java - Filas com lista encadeada
Estrutura de dados em Java - Filas com lista encadeada
 
Explicando Estruturas/Registros no C#
Explicando Estruturas/Registros no C#Explicando Estruturas/Registros no C#
Explicando Estruturas/Registros no C#
 
Estrutura de dados - Filas
Estrutura de dados - FilasEstrutura de dados - Filas
Estrutura de dados - Filas
 
Comandos basicos
Comandos basicosComandos basicos
Comandos basicos
 
10 alocacao dinamica - listas ligadas
10   alocacao dinamica - listas ligadas10   alocacao dinamica - listas ligadas
10 alocacao dinamica - listas ligadas
 
O comando SELECT (JOIN)
O comando SELECT (JOIN)O comando SELECT (JOIN)
O comando SELECT (JOIN)
 
Estruturas de Dados em C#
Estruturas de Dados em C#Estruturas de Dados em C#
Estruturas de Dados em C#
 
Aula 20
Aula 20Aula 20
Aula 20
 
BDI - Aula 09 - SQL e Algebra Relacional
BDI - Aula 09 - SQL e Algebra RelacionalBDI - Aula 09 - SQL e Algebra Relacional
BDI - Aula 09 - SQL e Algebra Relacional
 
Aula 07 - lista linear
Aula 07 - lista linearAula 07 - lista linear
Aula 07 - lista linear
 
5.II SACIC - 2010 - Desenvolvimento de Aplicações para TVDigital com NCLUA
5.II SACIC - 2010 - Desenvolvimento de Aplicações para TVDigital com NCLUA5.II SACIC - 2010 - Desenvolvimento de Aplicações para TVDigital com NCLUA
5.II SACIC - 2010 - Desenvolvimento de Aplicações para TVDigital com NCLUA
 
Algoritmos - Aula 16 - Registros
Algoritmos - Aula 16 - RegistrosAlgoritmos - Aula 16 - Registros
Algoritmos - Aula 16 - Registros
 
Relatório agenda
Relatório   agendaRelatório   agenda
Relatório agenda
 
Structs em C
Structs em CStructs em C
Structs em C
 

Semelhante a Top0

Usar explicação 01
Usar explicação 01Usar explicação 01
Usar explicação 01
Ademar Trindade
 
Pged 04
Pged 04Pged 04
Pged 04
samuelthiago
 
Pged 03
Pged 03Pged 03
Pged 03
samuelthiago
 
Estrutura de Dados
Estrutura de DadosEstrutura de Dados
Estrutura de Dados
PauloOliveira186307
 
Pesquisa ppi 2
Pesquisa ppi 2Pesquisa ppi 2
Pesquisa ppi 2
Otaviano Viana
 
Estrutura de dados
Estrutura de dadosEstrutura de dados
Estrutura de dados
gjpbg
 
Apostila estrutura de dados 2
Apostila estrutura de dados 2Apostila estrutura de dados 2
Apostila estrutura de dados 2
Leandro Lopes
 
Apostila de Alocação Dinâmica em C
Apostila de Alocação Dinâmica em CApostila de Alocação Dinâmica em C
Estrutura de dados
Estrutura de dadosEstrutura de dados
Estrutura de dados
Jailson Torquato
 
Pilhas e Filas.ppt
Pilhas e Filas.pptPilhas e Filas.ppt
Pilhas e Filas.ppt
JoberthSilva
 
Introdução a estruturas de dados em python
Introdução a estruturas de dados em pythonIntrodução a estruturas de dados em python
Introdução a estruturas de dados em python
Alvaro Oliveira
 
Algoritmo e Estrutura de dados em C - Aula 01 - 2019
Algoritmo e Estrutura de dados em C - Aula 01 - 2019Algoritmo e Estrutura de dados em C - Aula 01 - 2019
Algoritmo e Estrutura de dados em C - Aula 01 - 2019
Eduardo S. Pereira
 
Java Desktop
Java DesktopJava Desktop
Java Desktop
ciceroclc
 
Fundamentos de SQL - Parte 3 de 8
Fundamentos de SQL - Parte 3 de 8Fundamentos de SQL - Parte 3 de 8
Fundamentos de SQL - Parte 3 de 8
Emiliano Barbosa
 
Tutorial aed iii 003 - algoritmo de ordenação shellsort
Tutorial aed iii   003 - algoritmo de ordenação shellsortTutorial aed iii   003 - algoritmo de ordenação shellsort
Tutorial aed iii 003 - algoritmo de ordenação shellsort
Flávio Freitas
 
Apostila PhP com Wamp 3a Parte
Apostila PhP com Wamp 3a ParteApostila PhP com Wamp 3a Parte
Apostila PhP com Wamp 3a Parte
Ilton Barbosa
 
Python2.5.ppt
Python2.5.pptPython2.5.ppt
Python2.5.ppt
wildcat9335
 
Map, filter e reduce
Map, filter e reduceMap, filter e reduce
Map, filter e reduce
Jackson Veroneze
 
Algoritmo
AlgoritmoAlgoritmo
Aula de SQL - Básico
Aula de SQL - BásicoAula de SQL - Básico
Aula de SQL - Básico
Airton Zanon
 

Semelhante a Top0 (20)

Usar explicação 01
Usar explicação 01Usar explicação 01
Usar explicação 01
 
Pged 04
Pged 04Pged 04
Pged 04
 
Pged 03
Pged 03Pged 03
Pged 03
 
Estrutura de Dados
Estrutura de DadosEstrutura de Dados
Estrutura de Dados
 
Pesquisa ppi 2
Pesquisa ppi 2Pesquisa ppi 2
Pesquisa ppi 2
 
Estrutura de dados
Estrutura de dadosEstrutura de dados
Estrutura de dados
 
Apostila estrutura de dados 2
Apostila estrutura de dados 2Apostila estrutura de dados 2
Apostila estrutura de dados 2
 
Apostila de Alocação Dinâmica em C
Apostila de Alocação Dinâmica em CApostila de Alocação Dinâmica em C
Apostila de Alocação Dinâmica em C
 
Estrutura de dados
Estrutura de dadosEstrutura de dados
Estrutura de dados
 
Pilhas e Filas.ppt
Pilhas e Filas.pptPilhas e Filas.ppt
Pilhas e Filas.ppt
 
Introdução a estruturas de dados em python
Introdução a estruturas de dados em pythonIntrodução a estruturas de dados em python
Introdução a estruturas de dados em python
 
Algoritmo e Estrutura de dados em C - Aula 01 - 2019
Algoritmo e Estrutura de dados em C - Aula 01 - 2019Algoritmo e Estrutura de dados em C - Aula 01 - 2019
Algoritmo e Estrutura de dados em C - Aula 01 - 2019
 
Java Desktop
Java DesktopJava Desktop
Java Desktop
 
Fundamentos de SQL - Parte 3 de 8
Fundamentos de SQL - Parte 3 de 8Fundamentos de SQL - Parte 3 de 8
Fundamentos de SQL - Parte 3 de 8
 
Tutorial aed iii 003 - algoritmo de ordenação shellsort
Tutorial aed iii   003 - algoritmo de ordenação shellsortTutorial aed iii   003 - algoritmo de ordenação shellsort
Tutorial aed iii 003 - algoritmo de ordenação shellsort
 
Apostila PhP com Wamp 3a Parte
Apostila PhP com Wamp 3a ParteApostila PhP com Wamp 3a Parte
Apostila PhP com Wamp 3a Parte
 
Python2.5.ppt
Python2.5.pptPython2.5.ppt
Python2.5.ppt
 
Map, filter e reduce
Map, filter e reduceMap, filter e reduce
Map, filter e reduce
 
Algoritmo
AlgoritmoAlgoritmo
Algoritmo
 
Aula de SQL - Básico
Aula de SQL - BásicoAula de SQL - Básico
Aula de SQL - Básico
 

Mais de Ademar Trindade

pesquisa-mercadolc3b3gica-aula-2-2017.ppt
pesquisa-mercadolc3b3gica-aula-2-2017.pptpesquisa-mercadolc3b3gica-aula-2-2017.ppt
pesquisa-mercadolc3b3gica-aula-2-2017.ppt
Ademar Trindade
 
pesquisacientifica.ppt
pesquisacientifica.pptpesquisacientifica.ppt
pesquisacientifica.ppt
Ademar Trindade
 
aula-091.ppt
aula-091.pptaula-091.ppt
aula-091.ppt
Ademar Trindade
 
va_Arte_Pesquisar_II_Estratégia_busca_fontes_informação_2019.ppt
va_Arte_Pesquisar_II_Estratégia_busca_fontes_informação_2019.pptva_Arte_Pesquisar_II_Estratégia_busca_fontes_informação_2019.ppt
va_Arte_Pesquisar_II_Estratégia_busca_fontes_informação_2019.ppt
Ademar Trindade
 
AULA_ORIENTATIVO_TCC.pptx
AULA_ORIENTATIVO_TCC.pptxAULA_ORIENTATIVO_TCC.pptx
AULA_ORIENTATIVO_TCC.pptx
Ademar Trindade
 
AULA_INTRODUÇÃO_PARTE_1.pptx
AULA_INTRODUÇÃO_PARTE_1.pptxAULA_INTRODUÇÃO_PARTE_1.pptx
AULA_INTRODUÇÃO_PARTE_1.pptx
Ademar Trindade
 
AULA_INTRODUÇÃO_PARTE_0.pptx
AULA_INTRODUÇÃO_PARTE_0.pptxAULA_INTRODUÇÃO_PARTE_0.pptx
AULA_INTRODUÇÃO_PARTE_0.pptx
Ademar Trindade
 
TCC Tiago Barreto de Lima.pdf
TCC Tiago Barreto de Lima.pdfTCC Tiago Barreto de Lima.pdf
TCC Tiago Barreto de Lima.pdf
Ademar Trindade
 
Simulando infraestruturas-computacionais-para-a-ubicomp
Simulando infraestruturas-computacionais-para-a-ubicompSimulando infraestruturas-computacionais-para-a-ubicomp
Simulando infraestruturas-computacionais-para-a-ubicomp
Ademar Trindade
 
Isa madapt tese
Isa madapt teseIsa madapt tese
Isa madapt tese
Ademar Trindade
 
Internet das-coisas
Internet das-coisasInternet das-coisas
Internet das-coisas
Ademar Trindade
 
Artigo ihc1
Artigo ihc1Artigo ihc1
Artigo ihc1
Ademar Trindade
 
63924715 xxi-simposio-brasileiro-de-redes-de-computadores
63924715 xxi-simposio-brasileiro-de-redes-de-computadores63924715 xxi-simposio-brasileiro-de-redes-de-computadores
63924715 xxi-simposio-brasileiro-de-redes-de-computadores
Ademar Trindade
 
4452
44524452
2007 alexandre rodriguesgomes
2007 alexandre rodriguesgomes2007 alexandre rodriguesgomes
2007 alexandre rodriguesgomes
Ademar Trindade
 
926 4624-1-pb
926 4624-1-pb926 4624-1-pb
926 4624-1-pb
Ademar Trindade
 
45
4545
170557670 pesquisa-e-ordenacao
170557670 pesquisa-e-ordenacao170557670 pesquisa-e-ordenacao
170557670 pesquisa-e-ordenacao
Ademar Trindade
 
7082 texto do artigo-33807-2-10-20180903
7082 texto do artigo-33807-2-10-201809037082 texto do artigo-33807-2-10-20180903
7082 texto do artigo-33807-2-10-20180903
Ademar Trindade
 
00011
0001100011

Mais de Ademar Trindade (20)

pesquisa-mercadolc3b3gica-aula-2-2017.ppt
pesquisa-mercadolc3b3gica-aula-2-2017.pptpesquisa-mercadolc3b3gica-aula-2-2017.ppt
pesquisa-mercadolc3b3gica-aula-2-2017.ppt
 
pesquisacientifica.ppt
pesquisacientifica.pptpesquisacientifica.ppt
pesquisacientifica.ppt
 
aula-091.ppt
aula-091.pptaula-091.ppt
aula-091.ppt
 
va_Arte_Pesquisar_II_Estratégia_busca_fontes_informação_2019.ppt
va_Arte_Pesquisar_II_Estratégia_busca_fontes_informação_2019.pptva_Arte_Pesquisar_II_Estratégia_busca_fontes_informação_2019.ppt
va_Arte_Pesquisar_II_Estratégia_busca_fontes_informação_2019.ppt
 
AULA_ORIENTATIVO_TCC.pptx
AULA_ORIENTATIVO_TCC.pptxAULA_ORIENTATIVO_TCC.pptx
AULA_ORIENTATIVO_TCC.pptx
 
AULA_INTRODUÇÃO_PARTE_1.pptx
AULA_INTRODUÇÃO_PARTE_1.pptxAULA_INTRODUÇÃO_PARTE_1.pptx
AULA_INTRODUÇÃO_PARTE_1.pptx
 
AULA_INTRODUÇÃO_PARTE_0.pptx
AULA_INTRODUÇÃO_PARTE_0.pptxAULA_INTRODUÇÃO_PARTE_0.pptx
AULA_INTRODUÇÃO_PARTE_0.pptx
 
TCC Tiago Barreto de Lima.pdf
TCC Tiago Barreto de Lima.pdfTCC Tiago Barreto de Lima.pdf
TCC Tiago Barreto de Lima.pdf
 
Simulando infraestruturas-computacionais-para-a-ubicomp
Simulando infraestruturas-computacionais-para-a-ubicompSimulando infraestruturas-computacionais-para-a-ubicomp
Simulando infraestruturas-computacionais-para-a-ubicomp
 
Isa madapt tese
Isa madapt teseIsa madapt tese
Isa madapt tese
 
Internet das-coisas
Internet das-coisasInternet das-coisas
Internet das-coisas
 
Artigo ihc1
Artigo ihc1Artigo ihc1
Artigo ihc1
 
63924715 xxi-simposio-brasileiro-de-redes-de-computadores
63924715 xxi-simposio-brasileiro-de-redes-de-computadores63924715 xxi-simposio-brasileiro-de-redes-de-computadores
63924715 xxi-simposio-brasileiro-de-redes-de-computadores
 
4452
44524452
4452
 
2007 alexandre rodriguesgomes
2007 alexandre rodriguesgomes2007 alexandre rodriguesgomes
2007 alexandre rodriguesgomes
 
926 4624-1-pb
926 4624-1-pb926 4624-1-pb
926 4624-1-pb
 
45
4545
45
 
170557670 pesquisa-e-ordenacao
170557670 pesquisa-e-ordenacao170557670 pesquisa-e-ordenacao
170557670 pesquisa-e-ordenacao
 
7082 texto do artigo-33807-2-10-20180903
7082 texto do artigo-33807-2-10-201809037082 texto do artigo-33807-2-10-20180903
7082 texto do artigo-33807-2-10-20180903
 
00011
0001100011
00011
 

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.