estruturas em dados (linguagem c)

14
Variáveis Dinâmicas Todas as estruturas de dados vistas anteriormente são estáticas isto é, as variáveis, uma vez declaradas implicam uma alocação de espaço fixo e predeterminado. Durante toda a execução do programa a quantidade de bytes alocados para as variáveis não pode ser modificada, mesmo que seja pouco utilizado. É muito freqüente, entretanto, a ocorrência de listas de dados que variam em tamanho. Ex: Por outro lado, se num mesmo programa precisamos processar matrizes de ordem grande, pode não haver espaço de memória suficiente. O ideal seria utilizar o espaço para uma delas, fazer as operações desejadas e dispor desse espaço, liberando-o para outra finalidade. As variáveis dinâmicas, que veremos não são criadas em tempo de compilação isto significa que o compilador não faz alocação de espaço de memória para as variáveis dinâmicas. Durante a execução do programa, podemos alocar espaço desejado ou dispor dele quando não for mais necessário. Tipo Ponteiro Os valores do tipo ponteiro é definida pelo símbolo -> seguido do tipo da variável dinâmica que pode ser que pode ser referenciada por esse ponteiro. Ex: ... Typedef struct no { char nome [30], cidade [20]; int código, idade struct no *inicio; }no; A declaração acima aloca espaço somente a variável inicio que é do tipo ponteiro. Uma variável do tipo ponteiro ocupa 4 bytes de memória. Observe que na declaração do tipo ponteiro é especificado o tipo da estrutura que pode ser referenciada pela variável ponteiro. No exemplo acima, uma variável do tipo no pode referenciar ou apontar para um endereço que comporte armazenar a estrutura de dados citado acima. Nome Cidade Código Idade Inicio A declaração da variável início não inicializa a variável, isto é, nenhum valor é armazenado em início e na memória não existe ainda nenhuma estrutura do tipo no. Para criar uma variável dinâmica, é preciso uma certa quantidade de espaço de memória. No exemplo acima, o espaço necessário é o numero de bytes que acomode o tipo nó. A alocação desse espaço e a sua localização na memória são feitas pelo procedimento predefinido chamado MALLOC. Comando MALLOC O procedimento MALLOC tem como parâmetro uma variável ponteiro e, quando ativado aloca, espaço de memória de acordo com a declaração do tipo do ponteiro. Ex: Inicio=(no*)malloc(sizeof(no));

Upload: naiade-de-lima

Post on 10-Mar-2016

235 views

Category:

Documents


14 download

DESCRIPTION

*Variáveis Dinâmicas *Tipo Ponteiro *Comando MALLOC *Árvores *Espalhamento – hashing *Pilha *Fila *Simulado

TRANSCRIPT

Page 1: Estruturas em dados (linguagem c)

Variáveis Dinâmicas

Todas as estruturas de dados vistas anteriormente são estáticas isto é, as variáveis, uma vez declaradas implicam uma alocação de espaço fixo e predeterminado. Durante toda a execução do programa a quantidade de bytes alocados para as variáveis não pode ser modificada, mesmo que seja pouco utilizado. É muito freqüente, entretanto, a ocorrência de listas de dados que variam em tamanho. Ex: Por outro lado, se num mesmo programa precisamos processar matrizes de ordem grande, pode não haver espaço de memória suficiente. O ideal seria utilizar o espaço para uma delas, fazer as operações desejadas e dispor desse espaço, liberando-o para outra finalidade. As variáveis dinâmicas, que veremos não são criadas em tempo de compilação isto significa que o compilador não faz alocação de espaço de memória para as variáveis dinâmicas. Durante a execução do programa, podemos alocar espaço desejado ou dispor dele quando não for mais necessário. Tipo Ponteiro

Os valores do tipo ponteiro é definida pelo símbolo -> seguido do tipo da variável dinâmica que pode ser que pode ser referenciada por esse ponteiro. Ex:

... Typedef struct no { char nome [30], cidade [20]; int código, idade struct no *inicio; }no;

