Prof. Cristiano Biancardi
Estruturas de Dados em C
Sumário
1. Tipos de Dados
1.1. Tipos Primitivos
1.2. Construção de Tipos (Estruturados)
2. Vetores e Matrizes
2.1. Conceitos Básicos
3. Listas Lineares
3.1. Listas Genéricas
3.2. Listas com disciplinas de Acesso (PILHA, FILA e DEQUE)
3.3. Representação por Contigüidade Física
3.4. Representação por Encadeamento
4. Árvores
5.1. Conceitos Básicos
5.2. Árvores Binárias de Pesquisa
5.3. Operações Básica
5. Pesquisa e Classificação de Dados
5.1. Pesquisa Seqüencial
5.2. Pesquisa Binária
5.3. Cálculo de Endereço
5.4. Classificaçao por Inserção
5.5. Classificação por Troca
5.6. Classificação por Seleção
1. Tipos de Dados
1.1 Conceitos Básicos
Estruturas de Dados
Estuda as principais técnicas de representação e manipulação de dados na memória
principal (Memória de Acesso Randômico, RAM – Random Access Memory).
Organização de Arquivos
Estuda as principais técnicas de representação e manipulação de dados na memória
secundária (DISCO).
Conceito
Realidade
Dados
abstração
Mundo Real
Memória do Computador
Dados
São as informações a serem representadas, armazenadas ou manipuladas.
Tipos de Dados
É o conjunto de valores que uma constante, ou variável, ou expressão pode assumir,
ou então um conjunto de valores que possam ser gerados por uma função.
Os tipos de dados podem ser: Primitivos ou Estruturados, sendo que os
estruturados, são chamados de Complexos.
Um Tipo de Dado Abstrato é um dado não reconhecido pelo processador e por isso
tendo que ser implementado pelo programador. Uma implementação de um TAD é uma
descrição de um modelo matemático e das operações daquele TAD utilizando os
mecanismo (declarações e comandos) de uma linguagem de programação.
Um TAD
é uma estrutura de dados não implementada, em conjunto com uma lista de funções de
acesso a essa estrutura de dados.
A noção de tipos de dados ocorre na maioria das linguagens de programação
tradicionais. Na declaração do tipo de uma variável, delimita-se o conjunto de valores que
ela pode assumir e as operações que ela pode sofrer. A especificação de um tipo de dados
deve definir os objetos constituintes do tipo e as operações aplicáveis a estes objetos. Além
disso, é possível estabelecer uma maneira de representação para os objetos.
Geralmente, uma linguagem de programação provê alguns tipos básicos
pré-definidos (tipos primitivos) e ainda oferece mecanismos para definição de novos tipos de
dados renomeando tipos existentes ou agregando alguns tipos primitivos e/ou definidos
pelo usuário. Existem linguagens que além de proporcionarem tipos de dados primitivos e
tipos de dados definidos pelo usuário, incorporam o conceito de tipos abstratos de dados.
Tipos abstratos de dados envolvem a disponibilidade de dados e operações
(comportamento) sobre estes dados em uma única unidade.
A abstração de dados é utilizada para introduzir um novo tipo de dados, que é
considerado útil no domínio do problema a ser resolvido. Os usuários do tipo abstrato de
dados preocupam-se apenas com o comportamento do tipo, demonstrado em termos de
operações significativas para tais, não necessitando conhecer como eles estão representados
ou como as operações são realizadas neles (ocultamento de informação). Portanto, uma
abstração de dados consiste de um conjunto de valores e de operações que completamente
caracterizam o comportamento.
Mais precisamente, um tipo abstrato de dados pode ser definido como um tipo de
dados que satisfaz as seguintes condições:
A representação e definição do tipo e as operações nos objetos do tipo são
descritos em uma única unidade sintátca;
A representação (implementação) dos objetos do tipo é escondida das unidades de
programa que utilizam o tipo; portanto, as únicas operações possíveis em tais
objetos são aquelas que fazem parte da definição (interface) do tipo.
O estilo de programação com tipos abstratos de dados inclui o princípio de
encapsulamento, que proporciona ocultamento e proteção de informação, viabilizando a
manutenção e facilitando a evolução de sistemas. Com o encapsulamento da estrutura de
dados que representa os objetos e dos procedimentos que representam as possíveis
operações sobre os objetos, tem-se que uma alteração na estrutura de dados provavelmente
exigirá modificações nos procedimentos, porém o efeito dessas modificações fica restrito às
fronteiras da unidade sintática que descreve o tipo. Se a interface permanecer a mesma, as
unidades de programa que utilizam o tipo não necessitam sofrer alterações.
1.2 Tipos Primitivos
São os tipos de dados que, além de depender das características do sistema,
dependem do processador e do co-processador.
CARACTER ( char ch; )
INTEIRO ( int i; )
REAL ( float f; ou double d;)
Tipo Bytes Bits Faixa de valores
char 1 8 -128 à 127
Int 2 16 -32768 à 32767
float 4 32 -3.4E-38 à 3.4E+38
double 8 64 -1.7E-308 à 1.7E+308
void 0 0 Sem valor
1.3 Construção de tipos (Estruturados ou Complexos)
Tipos obtidos através de tipos primitivos, podem ser:
STRING (Cadeia de Caracteres) ( char *s; ou char s[11]; )
VETOR (Agregados Homogêneos) ( int v[10]; )
ESTRUTURA (Agregados Heterogêneos) ( struct )
PONTEIRO (Apontadores) ( int *p; )
1.3.1 String (Cadeia de Caracteres)
Tipo de dado que permite que uma variável possua vários caracteres.
Exemplo:
char nome[30]=”UCPel”; ou char *s=”UCPel\n”;
1.3.2 Vetor (Agregados Homogêneos)
Tipo de dado que permite que uma variável possua vários elementos, todos do
mesmo tipo.
Exemplo:
#define MAX 10
float vetor[MAX]; ... vetor[0] até vetor[9]
1.3.3 Struct (Estrutura)
Tipo de dado que permite que uma variável possua vários campos. Os campos
podem ser de tipos de dados distintos.
#define MAX 50
struct ALUNO {
int matricula;
char nome[30];
char endereco[40];
}
struct ALUNO turma[MAX];
typedef struct {
int matricula;
char nome[30];
char endereco[40];
} ALUNO;
struct DATA {
int dia;
int mes;
int ano;
} data;
Acesso aos elementos: data.dia, data.mes ou data.ano
struct TEMPO {
int horas;
int minutos;
int segundos;
} *tempo;
Acesso aos elementos
tempohoras, tempominutos ou temposegundos
ou
(*tempo).horas, (*tempo).minutos ou (*tempo).segundos
Exemplo: #include <stdio.h> struct Name{ char * first; char midinit; char *last; };
void main(void) {
struct Name regNome; regNome.first = "Cristiano"; regNome.midinit='M'; regNome.last = "Biancardi";
printf("Nome Completo :%s %s - Sexo: %c", regNome.first, regNome.last, regNome.midinit); }
Definindo uma estrutura como um tipo
typedef struct {
char first[10]; char midinit; char last[20]; }Name;
Onde typedef é usado para indicar a especificação de um tipo criado pelo usuário. Exemplo 2: #include <stdio.h> typedef struct { char *first; char midinit; char *last; }Name; void main(void) { Name regNome; clrscr(); regNome.first = "Roscleyton"; regNome.midinit='M'; regNome.last = "Junior";
printf(”Nome Completo : %s %c %s”, regNome.first, regNome.midinit, regNome.last); }
Exemplo Completo:
#include <stdio.h> #include <string.h> typedef struct { int codigo; char nome[30]; int idade; char sexo[1];}Registro; void main(void) { Registro Aluno[2]; int i; for(i=0;i<2;i++) {
printf("Digite o codigo do aluno\n"); scanf("%d", &Aluno[i].codigo); printf("Digite o nome do aluno\n"); scanf("%s", Aluno[i].nome); printf("Digite a idade do aluno\n"); scanf("%d", &Aluno[i].idade); printf("Digite o sexo do aluno\n"); scanf("%s", Aluno[i].sexo); } for(i=0;i<2;i++) { printf("Codigo : %d ", Aluno[i].codigo); printf("Nome : %s ", Aluno[i].nome); printf("Idade : %d ", Aluno[i].idade); printf("Sexo : %s \n", Aluno[i].sexo); } }
Struct como membro de um Struct struct nametype { char first[10]; char midinit; char last[20]; }; struct addrtype { char straddr[40]; char city[10]; char state[2]; char zip[5]; }; struct mnadtype {
struct nametype name; struct addrtype address; };
Exemplo:
struct mnatype d1, d2; Comandos válidos:
d1.name.midinit = d2.name.midinit; for (i = 1; i < 10; i++) d1.name.first[i] = d2.name.first[i]; Exemplo Completo: #include <stdio.h> struct nametype{ char first[10]; char midinit; char last[20]; int a; }; struct addrtype { char straddr[40]; char city[10]; char state[2]; char zip[5]; }; struct mnadtype {
struct nametype name; struct addrtype address; }; int main() { struct mnadtype d1, d2; int i; d1.name.midinit = d2.name.midinit; for (i = 1; i < 10; i++) d1.name.first[i] = d2.name.first[i]; return 0; }
1.3.4 Ponteiros (Apontadores)
É um tipo de dado, onde a variável contém o endereço de outra variável, ou um
endereço de memória. Permite ainda, alocação dinâmica de Memória, ou seja, alocação de
memória em tempo de execução do programa.
int *p;
Exemplos:
#include <stdio.h> #include <conio.h> void main(void) { int *p; int n; clrscr(); n = 65; p = &n; printf(“Conteúdo: %p\n”,*p); getch(); }&n ... Endereço da variável “n” na memória principal (RAM), sendo que o endereço é
formado de Segmento:OffSet (segmento e deslocamento).
#include <stdio.h> #include <conio.h> #include <alloc.h> #include <stdlib.h> void main(void) { int *p; int i,n; clrscr(); printf("Quantos valores: "); scanf("%d",&n); p = (int *) malloc(sizeof(int)*n); if (p == NULL)
printf("ERRO FATAL: Falta de Memória"); else
{
for (i = 0;i < n;i++) p[i] = i;
for (i = 0;i < n;i++)
printf("Conteúdo: %d\n",p[i]); free(p);
} getch();
} Exemplo: #include <stdio.h> #include <conio.h> #include <alloc.h> #include <stdlib.h> void main(void) { int *p; int i,n; clrscr(); printf("Quantos valores: "); scanf("%d",&n); p = (int *) malloc(sizeof(int)*n); if (p == NULL)
printf("ERRO FATAL: Falta de Memória"); else
{
for (i = 1;i <= n;i++) {
*p = i; p++; }
for (i = 1;i <= n;i++) { p--; printf("Conteúdo: %d\n",*p); } free(p); } getch(); }
Ponteiros para struct
struct nametype *name; int i;
printf(“\n”);
for(i=0; (i<10) && (name->first[i]) != ´\0´); i++) { printf(“%c”, nmae->first[i]); } Exemplo Completo: #include <stdio.h> typedef struct { char *first;
char todo[10]; char midinit; char last[20]; int a; }Nam; int main() { Nam *na; na = malloc(sizeof(Nam)); na->a = 10; na->first = "MASSARA"; na->todo[0] = 'c'; printf("%s", na->first); scanf("%s", na->todo); return 0; }
Exercícios:
1. Definir uma estrutura para armazenar as seguintes informação de uma funcionário : CFC,Nome,Idade,Sexo,Estado Civil,Numero de filhos e Salário.
2. Dada a estrutura abaixo fazer uma função ( uma função não é um programa ), que armazene dados em um vetor do tipo Registro com 10 posições onde não possa ter código repetido. typedef struct { int codigo; char nome[25]; int idade; char sexo; }Registro;
3. Fazer um programa em C que inclua,altere e consulte dados na estrutura abaixo. typedef struct { int dia; int mes; int ano; }Data; typedef struct { int codigo; char nome[25]; Data dtNasc; char sexo; }Registro;
4. Dado o vetor abaixo responda as questões : Registro
Nome R O S C L E I T O N
Idade 25
Sexo M
a) Qual é o nome desta Estrutura ?
R:___________________________________________________________.
b) Quantos e quais são os membros desta estrutura ?
R:___________________________________________________________. c) Qual é o valor do membro “sexo” ?
R:___________________________________________________________.
5. Faça um programa em C que armazene em uma estrutura as seguintes informações de 10 pessoas: Nome,Endereço,Cidade,Estado e apresente na tela todas as pessoas que residem no estado SP.
Definições
malloc(p) ... Aloca dinamicamente memória para o ponteiro "p"
free(p) ... Desaloca memória ocupada pela variável "p"
NULL ... Palavra reservada para ponteiro NULO
p ... Endereço da memória RAM
*p ... Conteúdo do ponteiro
&p ... Endereço do ponteiro
Funções de Alocação Dinâmicas em CPonteiros fornecem o suporte necessário para o poderoso sistema de alocação
dinâmica de C. Alocação dinâmica é o meio pelo qual um programa pode obter memória
enquanto está em execução. O coração do sistema de alocação dinâmica de C consiste nas
funções malloc() e free(). Na verdade, C tem diversas outras funções de alocação dinâmica,
mas essas duas são as mais importantes.
int *p;
p = (int *) malloc(sizeof(int));
if(p==NULL)
printf( “memória insuficiente”);
else
free(p); // libera o espaço alocado na memória
Neste exemplo está sendo alocada uma área de memória suficiente para armazenar um
inteiro. Caso não seja possível alocar a memória, será retornado NULL, caso contrário será
retornado o endereço de memória da área alocada. Repare que está sendo feito um casting
para (int *), pois o malloc retorna por default (char *).
Quando não se está mais usando uma área de memória, é necessário que esta seja liberada
para ser usada por outros programas. Para fazer isso, usamos a função free. Caso o endereço
seja NULL, dará um erro em tempo de execução, e seu programa irá terminar a sua
execução.
Comparação de Ponteiros
É possível comparar ponteiros em uma expressão relacional. Só é possível comparar
ponteiros de mesmo tipo. O trecho de programa abaixo ilustra um exemplo deste tipo de
operações.
char *c, *v;
scanf("%c %c", c, v);
if (c == v)
printf("As variáveis estao na mesma posicao.\n");
else
printf("As variaveis nao estao na mesma posicao.\n");
Incrementando e Decrementando Ponteiros
O exemplo abaixo mostra que operações de incremento e decremento podem ser aplicadas
em operandos. O primeiro printf imprime 30 o segundo 40 e o terceiro 50.
void main(void)
{
int vetor[] = { 10, 20, 30, 40, 50 };
int *p1;
p1 = &vetor[2];
printf("%d\n", *p1);
p1++;
printf("%d\n", *p1);
p1 = p1 + 1;
printf("%d\n", *p1);
}
Pode parecer estranho que um endereço que aponte para um número inteiro que é
armazenado em dois bytes seja incrementado por um e passe para apontar para o próximo
número inteiro. A resposta para isto é que sempre que um ponteiro é incrementado
(decrementado) ele passa a apontar para a posição do elemento seguinte (anterior). Do
mesmo modo somar três a um ponteiro faz com que ele passe apontar para o terceiro
elemento após o atual. Portanto, um incremento em um ponteiro que aponta para um valor
que é armazenado em
nbytes faz que
nseja somado ao endereço.
É possível se usar o seguinte comando:
*(p+1)=10;
Este comando armazena o valor 10 na posição seguinte àquela apontada por
p. É possível
somar-se e subtrair-se inteiros de ponteiros. A operação abaixo faz com que o ponteiro p
passe a apontar para o terceiro elemento após o atual.
p = p + 3;
A diferença entre ponteiros fornece quantos elementos do tipo do ponteiro existem entre os
dois ponteiros. No exemplo abaixo é impresso o valor 3.
void main(void)
{
float vetor[] = { 1.0, 2.0, 3.0, 4.0, 5.0 };
float *p1, *p2;
p1 = &vetor[2]; /* endereco do terceiro elemento */
p2 = &vetor; /* endereco do primeiro elemento */
printf("Diferenca entre ponteiros %d\n", p1-p2);
}
Não é possível multiplicar ou dividir ponteiros, e não se pode adicionar ou subtrair o tipo
floatou o tipo
doublea ponteiros.
Exercícios:
1. Fazer uma função que recebe como parâmetro uma variável e retorne o endereço de
memória da mesma.
2. Fazer um programa em C que apresente na tela o endereço de memória de uma
estrutura.
3. Fazer um programa em C que aloque espaço de memória para uma estrutura e teste
se tem memória suficiente.
4. Dado o programa abaixo considerando a Tabela de endereçamento responda as
questões :
void main(void){
int *P;
int X,Y;
X = 5;
P = &X;
Y = *P;
Y = Y + 10;
}
Memória
01F 02F 03F 04F 05F 06F 07F 08F
09F 10F 11F 12F 13F 14F 15F 16F
Tabela de endereçamento
P
01F
X
02F
Y
03F
a) Qual será o valor de P após a execução de Main()?
R:_____________________________________________________________________
.
b) Qual será o valor de Y após a execução de Main()?
R:_____________________________________________________________________
.
5. Faça um programa em C que utilize 3 variáveis do tipo int, 3 variáveis do tipo char e
três variáveis do tipo float. Faça com que o usuário digite valores para estas
variáveis, depois disto apresente na tela em forma de tabela o nome da variável o
endereço de memória e o seu valor.
1.4 Operadores(Aritméticos, Relacionais e Lógicos)
1.4.1 Aritméticos
+
Adição
-
Subtração
*
Multiplicação
/
Divisão
%
Resto Inteiro da Divisão
++
Incremento
--
Decremento
1.4.2 Relacionais
>
Maior
<
Menor
>=
Maior ou Igual
<=
Menor ou Igual
==
Igual
!=
Diferente
1.4.3 Lógicos
&&
e
||
ou
!
não
2. Vetores e Matrizes
Permitem armazenamento de vários dados na memória RAM ao mesmo instante de
tempo e com contigüidade física, ou seja, uma variável com possui vários elementos,
igualmente distanciados, ou seja, um ao lado do outro.
Vetor: (É uma matriz unidimensional)
#define MAX 7
Matriz: (Possui mais de uma dimensão)
#define M 3
#define N 4
float matriz[M][N];
Índice: Constante númerica inteira que referencia cada elemento
Exemplos:
Dada a definição acima:
vetor[0]... primeiro elemento
vetor[MAX-1]... último elemento
m[0][0]... primeiro elemento
m[M-1][N-1]... último elemento
Entrada de um Vetor
Entrada de uma Matriz Bidimensional
for (i = 0;i < MAX;i++)
for (i = 0;i < M;i++)
scanf(“%d”, &vetor[i]);
for (j = 0;j < N;j++)
scanf(“%f”, &matriz[i][j]);
Exercícios
1) Escreva um programa em C que lê uma matriz A (6x6) e cria 2 vetores SL e SC de 6
elementos que contenham respectivamente a soma das linhas (SL) e a soma das colunas
(SC). Imprimir os vetores SL e SC.
2) Escreva um programa em C que lê uma matriz A (12x13) e divide todos os elementos de
cada uma das 12 linhas de A pelo valor do maior elemento daquela linha. Imprimir a matriz
A modificada.
Observação: Considere que a matriz armazena apenas elementos inteiros
3) Escreva um programa em C que insere números inteiros (máximo 10 elementos) em um
vetor mantendo-o ordenado. Quando o usuário digitar um ZERO o programa deve imprimir
na tela o vetor ordenado.
Operações sobre os Dados
Criação dos Dados
Manutenção dos Dados
Inserção de um Componente
Remoção de um Componente
Alteração de um Componente
Consulta aos Dados
Destruição dos Dados
Pesquisa e Classificação
Alocação de Memória
(RAM - Random Access Memory)
Alocação Estática de Memória
É a forma mais simples de alocação, na qual cada dado tem sua área reservada, não
variando em tamanho ou localização ao longo da execução do programa.
float f;
/* a variável “f” ocupa 4 bytes durante toda a execução do programa */
Alocação Dinâmica de Memória
Nesta forma de alocação, são feitas requisições e liberações de porções da memória
ao longo da execução do programa. Para isto, são usadas variáveis do tipo Ponteiro.
int *p;
/* a variável “p” poderá ocupar “n” bytes a qualquer momento */
Célula, Nodo ou Nó
Espaço reservado (alocado) na memória RAM para uma variável (tipo primitivo ou
complexo), ou seja, número de bytes “gastos” para o armazenamento de um dado.
Campo
É uma subdivisão de uma célula, ou seja, cada elemento de uma estrutura (struct).
No exemplo abaixo, “tempo” é uma célula e “horas, minutos e segundos” são os campos.
struct TEMPO {
int horas;
int minutos;
int segundos;
} *tempo;
3. Listas Lineares
3.1 Listas Genéricas
Conceito
Conjunto de dados que mantém a relação de ordem Linear entre os componentes. É
composta de elementos (componentes ou nós), os quais podem conter um dado primitivo ou
estruturado.
Lista Linear
É uma estrutura que permite representar um conjunto de dados de forma a preservar
a relação de ordem entre eles.
Uma lista linear X é um conjunto de nodos (nós) X1, X2, ... Xn, Tais que:
1) Existem “n” nodos na lista (n >= 0)
2) X1 é o primeiro nodo da lista
3) Xn é o último nodo da lista
4) Para todo i,j entre 1 e n, se i<j, então o elemento Xi antecede o elemento Xj
5) Caso i = j-1, Xi é o antecessor de Xj e Xj é o sucessor de Xi
Observação: Quando n=0, dizemos que a Lista é Vazia
Exemplos de Listas
Lista de clientes de um Banco
Lista de Chamada
Operações sobre Listas
1) Percurso
Permite utilizar cada um dos elementos de uma lista, de tal forma que:
0 primeiro nodo utilizado é o primeiro da lista;
Para utilizar o nodo Xj, todos os nodos de X1 até X(j-1) já foram utilizados;
último nodo utilizado é o último nodo da lista.
2) Busca
Procura um nodo específico da lista linear, de tal forma que:
nodo é identificado por sua posição na lista;
nodo é identificado pelo seu conteúdo.
3) Inserção
Acrescenta um nodo X a uma lista linear, de tal forma que:
nodo X terá um sucessor e/ou um antecessor;
Após inserir o nodo X na posição i (i >= 1 e i <= n+1), ele passará a ser i-ésimo nodo da
lista;
número de elementos (n) é acrescido de uma unidade.
X1
X2
X4
X3
. . .
Xn
4) Retirada (Exclusão)
Retira um nodo X da lista, de tal forma que:
Se Xi é o elemento retirado, o seu sucessor passa a ser o sucessor de seu antecessor.
X(i+1) passa a ser o sucessor de X(i-1). Se Xi é o primeiro nodo, o seu sucessor passa a
ser o primeiro, se Xi é o último, o seu antecessor passa a ser o último;
Operações Válidas sobre Listas
Acessar um elemento qualquer da lista;
Inserir um novo elemento à lista;
Concatenar duas listas;
Determinar o número de elementos da lista;
Localizar um elemento da lista com um determinado valor;
Excluir um elemento da lista;
Alterar um elemento da lista;
Criar uma lista;
Destruir a lista.
3.2 Tipos de Representações
3.2.1 Lista Representada por Contigüidade Física
Os nodos são armazenados em endereços contíguos, ou igualmente distanciados um
do outro.
Os elementos são armazenados na memória um ao lado do outro, levando-se em
consideração o tipo de dado, ou seja, a quantidade de bytes.
Se o endereço do nodo Xi é conhecido, então o endereço do nodo X(i+1) pode ser
determinado.
...
X(n-2)
X(n-1)
Xn
X1
X2
X3
Contigüidade Física
Esquema:
Os relacionamentos são representados pela disposição física dos componentes na
memória;
A posição na estrutura lógica determina a posição na estrutura física.
Observação: Uma lista pode ser implementada através de um vetor de “m” elementos.
Atenção: Se “n’ = “m” a Lista é chamada Cheia
Observação: Como o número de nodos armazenados na lista pode ser modificado durante a
execução do programa, deve-se representá-la como parte de um vetor de “m” elementos
com “n <= m”.
Representação
: A lista X está representada por um vetor V de “m” elementos.
Componentes de uma Lista
Número de nodos da lista (n);
Vetor de nodos (v);
Tamanho total da lista (m).
v
"m" elementos
n
#define m 7
typedef float TDADOS;
typedef struct {
int n;
TDADOS v[m];
} TLISTA;
TLISTA l;
Observação: Considera-se que o primeiro nodo da lista será armazenado na primeira
Exemplo:
typedef int TDADOS;
#define SUCESSO 1 #define LISTA_CHEIA 2 /* --- Cria_Lista */ void Cria_Lista(TLISTA *x) { x->n = 0; } /* --- Inclui_Fim */ int Inclui_Fim(TLISTA *x, TDADOS no)
{ if (x->n == m) return(LISTA_CHEIA); else { x->v[x->n] = no; x->n = x->n + 1; return(SUCESSO); } } /* --- Inclui_Inicio */ int Inclui_Inicio(TLISTA *x, TDADOS no)
{ int i; if (x->n == m) return(LISTA_CHEIA); else {
for (i = x->n-1;i >= 0;i--) x->v[i+1] = x->v[i]; x->v[0] = no; x->n = x->n + 1; return(SUCESSO); } }
Problema proposto:
4) Incluir dados em uma lista de números inteiros (máximo 10 elementos), mantendo-a
ordenada.
Solução do problema proposto (4):
/* Inserir Lista mantendo Ordenada */ #include <stdio.h> #include <conio.h> /* --- Definições */ #define m 5 #define SUCESSO 0 #define LISTA_CHEIA 1 #define LISTA_VAZIA 2 /* --- Tipos de Dados */ typedef int TDADOS;
typedef struct { int n; TDADOS v[m]; } TLISTA; /* --- Prototypes */ void Cria_Lista(TLISTA *x);
int Inclui_Fim(TLISTA *x, TDADOS dado); int Inclui_Inicio(TLISTA *x, TDADOS dado);
int Inclui_Posicao(TLISTA *x, TDADOS dado, int pos); int Verifica_Posicao(TLISTA *x, TDADOS dado);
void Exibe_Lista(TLISTA x); void Imprime_Erro(int erro);
/* --- Programa Principal */ void main(void) { TLISTA l; TDADOS valor; int erro; Cria_Lista(&l); clrscr(); printf("Valor: "); scanf("%d", &valor); if (valor != 0) { Inclui_Fim(&l,valor); do { Exibe_Lista(l); printf("\nValor: "); scanf("%d",&valor); if (valor != 0) { erro = Verifica_Posicao(&l,valor); if (erro) Imprime_Erro(erro);
}
} while (valor != 0 && erro != LISTA_CHEIA); } Exibe_Lista(l); getch(); } /* --- Cria_Lista */ void Cria_Lista(TLISTA *x) { x->n = 0; } /* --- Inclui_Fim */ int Inclui_Fim(TLISTA *x, TDADOS dado)
{ if (x->n == m) return(LISTA_CHEIA); else { x->v[x->n] = dado; x->n = x->n + 1; return(SUCESSO); } } /* --- Inclui_Inicio */ int Inclui_Inicio(TLISTA *x, TDADOS dado)
{ int i; if (x->n == m) return(LISTA_CHEIA); else {
for (i = x->n-1;i >= 0;i--) x->v[i+1] = x->v[i]; x->v[0] = dado; x->n = x->n + 1; return(SUCESSO); } } /* --- Inclui_Posicao */ int Inclui_Posicao(TLISTA *x, TDADOS dado, int pos)
{ int i; if (x->n == m) return(LISTA_CHEIA); else {
for (i = x->n-1;i >= pos;i--) x->v[i+1] = x->v[i]; x->v[pos] = dado;
x->n = x->n + 1; return(SUCESSO); }
}
/* --- Verifica_Posicao */ int Verifica_Posicao(TLISTA *x, TDADOS dado)
{ int i=0; do { if (dado < x->v[i]) return(Inclui_Posicao(x,dado,i)); i++; } while (i < x->n); return(Inclui_Fim(x,dado)); } /* --- Imprime_Erro */ void Imprime_Erro(int erro)
{
switch (erro) {
case LISTA_CHEIA: printf("ERRO: Lista Cheia\n"); break;
case LISTA_VAZIA: printf("ERRO: Lista Vazia\n"); break; } } /* --- Exibe_Lista */ void Exibe_Lista(TLISTA x) { int i; printf("Lista Ordenada: "); for (i = 0;i < x.n;i++) printf("%02d ",x.v[i]); }
Problema proposto:
5) Incluir dados em uma lista linear de números inteiros (máximo 50) sem repetição. O
programa termina quando o dado lido for zero, então o programa deve imprimir a lista na
tela sem repetição.
Solução do problema proposto (5):
/* Inserir Lista sem Repeticao */ #include <stdio.h>
/* --- Definições */ #define m 5 #define TRUE !0 #define FALSE 0 #define SUCESSO 0 #define LISTA_CHEIA 1 #define LISTA_VAZIA 2 #define DADO_REPETIDO 3 /* --- Tipos de Dados */ typedef int TDADOS;
typedef struct { int n; TDADOS v[m]; } TLISTA; /* --- Prototypes */ void Cria_Lista(TLISTA *x);
int Inclui_Fim(TLISTA *x, TDADOS dado); int Inclui_Inicio(TLISTA *x, TDADOS dado);
int Insere_Sem_Repeticao(TLISTA *x, TDADOS dado); void Imprime_Erro(int erro);
void Exibe_Lista(TLISTA x); /* --- Programa Principal */ void main(void) { TLISTA l; TDADOS valor; int erro; Cria_Lista(&l); clrscr(); printf("Valor: "); scanf("%d", &valor); if (valor != 0) { Inclui_Fim(&l,valor); do { Exibe_Lista(l); printf("\nValor: "); scanf("%d",&valor); if (valor != 0) { erro = Insere_Sem_Repeticao(&l,valor); if (erro) Imprime_Erro(erro); }
} while (valor != 0 && erro != LISTA_CHEIA); }
Exibe_Lista(l); getch();
} /* --- Cria_Lista */ void Cria_Lista(TLISTA *x) { x->n = 0; } /* --- Inclui_Fim */ int Inclui_Fim(TLISTA *x, TDADOS dado)
{ if (x->n == m) return(LISTA_CHEIA); else { x->v[x->n] = dado; x->n = x->n + 1; return(SUCESSO); } } /* --- Inclui_Inicio */ int Inclui_Inicio(TLISTA *x, int dado)
{ int i; if (x->n == m) return(LISTA_CHEIA); else {
for (i = x->n-1;i >= 0;i--) x->v[i+1] = x->v[i]; x->v[0] = dado; x->n = x->n + 1; return(SUCESSO); } } /* --- Insere_Sem_Repeticao */ int Insere_Sem_Repeticao(TLISTA *x, TDADOS dado)
{
int i,achei = FALSE; if (x->n == m)
return(LISTA_CHEIA); else
{
for (i = 0;i < x->n;i++) if (x->v[i] == dado) { achei = TRUE; return(DADO_REPETIDO); } if (!achei) return(Inclui_Fim(x,dado));
}
return(SUCESSO); }
/* --- Imprime_Erro */ void Imprime_Erro(int erro)
{
switch (erro) {
case LISTA_CHEIA: printf("ERRO: Lista Cheia\n"); break;
case LISTA_VAZIA: printf("ERRO: Lista Vazia\n"); break;
case DADO_REPETIDO: printf("ERRO: Dado Repetido\n"); break; } } /* --- Exibe_Lista */ void Exibe_Lista(TLISTA x) { int i;
printf("Lista sem Repeti‡Æo: "); if (x.n != 0)
for (i = 0;i < x.n;i++) printf("%02d ",x.v[i]); }
Contigüidade Física
Uma alternativa para representação por contigüidade física é não iniciar no início do
vetor, isto facilita as inserções.
Observação: As operações de inclusão e exclusão de nodos podem optar pela extremidade
da lista que irá diminuir (no caso de exclusão) ou aumentar (no caso de inserção) de
comprimento. “A escolha deverá considerar o caso que produz menor movimentação de
elementos”.
typedef float TDADOS;
typedef struct {
int fim;
TDADOS v[m];
} TLISTA;
TLISTA l;
Lista vazia
início = -1
fim = -1
Lista cheia
início = 0
fim = m-1
Problema proposto:
6) Escreva um programa em C que permite a inclusão de números inteiros no início ou no
fim da lista linear (máximo 7 elementos).
Solução do problema proposto (6):
/* Lista Linear */ #include <stdio.h> #include <conio.h> #include <string.h> #include <ctype.h> /* --- Definições */ #define m 7 #define SUCESSO 0 #define LISTA_CHEIA 1 #define LISTA_VAZIA 2 /* --- Tipos de Dados */ typedef int TDADOS;
typedef struct { int inicio; int fim; TDADOS v[m]; } TLISTA; /* --- Prototypes */ void Cria_Lista(TLISTA *x);
int Inclui_Fim(TLISTA *x, TDADOS dado); void Exibe_Lista(TLISTA x);
void Imprime_Erro(int erro);
/* --- Programa Principal */ void main(void) { TLISTA l; TDADOS valor; int erro; char ch; Cria_Lista(&l); clrscr(); do { Exibe_Lista(l); printf("\nValor: "); scanf("%d",&valor); if (valor != 0) { printf("[I]nício ou [F]im ?"); do { ch = toupper(getche()); } while (!strchr("IF",ch)); switch (ch) {
case 'I': erro = Inclui_Inicio(&l,valor); break;
case 'F': erro = Inclui_Fim(&l,valor); break;
}
if (erro)
Imprime_Erro(erro); }
} while (valor != 0 && erro != LISTA_CHEIA); Exibe_Lista(l); getch(); } /* --- Cria_Lista */ void Cria_Lista(TLISTA *x) { x->inicio = -1; x->fim = -1; } /* --- Inclui_Inicio */ int Inclui_Inicio(TLISTA *x, TDADOS dado)
{ if (x->inicio == -1) { x->inicio = m / 2; x->fim = x->inicio; x->v[x->inicio] = dado; return(SUCESSO); }
else if (x->inicio == 0) return(LISTA_CHEIA); else { x->inicio = x->inicio - 1; x->v[x->inicio] = dado; return(SUCESSO); } } /* --- Inclui_Fim */ int Inclui_Fim(TLISTA *x, TDADOS dado)
{ if (x->fim == -1) { x->inicio = m / 2; x->fim = x->inicio; x->v[x->fim] = dado; return(SUCESSO); } else if (x->fim == m-1) return(LISTA_CHEIA); else { x->fim = x->fim + 1; x->v[x->fim] = dado; return(SUCESSO); } } /* --- Imprime_Erro */ void Imprime_Erro(int erro)
{
switch (erro) {
case LISTA_VAZIA: printf("\nERRO: Lista Vazia"); break;
case LISTA_CHEIA: printf("\nERRO: Lista Cheia"); break; } } /* --- Exibe_Lista */ void Exibe_Lista(TLISTA x) { int i; printf("\nLista: "); if (x.inicio != -1)
for (i = x.inicio;i <= x.fim;i++) printf("%02d ",x.v[i]);
else
printf("VAZIA"); }
Problema proposto:
7) Escreva um programa em C que permite a inclusão de números inteiros no início ou no
fim da lista linear (máximo 7 elementos) avisando qual lado está cheio.
Observação: Note que a lista pode estar cheia num lado e não estar cheia no outro lado. A
próxima solução (“7”) avisa ao usuário qual lado da lista linear está cheio.
Solução do problema proposto (7):
/* Lista Linear no meio do Vetor */
#include <stdio.h> #include <conio.h> #include <string.h> #include <ctype.h> /* --- Definições */ #define m 7 #define SUCESSO 0 #define LISTA_CHEIA_ESQUERDA 1 #define LISTA_CHEIA_DIREITA 2 /* --- Tipos de Dados */ typedef int TDADOS;
typedef struct { int inicio; int fim; TDADOS v[m]; } TLISTA; /* --- Prototypes */ void Cria_Lista(TLISTA *x);
int Inclui_Inicio(TLISTA *x, TDADOS dado); int Inclui_Fim(TLISTA *x, TDADOS dado); void Imprime_Erro(int erro);
void Exibe_Lista(TLISTA x); /* --- Programa Principal */ void main(void) { TLISTA l; TDADOS valor; int erro; char ch; Cria_Lista(&l); clrscr();
do { Exibe_Lista(l); printf("\nValor: "); scanf("%d",&valor); if (valor != 0) { printf("[I]nício ou [F]im ?"); do { ch = toupper(getche()); } while (!strchr("IF",ch)); switch (ch) {
case 'I': erro = Inclui_Inicio(&l,valor); break;
case 'F': erro = Inclui_Fim(&l,valor); break; } if (erro) Imprime_Erro(erro); } } while (valor != 0); Exibe_Lista(l); getch(); } /* --- Cria_Lista */ void Cria_Lista(TLISTA *x) { x->inicio = -1; x->fim = -1; } /* --- Inclui_Inicio */ int Inclui_Inicio(TLISTA *x, TDADOS dado)
{ if (x->inicio == -1) { x->inicio = m / 2; x->fim = x->inicio; x->v[x->inicio] = dado; return(SUCESSO); } else if (x->inicio == 0) return(LISTA_CHEIA_ESQUERDA); else { x->inicio = x->inicio - 1; x->v[x->inicio] = dado; return(SUCESSO); } } /* --- Inclui_Fim */ int Inclui_Fim (TLISTA *x, TDADOS dado)
if (x->fim == -1) { x->inicio = m / 2; x->fim = x->inicio; x->v[x->fim] = dado; return(SUCESSO); } else if (x->fim == m-1) return(LISTA_CHEIA_DIREITA); else { x->fim = x->fim + 1; x->v[x->fim] = dado; return(SUCESSO); } } /* --- Imprime_Erro */ void Imprime_Erro(int erro)
{
switch (erro) {
case LISTA_CHEIA_ESQUERDA: printf("\nERRO: Lista Cheia na ESQUERDA"); break;
case LISTA_CHEIA_DIREITA: printf("\nERRO: Lista Cheia na DIREITA"); break; } } /* --- Exibe_Lista */ void Exibe_Lista(TLISTA x) { int i; printf("\nLista: "); if (x.inicio == -1) printf("VAZIA"); else
for (i = x.inicio;i <= x.fim;i++) printf("%02d ",x.v[i]);
}
Problema proposto:
8) Escreva um programa em C que permite a inclusão de números inteiros em uma lista
linear no início, fim e na posição escolhida pelo usuário
Solução do problema proposto (8):
/* Lista Linear meio do vetor */ #include <stdio.h>
#include <string.h> #include <ctype.h> /* --- Definições */ #define m 7 #define SUCESSO 0 #define LISTA_CHEIA 1 #define LISTA_VAZIA 2 /* --- Tipos de Dados */ typedef int TDADOS;
typedef struct { int inicio; int fim; TDADOS v[m]; } TLISTA; /* --- Prototypes */ void Cria_Lista(TLISTA *x);
int Inclui_Inicio(TLISTA *x, TDADOS dado); int Inclui_Fim(TLISTA *x, TDADOS dado);
int Inclui_Posicao(TLISTA *x, TDADOS dado, int pos); void Exibe_Lista(TLISTA x);
void Imprime_Erro(int erro);
/* --- Programa Principal */ void main(void) { TLISTA l; TDADOS valor; int erro,pos,inic,fim; char ch; Cria_Lista(&l); clrscr(); do { Exibe_Lista(l); printf("\nValor: "); scanf("%d",&valor); if (valor != 0) {
printf("[I]nício, [P]osição ou [F]im ?"); do {
ch = toupper(getche()); } while (!strchr("IFP",ch)); switch (ch)
{
case 'I': erro = Inclui_Inicio(&l,valor); break;
case 'F': erro = Inclui_Fim(&l,valor); break;
case 'P': if (l.inicio == -1) inic = 1;
else if (l.inicio == 0) inic = 1; else inic = l.inicio +1; if (l.fim == -1) fim = m; else fim = l.fim + 1; printf("\n"); do { printf("Posição [%d..%d]: ",inic,fim); scanf("%d",&pos);
} while (!(pos >= inic && pos <= fim)); erro = Inclui_Posicao(&l,valor,pos-1); break; } } if (erro) Imprime_Erro(erro); } while (valor != 0); Exibe_Lista(l); getch(); } /* --- Cria_Lista */ void Cria_Lista(TLISTA *x) { x->inicio = -1; x->fim = -1; } /* --- Inclui_Inicio */ int Inclui_Inicio(TLISTA *x, TDADOS dado)
{ if (x->inicio == -1) { x->inicio = m / 2; x->fim = x->inicio; x->v[x->inicio] = dado; return(SUCESSO); } else if (x->inicio == 0) return(LISTA_CHEIA); else { x->inicio = x->inicio - 1; x->v[x->inicio] = dado; return(SUCESSO); } } /* --- Inclui_Fim */ int Inclui_Fim(TLISTA *x, TDADOS dado)
if (x->fim == -1) { x->fim = m / 2; x->inicio = x->fim; x->v[x->fim] = dado; return(SUCESSO); } else if (x->fim == m-1) return(LISTA_CHEIA); else { x->fim = x->fim + 1; x->v[x->fim] = dado; return(SUCESSO); } } /* --- Inclui_Posicao */ int Inclui_Posicao(TLISTA *x, TDADOS dado, int pos) { int i,erro; if (x->inicio == -1) { x->inicio = pos; x->fim = pos; x->v[x->inicio] = dado; return(SUCESSO); } else
if (x->inicio == 0 && x->fim == m-1) return(LISTA_CHEIA); else if (pos == x->inicio-1) { erro = Inclui_Inicio(x,dado); return(erro); } else if (pos == x->fim+1) { erro = Inclui_Fim(x,dado); return(erro); } else {
for (i = x->fim;i >= pos;i--) x->v[i+1] = x->v[i]; x->v[pos] = dado; x->fim = x->fim + 1; return(SUCESSO); } } /* --- Exibe_Lista */ void Exibe_Lista(TLISTA x)
{ int i; printf("\nLista: "); if (x.inicio == -1) printf("VAZIA"); else
for (i = x.inicio;i <= x.fim;i++) printf("%02d ",x.v[i]);
}
/* --- Imprime_Erro */ void Imprime_Erro(int erro)
{
switch (erro) {
case LISTA_CHEIA: printf("ERRO: Lista Cheia\n"); break;
case LISTA_VAZIA: printf("ERRO: Lista Vazia\n"); break;
} }
Vantagens e Desvantagens da Representação por Contigüidade Física
Vantagens
- A consulta pode ser calculada (acesso randômico aos dados);
- Facilita a transferência de dados (área de memória contígua);
- Adequada para o armazenamento de estruturas simples.
Desvantagens
- O tamanho máximo da lista precisa ser conhecido e alocado antecipadamente, pois a lista
é alocada estaticamente na memória;
- Inserções e remoções podem exigir considerável movimentação de dados;
- Inadequada para o armazenamento de estruturas complexas;
- Mantém um espaço de memória ocioso (não ocupado);
- Como a lista é limitada, devem ser testados os limites.
3.2.2 Lista representada por Encadeamento
Permite Alocação Dinâmica de Memória, ou seja, a lista cresce com a execução do
programa. Operações como inserção e remoção são mais simples. Isto é feito através de
variáveis do tipo ponteiro, ou seja, um elemento aponta (possui o endereço, posição de
memória do próximo elemento) para o próximo.
Problema proposto:
9) Escreva um programa em C que permite incluir números inteiros em uma lista
encadeada.
Solução do problema proposto (9):
/* Lista Encadeada */ #include <stdio.h> #include <conio.h> #include <alloc.h> #include <stdlib.h> /* --- Definições */ #define SUCESSO 0 #define FALTA_DE_MEMORIA 1 #define LISTA_VAZIA 2 /* --- Tipos de Dados */ typedef int TDADOS;
typedef struct nodo {
TDADOS dado; struct nodo *elo; } TNODO;
typedef struct {
TNODO *primeiro; } TLISTA;
/* --- Prototypes */ void Cria_Lista (TLISTA *l);
int Inclui_Lista (TLISTA *l, TDADOS d); int Remove_Primeiro(TLISTA *l);
int Conta_Elementos_Lista(TLISTA l); int Remove_Ultimo(TLISTA *l);
void Imprime_Erro(int erro); void destroi_Lista(TLISTA *l);
void main(void) { TLISTA l; TDADOS d; int n,erro; Cria_Lista(&l); clrscr(); do { printf("Valor: "); scanf("%d",&d); if (d != 0) { erro = Inclui_Lista(&l,d); if (erro) { Imprime_Erro(erro); break; } } } while (d != 0); n = Conta_Elementos_Lista(l); printf("Número de Elementos: %d\n",n); Destroi_Lista(&l); getch(); } /* --- Cria_Lista */ void Cria_Lista (TLISTA *l)
{
l->primeiro = NULL; }
/* --- Inclui_Lista */ int Inclui_Lista (TLISTA *l, TDADOS d)
{ TNODO *p; p = (TNODO *) malloc(sizeof(TNODO)); if (p == NULL) return(FALTA_DE_MEMORIA); else { if (l->primeiro == NULL) { l->primeiro = p; p->dado = d; p->elo = NULL; } else { p->dado = d; p->elo = l->primeiro; l->primeiro = p; } return(SUCESSO);
} } /* --- Remove_Primeiro */ int Remove_Primeiro(TLISTA *l) { TNODO *p; if (l->primeiro == NULL) return(LISTA_VAZIA); else { p = l->primeiro; l->primeiro = p->elo; free(p); return(SUCESSO); } } /* --- Conta_elementos */ int Conta_Elementos_Lista(TLISTA l) { TNODO *p; int n; if (l.primeiro == NULL) return(0); else { n = 0; p = l.primeiro; while (p != NULL) { n++; p = p->elo; } return(n); } } /* --- Remove_Ultimo */ int Remove_Ultimo(TLISTA *l) { TNODO *p,*q; if (l->primeiro == NULL) return(LISTA_VAZIA); else { q = l->primeiro; p = l->primeiro;
while (p->elo != NULL) {
q = p; p = p->elo; }
if (l->primeiro == q) l->primeiro = NULL; else q->elo = NULL; free(p); return(SUCESSO); } } /* --- Imprime_Erro */ void Imprime_Erro(int erro)
{
switch (erro) {
case FALTA_DE_MEMORIA: printf("ERRO: Falta de Memória\n"); break;
case LISTA_VAZIA: printf("ERRO: Lista Vazia\n"); break; } getch(); } /* --- Destroi_Lista */ void Destroi_Lista(TLISTA *l) { TNODO *p; if (l->primeiro != NULL) { p = l->primeiro; while (p != NULL) { l->primeiro = p->elo; free(p); p = l->primeiro; } } }
Problema proposto:
10) Escrever um programa em C que insere dados em uma lista encadeada, permitindo
obter o conteúdo do último elemento, imprimindo também, toda a lista.
Solução do problema proposto (10):
/* Lista Encadeada */ #include <stdio.h> #include <conio.h> #include <alloc.h> #include <stdlib.h> /* --- Definições */
#define SUCESSO 0
#define FALTA_DE_MEMORIA 1
#define LISTA_VAZIA 2
/* --- Tipos de Dados */ typedef int TDADOS;
typedef struct nodo {
TDADOS dado; struct nodo *elo; } TNODO;
typedef struct {
TNODO *primeiro; } TLISTA;
/* --- Prototypes */ void Cria_Lista (TLISTA *l);
int Inclui_Lista (TLISTA *l, TDADOS dado); int Consulta_Ultimo(TLISTA l,TDADOS *dado); int Imprime_Lista(TLISTA l);
void Imprime_Erro(int erro);
/* --- Programa Principal */ void main(void) { TLISTA l; TDADOS valor; int erro; Cria_Lista(&l); clrscr(); do { printf("Valor: "); scanf("%d",&valor); if (valor != 0) { erro = Inclui_Lista(&l,valor); if (erro) { Imprime_Erro(erro); break; } } } while (valor != 0); erro = Consulta_Ultimo(l,&valor); if (erro == SUCESSO) {
printf("Último Elemento: %d\n",valor); Imprime_Lista(l); } else Imprime_Erro(erro); getch(); }
/* --- Cria_Lista */ void Cria_Lista (TLISTA *l)
{
l->primeiro = NULL; }
/* --- Inclui_Lista */ int Inclui_Lista (TLISTA *l, TDADOS d)
{ TNODO *p; p = (TNODO *) malloc(sizeof(TNODO)); if (p == NULL) return(FALTA_DE_MEMORIA); else { if (l->primeiro == NULL) { l->primeiro = p; p->dado = d; p->elo = NULL; } else { p->dado = d; p->elo = l->primeiro; l->primeiro = p; } return(SUCESSO); } } /* --- Consulta_Ultimo */ int Consulta_Ultimo(TLISTA l,TDADOS *dado)
{ TNODO *p; if (l.primeiro == NULL) return(LISTA_VAZIA); else { p = l.primeiro;
while (p->elo != NULL) p = p->elo; *dado = p->dado; return(SUCESSO); } } /* --- Imprime_Erro */ void Imprime_Erro(int erro)
{
switch (erro) {
case FALTA_DE_MEMORIA: printf("ERRO: Falta de Memória\n"); break;
case LISTA_VAZIA: printf("ERRO: Lista Vazia\n"); break; } } /* --- Imprime_Lista */ int Imprime_Lista(TLISTA l) { TNODO *p; if (l.primeiro == NULL) return(LISTA_VAZIA); else { printf("Lista Encadeada: "); p = l.primeiro; while (p != NULL) { printf("%02d ",p->dado); p = p->elo; } return(SUCESSO); } }
Problema proposto:
11) Escrever um programa em C que permite incluir, excluir e consultar (no início ou fim)
dados inteiros em uma lista encadeada. Em cada operação imprimir a lista.
Solução do problema proposto (11):
/* Lista Encadeada */ #include <stdio.h> #include <conio.h> #include <string.h> #include <ctype.h> #include <alloc.h> #include <stdlib.h> /* --- Definições */ #define SUCESSO 0 #define FALTA_DE_MEMORIA 1 #define LISTA_VAZIA 2 /* --- Tipos de Dados */ typedef int TDADOS;
typedef struct nodo {
struct nodo *elo; } TNODO; typedef struct { TNODO *primeiro; } TLISTA; /* --- Prototypes */ void Cria_Lista(TLISTA *l);
int Inclui_Lista(TLISTA *l, TDADOS valor); int Exclui_Lista(TLISTA *l);
int Consulta_Lista(TLISTA l, TDADOS *valor); void Imprime_Erro(int erro);
void Destroi_Lista(TLISTA *l); void Exibe_Primeiro(TLISTA l); void Exibe_Lista(TLISTA l); /* --- Programa Principal */ void main(void) { TLISTA l; TDADOS valor; int erro; char tecla; Cria_Lista(&l); clrscr(); do { Exibe_Primeiro(l); Exibe_Lista(l); gotoxy(1,3);
printf("[I]ncluir, [E]xcluir, [C]onsultar ou [F]inalizar: "); do {
tecla = toupper(getche()); } while (!strchr("IECF",tecla)); switch (tecla)
{
case 'I': gotoxy(1,4);
printf("Valor: "); scanf("%d",&valor); gotoxy(1,4); clreol(); erro = Inclui_Lista(&l,valor); break;
case 'E': erro = Exclui_Lista(&l); if (!erro)
{
gotoxy(1,4);
printf("Ok, Elemento Excluído");
printf(", tecle <enter> para continuar"); getch();
gotoxy(1,4); clreol(); }
break;
case 'C': erro = Consulta_Lista(l,&valor); if (!erro)
{
gotoxy(1,4);
printf("Valor Consultado: %d",valor); }
break; }
if (erro && tecla != 'F') Imprime_Erro(erro); } while (tecla != 'F'); Destroi_Lista(&l); } /* --- Cria_Lista */ void Cria_Lista(TLISTA *l) { l->primeiro = NULL; } /* --- Inclui_Lista */ int Inclui_Lista(TLISTA *l, TDADOS dado)
{ TNODO *p; p = (TNODO *) malloc(sizeof(TNODO)); if (p == NULL) return(FALTA_DE_MEMORIA); else { p->dado = dado; if (l->primeiro == NULL) { l->primeiro = p; p->elo = NULL; } else { p->elo = l->primeiro; l->primeiro = p; } return(SUCESSO); } } /* --- Exclui_Lista */ int Exclui_Lista(TLISTA *l) { TNODO *p; if (l->primeiro == NULL) return(LISTA_VAZIA); else { p = l->primeiro; l->primeiro = p->elo; free(p); return(SUCESSO);
} }
/* --- Consulta_Lista */ int Consulta_Lista(TLISTA l, TDADOS *dado)
{ TNODO *p; if (l.primeiro == NULL) return(LISTA_VAZIA); else { p = l.primeiro; *dado = p->dado; return(SUCESSO); } } /* --- Imprime_Erro */ void Imprime_Erro(int erro)
{
gotoxy(1,4); switch (erro) {
case FALTA_DE_MEMORIA: printf("ERRO: FALTA DE MEMÓRIA"); break;
case LISTA_VAZIA: printf("ERRO: LISTA VAZIA"); break;
}
printf(", tecle <enter> para continuar"); getch(); gotoxy(1,4); clreol(); } /* --- Destroi_Lista */ void Destroi_Lista(TLISTA *l) { TNODO *p,*q; if (l->primeiro != NULL) { p = l->primeiro; while (p != NULL) { q = p->elo; free(p); p = q; } } Cria_Lista(l); } /* --- Exibe_Primeiro */ void Exibe_Primeiro(TLISTA l)
{ gotoxy(1,1); if (l.primeiro != NULL) printf("Primeiro: | %p |",l.primeiro); else printf("Primeiro: | NULL |"); } /* --- Exibe_Lista */ void Exibe_Lista(TLISTA l) { TNODO *p; gotoxy(1,2); clreol(); gotoxy(1,2); printf("Lista Encadeada: "); if (l.primeiro == NULL) printf("LISTA VAZIA"); else { p = l.primeiro; while (p != NULL) { printf("| %02d ",p->dado); p = p->elo; } } }