• Nenhum resultado encontrado

ApostilaED-emC

N/A
N/A
Protected

Academic year: 2021

Share "ApostilaED-emC"

Copied!
137
0
0

Texto

(1)

Prof. Cristiano Biancardi

Estruturas de Dados em C

(2)

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

(3)

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

(4)

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.

(5)

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.

(6)

#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

tempohoras, tempominutos ou temposegundos

ou

(*tempo).horas, (*tempo).minutos ou (*tempo).segundos

Exemplo: #include <stdio.h> struct Name{ char * first; char midinit; char *last; };

(7)

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];

(8)

}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:

(9)

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.

(10)

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();

(11)

} 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;

(12)

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

(13)

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 C

Ponteiros 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á

(14)

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

n

bytes faz que

n

seja somado ao endereço.

É possível se usar o seguinte comando:

*(p+1)=10;

(15)

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

float

ou o tipo

double

a 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

(16)

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.

(17)

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

(18)

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.

(19)

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;

(20)

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

(21)

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;

(22)

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”.

(23)

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

(24)

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.

(25)

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);

(26)

}

} 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;

(27)

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>

(28)

/* --- 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();

(29)

} /* --- 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));

(30)

}

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 {

(31)

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);

(32)

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); }

(33)

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"); }

(34)

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();

(35)

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)

(36)

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>

(37)

#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;

(38)

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)

(39)

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)

(40)

{ 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.

(41)

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);

(42)

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);

(43)

} } /* --- 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; }

(44)

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 */

(45)

#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(); }

(46)

/* --- 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) {

(47)

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 {

(48)

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)

(49)

{

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);

(50)

} }

/* --- 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)

(51)

{ 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; } } }

(52)

Vantagens das Listas representadas por Encadeamento

- Lista cresce indeterminadamente, enquanto houver memória livre (Alocação Dinâmica

de Memória);

- As operações de insersão e remoção de elementos não exige a movimentação dos

demais elementos.

Desvantagens das Listas representadas por Encadeamento

- Determinar o número de elementos da lista, pois para tanto, deve-se percorrer toda a

lista;

- Acessar diretamente um determinado elemento pela sua posição, pois só é conhecido o

primeiro elemento da lista;

- Acessar o último elemento da lista, pois para acessá-lo, deve-se “visitar” todos os

intermediários.

3.2.3 Lista Encadeada com Descritor

Como foi visto anteriormente, as dificuldades da lista encadeada, é descobrir o

número de elementos e ainda, acessar o último elemento. Estas dificuldades podem ser

resolvidas utilizando-se um descritor, da seguinte forma:

Referências

Documentos relacionados

Declaro ser esclarecido e estar de acordo com os seguintes pontos: O trabalho ESTUDO CLÍNICO E HISTOPATOLÓGICO E AVALIAÇÃO IMUNOHISTOQUÍMICA DA PROTEÍNA Ki67 EM QUEILITES

XI – ter autonomia para definir produção, programação e distribuição de conteúdo no sistema público de radiodifusão, em consonância com o seu Conselho

Não fique “sofrendo” gastando mais do que você precisa investir para construir uma lista de emails qualificadas e que seja capaz de gerar rela- cionamento com o seu público já

O presente documento visa orientar os gestores das Instituições de Ensino da rede de Colégios Adventistas, objetivando o retorno gradual das aulas, buscando prover um ambiente

Participação do setor na arrecadação do tributo é de apenas 0,11% Participação do setor na arrecadação do tributo é de apenas 0,11% Participação do setor na arrecadação

A seleção portuguesa feminina de andebol de sub-20 perdeu hoje 21-20 com a Hungria, na terceira jornada do Grupo C do Mundial da categoria, a decorrer em Koprivnica, na

• Structs são coleções de dados heterogêneos agrupados em um mesmo elemento de dados. • Ex: armazenar as coordenadas (x,y) de um

uma lista encadeada é representada pelo ponteiro para seu primeiro elemento, do tipo