A declaração acima aloca espaço somente a variável inicio que é do tipo ponteiro. Uma variável do tipo ponteiro ocupa 4 bytes de memória. Observe que na declaração do tipo ponteiro é especificado o tipo da estrutura que pode ser referenciada pela variável ponteiro. No exemplo acima, uma variável do tipo no pode referenciar ou apontar para um endereço que comporte armazenar a estrutura de dados citado acima. Nome Cidade Código Idade

Inicio A declaração da variável início não inicializa a variável, isto é, nenhum valor é armazenado em início e na memória não existe ainda nenhuma estrutura do tipo no. Para criar uma variável dinâmica, é preciso uma certa quantidade de espaço de memória. No exemplo acima, o espaço necessário é o numero de bytes que acomode o tipo nó. A alocação desse espaço e a sua localização na memória são feitas pelo procedimento predefinido chamado MALLOC. Comando MALLOC

O procedimento MALLOC tem como parâmetro uma variável ponteiro e, quando ativado aloca, espaço de memória de acordo com a declaração do tipo do ponteiro. Ex: Inicio=(no*)malloc(sizeof(no));

Page 2: Estruturas em dados (linguagem c)

desta semântica aloca um espaço de memória para uma estrutura do tipo nó, e faz com que o endereço dessa estrutura seja armazenada na variável inicio. Portanto dizemos q o inicio aponta para estrutura do tipo nó.

____________________________ 1 camada S.O./Compilador ____________________________

2 camada stack inicio ____________________________

3 camada ////////

____________________________ tipo nó A estrutura dinâmica não é inicializada pois nada é armazenada em nó. A variável inicio contém endereço dessa estrutura que permite o acesso e armazenamento dos dados. Para acessar a estrutura dinâmica, podemos escrever o nome da variável do tipo ponteiro, seguido do símbolo ->. inicio-> nome Estrutura do nó “campo” Variável dinâmica Este procedimento permite o acesso ou armazenamento do dado. Exemplo:

inicio->nome=”ANA”; inicio->código=1; If inicio->nota > 10{ ... } Scanf(“%s”,inicio->nome); Scanf(“%d”, inicio->idade); ...

Podemos usar o comando de atribuição para as variáveis do tipo ponteiro desde que sejam da mesma estrutura. inicio=corrente; Os operadores relacionais =e <> também podem ser utilizados. Há uma constante predefinida para o tipo ponteiro que é identificado por NULL. O valor NULL, não é nenhum endereço valido e é compatível com qualquer variável ponteiro. Adotaremos um pseudocódigo para o desenvolvimento da aprendizagem na aplicação da variável dinânica. Exemplo: typedef struct no char *no; struct no *P, *Q; P=(no*) malloc (sizeof(no)); P->=’A’; Q=P;

P=Null; Comando Free O procedimento Free disponibiliza O endereço até então ocupado por uma variável do tipo ponteiro. Podemos citar o seguinte exemplo: typedef struct no int *no

Page 3: Estruturas em dados (linguagem c)

struct no *P, *Q, *Local; P=(no*) malloc(sizeof(no));

P->=51; Q= (no*) malloc(sizeof(no)); Q->=13; Local=P; P=Q; Free(Local);

1º P /////

2º P / 51/

3º Q ///// P / 51/

4º Q /13/ P / 51/

5º Q /13/ P / 51/

Local

6º P /13/ Local / 51/ Q

7º P /13/ Local / 51/ Q

Estrutura Lista Simplesmente Encadeada A estrutura mencionada acima permite desenvolver uma estrutura para fins de armazenamento e recuperação dos dados. Para obter essa recuperação é necessário que na estrutura venha ser informado um campo do tipo ponteiro. Exemplo:

////

campo do tipo ponteiro Exemplo: typedef struct no { char nome[30], cidade[30]; int código, idade; struct no* next; }no; struct no *inicio; struct no *corrente; struct no *auxiliar; Em uma estrutura de dados necessitamos atribuir alguns ponteiro bem como suas funções a ser desempenhado como: Ponteiro de estrutura Ponteiro auxiliar de processamento Ponteiro sentinela

