PR1022804 2025 1 AULA12: mudanças entre as edições
Criou página com '=Operações com Arquivos= ;OBJETIVOS *O sistema de arquivos no Linux; *Tratamento de arquivos no C; *O acesso com funções de alto nível. ;INTRODUÇÃO :O sistema de arquivos é um "conjunto de estruturas lógicas" usado em todos os HDs, SSDs e chips de memória flash. Caso os componentes não tenham o sistema, os dados armazenados não poderão ser localizados e muito menos lidos em computadores e celulares com Windows, Linux, iOS ou Android. Na prática, um sis...' |
Sem resumo de edição |
||
Linha 1: | Linha 1: | ||
= | =Listas Encadeada= | ||
;OBJETIVOS | ;OBJETIVOS | ||
:O aluno deverá conhecer: | |||
* | |||
* | :*Listas encadeadas; | ||
:*Algumas aplicações. | |||
; | ;METODOLOGIA: A aula será expositiva e dialogada, utilizando apresentação de texto base na Internet, onde serão mostrados exemplos testados programas no microcomputador do laboratório de informática. | ||
: | ;INTRODUÇÃO: A Lista Encadeada nada mais é que uma representação de uma sequência de objetos, do mesmo tipo, na memória do computador. Cada elemento da sequência é armazenado em uma célula da lista: o primeiro elemento na primeira célula, o segundo na segunda e assim por diante. ''Linked list'' ou lista encadeada e um tipo de estrutura de dados que contém um grupo de nós (conjunto de dados) interligados através de ponteiros, onde o ponteiro dentro da estrutura aponta para o próximo nó até que o ponteiro seja '''NULL''' indicando assim o fim da lista. | ||
==Estrutura de uma lista encadeada== | |||
Uma lista encadeada (''linked list'') é uma sequência de células onde cada célula contém um objeto de algum tipo e o endereço da célula seguinte. | |||
Vamos supor que os objetos armazenados nas células são do tipo '''int'''. A estrutura de cada célula de uma determinada lista pode ser definida assim: | |||
<syntaxhighlight lang=c> | |||
struct cel { | |||
int conteudo; | |||
struct cel *prox; | |||
}; | |||
</syntaxhighlight> | |||
{| border="1" cellpadding="5" cellspacing="0" | |||
! style="background: #FAF0E6;" | 123 | |||
! style="background: #FAF0E6;" | --> | |||
|} | |||
;SENDO: | |||
:'''123''': conteudo | |||
:'''-->''': *prox | |||
É conveniente tratar as células como um novo '''tipo de dados''' (struct) e atribuir um nome a esse novo tipo: | |||
<syntaxhighlight lang=c> | |||
typedef struct cel celula; // célula | |||
</syntaxhighlight> | |||
Uma célula c e um ponteiro p para uma célula podem ser declarados assim: | |||
celula c; | |||
celula *p; | |||
Se '''c''' é uma célula então '''c.conteudo''' é o conteúdo da célula e '''c.prox''' é o endereço da próxima célula. Se '''p''' é o endereço de uma célula, então '''p->conteudo''' é o conteúdo da célula e '''p->prox''' é o endereço da próxima célula. Se '''p''' é o endereço da última célula da lista então: '''p->prox''' vale '''NULL'''. | |||
{| border="1" cellpadding=" | {| border="1" cellpadding="5" cellspacing="0" | ||
! style="background:# | ! style="background: #FAF0E6;" | 123 | ||
! style="background:# | ! style="background: #FAF0E6;" | --> | ||
! style="background:# | ! style="background: #FAF0E6;" | 234 | ||
! style="background: #FAF0E6;" | --> | |||
! style="background: #FAF0E6;" | 345 | |||
! style="background: #FAF0E6;" | --> | |||
! style="background: #FAF0E6;" | 456 | |||
! style="background: #FAF0E6;" | --> | |||
! style="background: #FAF0E6;" | 567 | |||
! style="background: #FAF0E6;" | --> | |||
! style="background: #FAF0E6;" | 678 | |||
! style="background: #FAF0E6;" | NULL | |||
|} | |} | ||
== | ==Listas com cabeça e sem cabeça== | ||
Uma lista encadeada pode ser organizada de duas maneiras diferentes. | |||
;LISTA COM CABEÇA: O conteúdo da primeira célula é irrelevante: ela serve apenas para marcar o início da lista. A primeira célula é a cabeça (= ''head cell'' = ''dummy cell'') da lista. Digamos que ini é o endereço da primeira célula. Então ini->prox == NULL se e somente se a lista está vazia. Para criar uma lista vazia, basta fazer: | |||
== | celula c, *ini; | ||
c.prox = NULL; | |||
ini = &c; | |||
ou, se preferir alocar a primeira célula dinamicamente, | |||
celula *ini; | |||
ini = malloc(sizeof (celula)); | |||
ini->prox = NULL; | |||
O | ;LISTA SEM CABEÇA: O conteúdo da primeira célula é tão relevante quanto o das demais. Nesse caso, a lista está vazia se o endereço de sua primeira célula é NULL. Para criar uma lista vazia basta fazer: | ||
celula *ini; | |||
ini = NULL; | |||
É preferível as listas sem cabeça porque são mais simples, porém, a vida do programador fica mais fácil quando as listas têm cabeça. | |||
;EXEMPLOS: Para imprimir o conteúdo de uma lista encadeada com cabeça: | |||
<syntaxhighlight lang=c> | |||
// Imprime o conteúdo de uma lista encadeada | |||
// com cabeça. O endereço da primeira célula é ini. | |||
== | void imprima(celula *ini) { | ||
celula *p; | |||
for (p = ini->prox; p != NULL; p = p->prox) | |||
printf( "%d\n", p->conteudo); | |||
} | |||
</syntaxhighlight> | |||
:Mesma função para lista sem cabeça: | |||
<syntaxhighlight lang=c> | |||
// Imprime o conteúdo de uma lista encadeada ini. | |||
// A lista não tem cabeça. | |||
void imprima(celula *ini) { | |||
celula *p; | |||
for (p = ini; p != NULL; p = p->prox) | |||
printf( "%d\n", p->conteudo); | |||
} | |||
</syntaxhighlight> | |||
;NOTE: Que o tipo de dados '''ini''' não inicializa no próximo (ini->prox) como no exemplo acima. | |||
== | ==Busca em uma lista encadeada== | ||
Veja como é fácil verificar se um inteiro x pertence a uma lista encadeada, ou seja, se é igual ao conteúdo de alguma célula da lista: | |||
<syntaxhighlight lang=c> | |||
// Esta função recebe um inteiro x e uma lista | |||
// encadeada ini de inteiros, com celula-cabeça. | |||
// A função devolve o endereço de uma celula que | |||
// contém x ou devolve NULL se tal celula não | |||
// existe. | |||
== | celula *busca( int x, celula *ini) | ||
{ | |||
celula *p; | |||
p = ini->prox; | |||
while (p != NULL && p->conteudo != x) | |||
p = p->prox; | |||
return p; | |||
} | |||
</syntaxhighlight> | |||
=Exercícios= | |||
Por vezes não se conhece o tamanho dos dados que se vai manipular e o uso de uma lista pode ser conveniente para | |||
armazená-los. Um sistema de estoque de produtos, por exemplo, poderia ser armazenado na forma de uma lista. | |||
;EXEMPLO: de lista ligada. | |||
<syntaxhighlight lang=c> | |||
#include <stdlib.h> | |||
#include <stdio.h> | |||
== | /*========================*/ | ||
/** OPERAÇÔES COM LISTA LIGADA ******/ | |||
/*========================*/ | |||
/* | |||
tipos e variáveis globais | |||
*/ | |||
struct TProduto{ | |||
; | int codigo; | ||
struct TProduto *next; | |||
} *head, *tail; | |||
* | /* | ||
adiciona item a cabeça da lista | |||
retorna 0 se tudo ok e -1 se erro | |||
*/ | |||
int add_nodo_head(int codigo) | |||
{ | |||
} | |||
/* | |||
adiciona item ao final lista | |||
retorna 0 se tudo ok e -1 se erro | |||
*/ | |||
int add_nodo_tail(int codigo) | |||
{ | { | ||
struct TProduto *p = malloc (sizeof(struct TProduto)); | |||
if (!p) | |||
return -1; | |||
p->codigo = codigo; | |||
p->next = NULL; | |||
if (tail==NULL) { | |||
/* lista vazia */ | |||
tail = head = p; | |||
}else { | |||
/*lista não vazia */ | |||
tail->next = p; | |||
tail = p; | |||
} | |||
return 0; | |||
} | } | ||
/* | |||
imprimir lista | |||
*/ | |||
* | void print_list(struct TProduto *ini) | ||
{ | |||
struct TProduto *p; | |||
for (p = ini->next; p != NULL; p = p->next) | |||
printf( "%d\n", p->codigo); | |||
} | |||
void main() | void main() | ||
{ | { | ||
int i; | |||
int i | |||
head = tail = NULL; | |||
for (i=0;i<5;i++) | |||
add_nodo_tail(i); | |||
print_list (head); | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
;EXERCÍCIO: | ;EXERCÍCIO 1: Para o exemplo anterior: | ||
* Implementar a função add_node_head() | |||
* Implementar a função print_list() | |||
* Implementar a função delete_node(int codigo) | |||
;EXERCÍCIO 2: Considere um sistema de estoque de uma livraria representado por uma tabela conforme abaixo. Elabore as funções para adicionar, remover e listar um livro na/da tabela. Considere que uma entrada livre possui o ponteiro titulo igual a NULL. | |||
<syntaxhighlight lang=c> | <syntaxhighlight lang=c> | ||
#include <stdio.h> | #include <stdio.h> | ||
#define TAM 10 | |||
struct tLivro { | |||
{ | char *titulo; | ||
char *autor; | |||
char *isbn; | |||
float *preco; | |||
int estoque; | |||
}; | |||
typedef struct tLivro TLivro; | |||
TLivro Livros[10]; /* iniciar a tabela com NULL */ | |||
TLivro *retornar_entrada_livre() | |||
{ | |||
} | |||
int adicionar_livro() | |||
{ | |||
char aux_isbn[20]; | |||
TLivro *p; | |||
/* Ler ISBN */ | |||
if(verificar_livro_existe(aux_isbn)==1) | |||
return 0; | |||
if((p=retornar_entrada_livre())==NULL) | |||
return -1; | |||
/* Ler os dados do livro pelo teclado e colocar na estrutura | |||
apontada por p*/ | |||
} | } | ||
{ | /* retorna 0 se removido com sucesso e -1 caso contrário */ | ||
int remover_livro(char *isbn) | |||
{ | |||
} | |||
void imprimir_dados_livro(char *isbn) | |||
{ | |||
} | |||
main() | |||
{ | { | ||
/* testar as funções aqui */ | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
;EXERCÍCIO 3: Refazer o exercício anterior usando filas. | |||
; | ;EXERCÍCIO 4: Seja a seguinte estrutura: | ||
<syntaxhighlight lang=c> | <syntaxhighlight lang=c> | ||
struct tipo_carro { | |||
char *marca; | |||
char *modelo; | |||
int potencia; | |||
{ | }; | ||
int | |||
typedef tipo_carro tcarro; | |||
</syntaxhighlight> | </syntaxhighlight> | ||
:Implementar as funções abaixo: | |||
<syntaxhighlight lang=c> | <syntaxhighlight lang=c> | ||
/* cria dinamicamente uma estrutura, | |||
preenche os dados dos campos | |||
e retorna um ponteiro para a estrutura criada | |||
Retorna NULL caso não consiga alocar área | |||
*/ | |||
void tcarro *ler_carro() | |||
{ | |||
} | |||
/* | |||
recebe dois ponteiros para estruturas do tipo carro e | |||
retorna -1 caso pelo menos um dos ponteiros seja NULL, | |||
retorna 0 se os modelos forem iguais | |||
e retorna 1 se os modelos forem diferentes */ | |||
int compara_modelo(tcarro *p1, tcarro *p2) | |||
{ | { | ||
} | } | ||
/* libera a área da estrutura passada como parâmetro */ | |||
void deleta_estrutura(tcarro *p) | |||
* | { | ||
* | |||
} | |||
void main() | void main() | ||
{ | { | ||
/*testar as funções aqui */ | |||
/* criar dois carros */ | |||
/* comparar o modelo dos dois carros. Testar o retorno */ | |||
/* liberar a área das estruturas */ | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
==EXEMPLO DA AULA== | |||
<syntaxhighlight lang=c> | <syntaxhighlight lang=c> | ||
#include <stdlib.h> | |||
#include <stdio.h> | #include <stdio.h> | ||
#include <string.h> | |||
int | struct TFicha { | ||
int codigo; | |||
char nome[40]; | |||
char fone[20]; | |||
struct TFicha *prox; | |||
} *cliente,*cabeca; | |||
void | void Cadastrar(){ | ||
{ | struct TFicha *p = malloc (sizeof(struct TFicha)); | ||
printf("\nDigite codigo: "); | |||
scanf("%d",&p->codigo); | |||
printf("\nDigite Nome: "); | |||
fflush(stdin); | |||
scanf("%[^\n]",p->nome); | |||
printf("\nDigite Telefone: "); | |||
fflush(stdin); | |||
scanf("%[^\n]",p->fone); | |||
if (cliente==NULL) { | |||
/* lista vazia */ | |||
cliente = cabeca = p; | |||
}else { | |||
/*lista não vazia */ | |||
cliente->prox = p; | |||
cliente = p; | |||
} | |||
} | } | ||
void Imprimir(struct TFicha *ini) { | |||
struct TFicha *p; | |||
printf("\n\nCodigo Nome Fone"); | |||
for (p = ini; p != NULL; p = p->prox){ | |||
printf( "\n%-d", p->codigo); | |||
struct | printf( "\t%-20s", p->nome); | ||
printf( "\t%-20s", p->fone); | |||
} | |||
{ | |||
printf(" | |||
} | } | ||
void main(){ | |||
cliente=NULL; | |||
int opcao; | |||
while (1){ | |||
printf("\n\nEscolha:\n"); | |||
printf("1 - Cadastrar\n"); | |||
{ | printf("2 - Imprimir\n"); | ||
printf("3 - Sair\n"); | |||
printf("-> "); | |||
scanf("%d",&opcao); | |||
switch (opcao) | |||
{ | |||
case 1: | |||
Cadastrar(cliente); | |||
break; | |||
case 2: | |||
Imprimir(cabeca); | |||
break; | |||
case 3: | |||
return 0; | |||
} | |||
} | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Linha 580: | Linha 413: | ||
=Referências= | =Referências= | ||
[1] | [1] http://www.ime.usp.br/~pf/algoritmos/aulas/lista.html | ||
Edição atual tal como às 18h49min de 3 de julho de 2025
1 Listas Encadeada
- OBJETIVOS
- O aluno deverá conhecer:
- Listas encadeadas;
- Algumas aplicações.
- METODOLOGIA
- A aula será expositiva e dialogada, utilizando apresentação de texto base na Internet, onde serão mostrados exemplos testados programas no microcomputador do laboratório de informática.
- INTRODUÇÃO
- A Lista Encadeada nada mais é que uma representação de uma sequência de objetos, do mesmo tipo, na memória do computador. Cada elemento da sequência é armazenado em uma célula da lista: o primeiro elemento na primeira célula, o segundo na segunda e assim por diante. Linked list ou lista encadeada e um tipo de estrutura de dados que contém um grupo de nós (conjunto de dados) interligados através de ponteiros, onde o ponteiro dentro da estrutura aponta para o próximo nó até que o ponteiro seja NULL indicando assim o fim da lista.
1.1 Estrutura de uma lista encadeada
Uma lista encadeada (linked list) é uma sequência de células onde cada célula contém um objeto de algum tipo e o endereço da célula seguinte.
Vamos supor que os objetos armazenados nas células são do tipo int. A estrutura de cada célula de uma determinada lista pode ser definida assim:
struct cel {
int conteudo;
struct cel *prox;
};
123 | --> |
---|
- SENDO
- 123: conteudo
- -->: *prox
É conveniente tratar as células como um novo tipo de dados (struct) e atribuir um nome a esse novo tipo:
typedef struct cel celula; // célula
Uma célula c e um ponteiro p para uma célula podem ser declarados assim:
celula c; celula *p;
Se c é uma célula então c.conteudo é o conteúdo da célula e c.prox é o endereço da próxima célula. Se p é o endereço de uma célula, então p->conteudo é o conteúdo da célula e p->prox é o endereço da próxima célula. Se p é o endereço da última célula da lista então: p->prox vale NULL.
123 | --> | 234 | --> | 345 | --> | 456 | --> | 567 | --> | 678 | NULL |
---|
1.2 Listas com cabeça e sem cabeça
Uma lista encadeada pode ser organizada de duas maneiras diferentes.
- LISTA COM CABEÇA
- O conteúdo da primeira célula é irrelevante: ela serve apenas para marcar o início da lista. A primeira célula é a cabeça (= head cell = dummy cell) da lista. Digamos que ini é o endereço da primeira célula. Então ini->prox == NULL se e somente se a lista está vazia. Para criar uma lista vazia, basta fazer:
celula c, *ini; c.prox = NULL; ini = &c;
ou, se preferir alocar a primeira célula dinamicamente,
celula *ini; ini = malloc(sizeof (celula)); ini->prox = NULL;
- LISTA SEM CABEÇA
- O conteúdo da primeira célula é tão relevante quanto o das demais. Nesse caso, a lista está vazia se o endereço de sua primeira célula é NULL. Para criar uma lista vazia basta fazer:
celula *ini; ini = NULL;
É preferível as listas sem cabeça porque são mais simples, porém, a vida do programador fica mais fácil quando as listas têm cabeça.
- EXEMPLOS
- Para imprimir o conteúdo de uma lista encadeada com cabeça:
// Imprime o conteúdo de uma lista encadeada
// com cabeça. O endereço da primeira célula é ini.
void imprima(celula *ini) {
celula *p;
for (p = ini->prox; p != NULL; p = p->prox)
printf( "%d\n", p->conteudo);
}
- Mesma função para lista sem cabeça:
// Imprime o conteúdo de uma lista encadeada ini.
// A lista não tem cabeça.
void imprima(celula *ini) {
celula *p;
for (p = ini; p != NULL; p = p->prox)
printf( "%d\n", p->conteudo);
}
- NOTE
- Que o tipo de dados ini não inicializa no próximo (ini->prox) como no exemplo acima.
1.3 Busca em uma lista encadeada
Veja como é fácil verificar se um inteiro x pertence a uma lista encadeada, ou seja, se é igual ao conteúdo de alguma célula da lista:
// Esta função recebe um inteiro x e uma lista
// encadeada ini de inteiros, com celula-cabeça.
// A função devolve o endereço de uma celula que
// contém x ou devolve NULL se tal celula não
// existe.
celula *busca( int x, celula *ini)
{
celula *p;
p = ini->prox;
while (p != NULL && p->conteudo != x)
p = p->prox;
return p;
}
2 Exercícios
Por vezes não se conhece o tamanho dos dados que se vai manipular e o uso de uma lista pode ser conveniente para armazená-los. Um sistema de estoque de produtos, por exemplo, poderia ser armazenado na forma de uma lista.
- EXEMPLO
- de lista ligada.
#include <stdlib.h>
#include <stdio.h>
/*========================*/
/** OPERAÇÔES COM LISTA LIGADA ******/
/*========================*/
/*
tipos e variáveis globais
*/
struct TProduto{
int codigo;
struct TProduto *next;
} *head, *tail;
/*
adiciona item a cabeça da lista
retorna 0 se tudo ok e -1 se erro
*/
int add_nodo_head(int codigo)
{
}
/*
adiciona item ao final lista
retorna 0 se tudo ok e -1 se erro
*/
int add_nodo_tail(int codigo)
{
struct TProduto *p = malloc (sizeof(struct TProduto));
if (!p)
return -1;
p->codigo = codigo;
p->next = NULL;
if (tail==NULL) {
/* lista vazia */
tail = head = p;
}else {
/*lista não vazia */
tail->next = p;
tail = p;
}
return 0;
}
/*
imprimir lista
*/
void print_list(struct TProduto *ini)
{
struct TProduto *p;
for (p = ini->next; p != NULL; p = p->next)
printf( "%d\n", p->codigo);
}
void main()
{
int i;
head = tail = NULL;
for (i=0;i<5;i++)
add_nodo_tail(i);
print_list (head);
}
- EXERCÍCIO 1
- Para o exemplo anterior:
- Implementar a função add_node_head()
- Implementar a função print_list()
- Implementar a função delete_node(int codigo)
- EXERCÍCIO 2
- Considere um sistema de estoque de uma livraria representado por uma tabela conforme abaixo. Elabore as funções para adicionar, remover e listar um livro na/da tabela. Considere que uma entrada livre possui o ponteiro titulo igual a NULL.
#include <stdio.h>
#define TAM 10
struct tLivro {
char *titulo;
char *autor;
char *isbn;
float *preco;
int estoque;
};
typedef struct tLivro TLivro;
TLivro Livros[10]; /* iniciar a tabela com NULL */
TLivro *retornar_entrada_livre()
{
}
int adicionar_livro()
{
char aux_isbn[20];
TLivro *p;
/* Ler ISBN */
if(verificar_livro_existe(aux_isbn)==1)
return 0;
if((p=retornar_entrada_livre())==NULL)
return -1;
/* Ler os dados do livro pelo teclado e colocar na estrutura
apontada por p*/
}
/* retorna 0 se removido com sucesso e -1 caso contrário */
int remover_livro(char *isbn)
{
}
void imprimir_dados_livro(char *isbn)
{
}
main()
{
/* testar as funções aqui */
}
- EXERCÍCIO 3
- Refazer o exercício anterior usando filas.
- EXERCÍCIO 4
- Seja a seguinte estrutura:
struct tipo_carro {
char *marca;
char *modelo;
int potencia;
};
typedef tipo_carro tcarro;
- Implementar as funções abaixo:
/* cria dinamicamente uma estrutura,
preenche os dados dos campos
e retorna um ponteiro para a estrutura criada
Retorna NULL caso não consiga alocar área
*/
void tcarro *ler_carro()
{
}
/*
recebe dois ponteiros para estruturas do tipo carro e
retorna -1 caso pelo menos um dos ponteiros seja NULL,
retorna 0 se os modelos forem iguais
e retorna 1 se os modelos forem diferentes */
int compara_modelo(tcarro *p1, tcarro *p2)
{
}
/* libera a área da estrutura passada como parâmetro */
void deleta_estrutura(tcarro *p)
{
}
void main()
{
/*testar as funções aqui */
/* criar dois carros */
/* comparar o modelo dos dois carros. Testar o retorno */
/* liberar a área das estruturas */
}
2.1 EXEMPLO DA AULA
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct TFicha {
int codigo;
char nome[40];
char fone[20];
struct TFicha *prox;
} *cliente,*cabeca;
void Cadastrar(){
struct TFicha *p = malloc (sizeof(struct TFicha));
printf("\nDigite codigo: ");
scanf("%d",&p->codigo);
printf("\nDigite Nome: ");
fflush(stdin);
scanf("%[^\n]",p->nome);
printf("\nDigite Telefone: ");
fflush(stdin);
scanf("%[^\n]",p->fone);
if (cliente==NULL) {
/* lista vazia */
cliente = cabeca = p;
}else {
/*lista não vazia */
cliente->prox = p;
cliente = p;
}
}
void Imprimir(struct TFicha *ini) {
struct TFicha *p;
printf("\n\nCodigo Nome Fone");
for (p = ini; p != NULL; p = p->prox){
printf( "\n%-d", p->codigo);
printf( "\t%-20s", p->nome);
printf( "\t%-20s", p->fone);
}
}
void main(){
cliente=NULL;
int opcao;
while (1){
printf("\n\nEscolha:\n");
printf("1 - Cadastrar\n");
printf("2 - Imprimir\n");
printf("3 - Sair\n");
printf("-> ");
scanf("%d",&opcao);
switch (opcao)
{
case 1:
Cadastrar(cliente);
break;
case 2:
Imprimir(cabeca);
break;
case 3:
return 0;
}
}
}
3 Referências
[1] http://www.ime.usp.br/~pf/algoritmos/aulas/lista.html