Page 4: Estruturas em dados (linguagem c)

Ponteiro de Estrutura: São ponteiros que são declaraods na estrutura Registro, sendo reconhecido como campo do tipo ponteiro. Este campo permite armazenar endereço de memória permitindo o encadeamento com os demais registros ou nó. Ponteiro Auxiliar de Processamento: São ponteiros que contribuem na execução de tarefas durante o processamento. Citamos alguns:

a) Alocação de Endereço; b) Encadeamento de registros; c) Carregamento de dados;

Ponteiro Sentinela: São ponteiro que permanecem posicionados na estrutura servindo de referencia para os demais ponteiros. Pode ser deslocados somente quando a posição que ocupam deva ser removido, mesmo assim deve ser garantida uma nova posição na estrutura. Estrutura Simplesmente Encadeada É uma estrutura linear que permite as seguintes operações como (insert, remove, search, impress) permitindo muita flexibilidade no gerenciamento dos dados nesta estrutura. Sua aplicação podemos citar (arquivos em meios magnéticos, editores de texto, registro em arquivos) entre outros. Exemplo Typedef struct no char nome[30], cidade[10]; int código, idade; struct no*next; }no; struct no *H; struct no *T; struct no *P;

1) h=Null; 2) t=Null; 3) Malloc (P); 4) P->idade=10; 5) P->next=Null; 6) H=P; 7) T=P; 8) Malloc (P); 9) P->idade=20; P->nest=Null; 10) T->next=P; 11) T=P; 12) Malloc (P); 13) P->idade=30; 14) T->next=P; P->next=Null; 15) T=P; 16) P=H; 17) H=H->next; 18) Free (P); 19) P=H; 20) H=H->next; 21) Free (P); 22) Printf (P->idade);

Teste

1) H~ 2) H~ T~ 3) H~ T~ P-> 4) H~ T~ P->10 5) H~ T~ P->10~ 6) T~ H,P->10~ 7) T,H,P->10~ 8) T,H->10~ P-> 9) T,H->10~ P->20~ 10) T,H->10, P->20~ 11) H->10,P,T->20~ 12) H->10, T->20~ P-> 13) H->10,T->20~ P->30 14) H->10, T->20, P->30

a) H->10, T->20, P->30~ 15) H->10->20, T, P->30~ 16) P,H->10->20, T->30~ 17) P->10, H->20, T->30~ 18) H->20, T->30~ 19) H,P->20, T->30~ 20) P->20,T,H->30~ 21) T,H->30~

Page 5: Estruturas em dados (linguagem c)

___________________________________________________________________________________________ Código: #include<stdio.h> #include<conio.h> #include <stdlib.h> typedef struct no{ char nome[30], cidade[10]; int codigo, idade; struct no *prox; }no; int main(){ fflush(stdin); no *H, *T, *P; H = NULL; T = NULL; P = (no*)malloc(sizeof(no)); P->idade = 10; P->prox = NULL; H = P; T = P; P = (no*)malloc(sizeof(no));

P->idade = 20; P->prox=NULL; T->prox=P; T=P; P = (no*)malloc(sizeof(no)); P->idade = 30; T->prox=P; P->prox=NULL; T=P; P=H; H=H->prox; free(P); P=NULL; P=H; H=H->prox; free(P); P=NULL; printf("%i\n", P->idade); getch(); return 0; }

________________________________________________________________________________________

Exercício 1)Desenvolva uma rotina simplesmente encadeada que permita armazenar n registros – Rotina insert Abaixo segue a estrutura de registro: Código, Nome, idade e departamento. #include <stdio.h> #include <stdlib.h> #include <conio.h> Typedef struct no { int codigo, idade; char nome[20], depto[10]; struct no *next; }no; struct no *inicio, *corrente, *aux; int código=1; void Enterdata() { aux->código=código; printf(“\nDigite o nome”); scanf(“%s”&aux->nome); printf(“\nDigite a idade”); scanf(“%d”&aux->idade); printf(“\nDigite o Depto”); scanf(“%s”&aux->depto); código=código+1; } Void insert (no **Lista)

Page 6: Estruturas em dados (linguagem c)

{ IF (inicio==NULL) { inicio=(no*) malloc(sizeof(no)); corrente=inicio; aux=inicio; corrente->next=NULL; Enterdata(); } else { corrente=(no*)malloc(sizeof(no)); corrente->next=corrente; aux->next=corrente; aux=corrente; Enterdata(); } } Exercício 1)Converta a estrutura simplesmente encadeada para duplamente encadeada todas as operações.] <insert> <search> <Printer> <Remove> if inicio==Null{ corrente=Malloc...; corrente->next=Null;

corrente->back=Null; inicio=corrente; auxiliary=corrente; Enterdata(); }

else{ corrente=(no*)Malloc...; auxiliar->next=corrente; corrente->back=auxiliar; auxiliar=corrente; fim=corrente; corrente->next=Null; Enterdata();

Remoção aux=aux->next; aux->back=corrente;

aux=corrente; corrente->next=aux-next;

Remove {escopo

corrente=inicio; auxiliar=inicio; printf(“Entre com o código a ser removido”); scanf(xcod); if(corrente->código==xcod){

Page 7: Estruturas em dados (linguagem c)

achou=1; inicio=inicio->next; corrente->next=null; inicio->back=null; free(corrente); }

Else{ Corrente=corrente->next; } While corrente->next=null{

If(corrente->codigo=xcod){ Corrente=corrente->next; Corrente->back=auxiliary; Corrente=auxiliary->next; Achou=1; Auxiliary->next=corrente->next; Corrente->next=null; Free(corrente); }

Else{ Corrente=corrente->next; Auxiliary=auxiliary->next; }

} If(corrente->codigo==xcod){

Corrente->back=null; Auxiliary->next=null; Free(corrente); Achou=1; }

If(achou==0){ Printf(“Registro não encontrado…”); } }

Estrutura de Dados <<Simulado>>

1) Descreva as modalidades de ponteiros bem como suas funções. Ponteiro de estrutura – são ponteiros que fazem parte di registro, que tem a função de armazenar endereços dos nós(seguinte/anterior) permitindo o encadeamento. Ponteiro auxiliar – são ponteiros que auxilia as operações durante o processamento como: encadeamento/locação de memória/recuperação de dados. Ponteiro Sentinela – são ponteiros que atuam no inicio ou fim da estrutura permitindo ser referencia para os demais ponteiros.

2) Quais operações permitidas em listas? Inserção, consulta, remoção, impressão e alteração.

3) Converta semanticamente uma lista duplamente Encadeada para circular. Inicio->back=fim; Fim->next=inicio;

4) De que forma ocorre alocação de memória aos ponteiros, bem como acesso aos dados. Alocação ocorre de forma aleatória, e o acesso aos dados de forma seqüencial.

5) Ponteiro de Estrutura armazena o que? Endereço de memória.

Page 8: Estruturas em dados (linguagem c)

6) Explique a técnica de Encadeamento. Para que possamos manter a integridade dos dados em uma lista, é necessário ocorrer o encadeamento entre os nodos, ou seja, registros. Ex : Aux corrente {Este processo ocorre com o posicionamento da variável ponteiro anterior concatenada com o ponteiro da estrutura no qual recebe/armazena o endereço de corrente. Ex: aux->next=corrente.

7) Dentre as estruturas vistas, o que difere entre elas? É o modelo de gerenciamento de entrada/saída dos dados.

8) Descreva as semânticas para: a) Alocar endereço ao ponteiro;

corrente=(no*)malloc(sizeof(no)); b) Encadeamento entre um registro e outro;

auxiliar->next=corrente; corrente->back=auxiliar;

c) Saltar o ponteiro para a próxima posição; corrente=auxiliar->next; auxiliar=auxuliar->next;

9) Listas é aplicada em que segmento computacional? Gerenciamento de arquivos em meio magnético, gerenciamento de registros em arquivos.

10) Descreva as particularidades entre variáveis estáticas e dinâmicas. Variáveis estáticas - são variáveis que quando submetida a compilação ganha endereço de memória, permanecendo até o final do processamento. Variável Dinâmica – são variáveis que quando submetida a compilação não ganha endereço de memória, exceto na execução. Durante a execução ela pode disponibilizar o endereço alocado bem como ocupá-lo, tornando dinâmico o processo de otimizar recurso de memória.

11) O comando pré definido null tem qual finalidade? O atributo null tem a finalidade de atribuir nada para variável ponteiro, posicionando a variável dinâmica para a posição nula.

12) Quantos bytes ocupa variável dinâmica na memória? 4 bytes.

Pilhas Fundamentos Uma pilha é um tipo especial de lista linear em que todas as operações de inserção e remoção são realizadas numa mesma extremidade denominada topo. Cada vez que um novo elemento deve ser inserido na pilha, ele é colocado no topo, e em qualquer momento, apenas aquele posicionado no topo da pilha pode ser removido. Devido a esta disciplina de acesso os elementos são sempre removidos numa ordem inversa aquela em que foram inseridos, de modo que o último elemento que entra, será o primeiro que sai. Daí o fato de estas listas serem também denominadas Listas LIFO(last-in/first-out). Por definição , uma lista LIFO é uma estrutura dinâmica, ou seja, é uma coleção que pode aumentar e diminuir durante a sua existência.

Page 9: Estruturas em dados (linguagem c)

Uma pilha suporta quais operações: Push – insere elementos na pilha; Pop – remove elemento na pilha; Top – exibe o topo da pilha; NPR �Notação Polonesa Reversa, foi desenvolvida com a finalidade das expressões matemáticas aceitarem o símbolo parênteses. Para isso foi necessário estabelecer as notações: Infixa: o operador aparece entre osoperandos (A+B) Prefixa: o operador precede os operandos(+AB) Posfixa: o operador segue os operandos(AB+)

infixa Posfixa

A+B-C ABC-+

(A+B)-(Y*K) AB+YK*-

J*((P/C)+(K-L)) JPC/KL-+*

_____________

((B-J)+(K*A)/P)

Simbolo Ação Pilha Saida

( ignora - -

( ignora - -

B copia - B

- empilha - B

J copia - BJ

) descarrega BJ-

+ empilha + BJ-

( ignora + BJ-

K copia + BJ-K

* empilha +* BJ-K

A copia +* BJ-KA

) desenpilha + BJ-KA*

Regras

a) Parênteses de fechamento descarrega o ultimo operador da pilha; b) Parênteses de abertura ignora; c) Operador copia para a pilha; d) Operando copia para a saída;

Desenvolva a rotina POP, baseada em pilha.

Fila – É uma estrutura linear que permite apenas duas operações como:

Page 10: Estruturas em dados (linguagem c)

a) Enqueue b) Dequeue Desenvolva estas de forma dinâmica. c) Sequeue

A fila também conhecida como queue utilizadas no gerenciamento e controle de processo, desempenha importante função para os ambientes timesharing tem como denominação de (first-in/fist-out) FITO. Primeiro a entrar será o primeiro a sair. Inicio {out} Final {in} Fila – organizar os processos bem como obter sua identidade com relação a sua função. Job – são filas estabelecidas por profissionais de TI para efetuar tarefas como compilação/execução/impressão entre outros serviços.

Árvores Fundamentos Uma arvore é uma coleção finita de n>=0 nodos. Se n=0, dizemos que a árvore é nula; caso contrário uma arvore apresenta as seguintes características. - Existe um nodo especial denominado Raiz; - Os demais são particionados em T1...T2...Tn, estruturas disjuntas de arvores. - As estruturas T1...T2...Tn denominam-se subarvores. A exigência de que as estruturas T1...T2...Tn sejam coleções disjuntas, garante que um mesmo nodo não aparecerá em mais de uma subarvore ao mesmo tempo, ou seja, nunca teremos subarvores interligadas. Representação gráfica de uma árvore.

A estrutura de uma árvore ocorre da seguinte forma: Grau – Corresponde ao numero de dependente ligados diretamente ao nó não possui dependente dizemos que o nó é folha ou grau zero. Nível – Corresponde o nível em que o nó se encontra na arvore. Altura – Corresponde o nível máximo que a arvore possui, neste caso podemos afirmar que a arvore acima possui altura “4”.

1. Exercício: Conforme a tabela abaixo complete:

Símbolo GRAU Nível

c

A

B

Page 11: Estruturas em dados (linguagem c)

L

d

Árvores – Listas Generalizadas.

Uma lista generalizada é uma estrutura bastante conveniente para representar árvores. Devido a sua flexibilidade, as listas generalizadas podem armazenar árvores de qualquer grau. Exemplo:

Representação: T:[a,[b[e]],[c],[d,[f],[g]]]

Head – representa a raiz de uma subarvore Tail – representa as subarvores da raiz de Head/Tree. Exercícios Conforme exemplo acima, desenhe um código que permita inserir em cada nó três dependentes, ficando a cargo do usuário determinar o modelo de encadeamento a ser inserido através da função conio:

Arvore Binária A exigência de que T1...T2 sejam estruturas distintas garantindo que um mesmo modo não aparecerá em mais de uma subárvore ao mesmo tempo, ou seja, numa teremos subarvores interligadas no Exemplo abaixo as duas subarvores são distintas:

Page 12: Estruturas em dados (linguagem c)

Na arvora binária é um caso especial de arvore em que nenhum nodo tem mais de dois filhos. Adicionalmente para a arvore binária exixte um “senso de posição”, ou seja, sistingue-se entre subarvores esquerda e uma direita. Uma arvore de busca binária, cuja a raiz armazena o elemento R, é denominada arvore de busca binária. Para isso é necessário aplicação uma regra durante a inserção dos dados:

− todo elemento armazenado na subarvore esquerda é menor que R;

− nenhum elemento armazenado na subarvore direita é menor que R;

− As subarvores esquerda e direita também conhecidas como arvora de busca binária; Busca Binaria – organização indexada

{ 9 ,16 . 4 . 7 . 21. 8. 33 . 9 } 1º 2º 3º 4º 5º 6º 7º 8º

Espalhamento – hashing Seja P o conjunto que contém todos os elementos de um determinado universo, possivelmente infinito chamamos de Espalhamento (ou hashing) ao particionamento de P em um número finito de classes P1, P2, P3...Pn>1. Aplicabilidade do Espalhamento Em termos práticos a grande vantagem do espalhamento está no fato de que dado um elemento K de um conjunto P, o valor de hashing pode ser calculado em tempo constante, fornecimento imediatamente a classe da partição de P em que o elemento se encontra. Se considerarmos P uma coleção de elementos a ser pesquisada, é fácil perceber que o processo será muito mais eficiente se a pesquisa for retrita a uma pequena parte do conjunto P. Exemplo:

Page 13: Estruturas em dados (linguagem c)

Aplicando hashing

Modelo de divisão inteira O método da divisão consiste basicamente em realizar uma divisão inteira e tomar o seu resto. Para entendermos melhor como se funciona vamos espalhar os seguintes números numa coleção de 5 chaves. Pascal function dh(chv:interger):interger Begin dh:=(chv mod N)+1; End; Visão: dh(54) = (54 mod 5)+1=5 dh(46) = (46 mod 5)+1=2 dh(78) = (78 mod 5)+1=4 C int dh (int chv, int N){ return((chv%N)+1); } Transformação de chave Alfanumérica Pascal function adh(chv:string):integer; var i, soma:interger; Begin soma:=0; for i:=1 to length(chv) do soma:=soma+ord(chv[i]); adh:=(soma mod N)+1; End; End; C #include<string.h> int adh(char string[100],int N){ int i, soma=0; for (i=0; i<=strlen(string); i++)

Page 14: Estruturas em dados (linguagem c)

soma=soma+(int)string[i]; return((soma%N)+1); }