Transcript
Estrutura de Dados Engenharia da Computação
Artur Henrique Kronbauer 1
Ponteiros • Definição – Ponteiros são endereços, isto é, são variáveis que contém um endereço de memória. Se uma variável contém o endereço de outra, então a primeira (o ponteiro) aponta para a segunda.
A
B
5
8
1022
X 1022
1038 1042 1061 1084 1092
Nome das Variáveis Informação de Memória Endereços de Memória
– “X” o “ponteiro”, aponta para o “inteiro” A. – São ferramentas que nos possibilitam manipular endereços de memória e informações contidas nesses endereços.
2
Ponteiros • Operadores
– & - (E comercial) - fornece o endereço de determinada variável. Atribui o endereço de uma variável para um ponteiro. Obs: Não confundir com o operador lógico de operações de baixo nível, de mesmo símbolo. – * - (Asterisco) – permite acessar o conteúdo de uma variável, cujo endereço é o valor do ponteiro. Devolve o valor endereçado pelo ponteiro. Obs: Não confundir com o operador multiplicação de mesmo símbolo.
aritmético
de
3
Ponteiros • Exemplo 1: Utilização dos operadores & e *. #include ;
Declaração de um ponteiro.
Main() m obtém o endereço de memória { int destino, origem; variável origem. int *m; origem = 10; destino recebe a m = &origem; informação contida no endereço apontado por m. destino = *m; printf(“O resultado é : %i”,destino); }
destino origem 10
1038
10
1061
m
Nome das Variáveis
1061
Informação de Memória Endereços de Memória
1092
da
4
Ponteiros • Exemplo 2: Atribuição de ponteiros Declaração ponteiros.
dos
end2 recebe a posição de memória da variável origem que está guardada em end1.
#include ; Main() { float destino, origem; end1 recebe o endereço de float *end1, *end2; memória da variável origem. origem = 5.5; end1 = &origem; destino recebe a informação end2 = end1; contida no endereço apontada por end2. destino = *end2; printf(“O resultado é : %f”,destino); }
destino origem end1 end2 5.5
5.5
1038
1022
1038
1084
1038
1092
Nome das Variáveis Informação de Memória Endereços de Memória
5
Ponteiros e as Funções malloc e free • malloc(): Essa função serve para atribuir a um ponteiro uma determinada região de memória de acordo com o tipo do ponteiro. – malloc() está definido na biblioteca stdlib.h do C • Veja o código a seguir: main() { int *p, *q; int x; p = (int *) malloc (sizeof (int)); *p = 3; q = p; printf ("%d %d \n", *p, *q); x = 7; *q = x; printf ("%d %d \n", *p, *q); p = (int *) malloc (sizeof (int)); *p = 5; printf ("%d %d \n", *p, *q); getchar();
(a) (b) (c) (d)
(a) p q
3
(b) P q
x 7
7
x (c) p
q
7
7 x
(d) p
5
q
7
7
} 6
Ponteiros e as Funções malloc e free • Free: Essa função serve para liberar para o sistema operacional uma determinada região de memória alocada por um ponteiro.
• Veja o Código a seguir:
(a) (b) (c) (d)
main() { int *p, *q; int x; p = (int *) malloc (sizeof (int)); *p = 5; q = (int *) malloc (sizeof (int)); *q = 8; free(p); p = q; q = (int *) malloc (sizeof (int)); *q = 6; printf ("%d %d \n", *p, *q); getchar(); }
(a) p
5
(b) p
q
8
q
8
(c) p q (d) p
8
8
q
6
7
Vetores – Estruturas Estáticas • Definição – São tipos de dados compostos ou estruturados. – É um conjunto finito e ordenado de dados. – São chamadas de estruturas estáticas porque não podem mudar de tamanho durante a execução do programa, ou seja, preservam o tamanho definido pelo programador no momento do desenvolvimento do software. – São formados por índices e informações. • Índices: Definem as posições de armazenamento da estrutura • Informações: São os dados armazenados e identificados pelos índices. 0
1
2
3
4
5
6
7
8
9
índices
5
7
25
10
18
21
6
14
4
1
informação
8
Vetores – Estruturas Estáticas • Exemplo de manipulação de vetores #include #define MAX 4
int insere_elemento(int [], int); int remove_elemento(int[], int);
Inclusão das bibliotecas
Declaração de uma constante Definição dos protótipos, ou seja, especificação das funções do programa
main() { int vetorA[MAX], numero, espaco=0, I, aux, n; for (I=0; I < MAX; vetorA[I++]=0); printf("\n Geracao do vetor : \n "); do { aux = rand(); printf("\n %d",aux); espaco=insere_elemento(vetorA, aux); } while (espaco == 0); printf("\n Entre com o elemento a ser removido\n"); scanf("%d",&n); if (remove_elemento(vetorA, n) == 0 ) { printf("\n Elemento removido\n"); } else { printf("\n Elemento nao encontrado\n"); } getchar(); }
Declaração das variáveis Inicialização do vetor
9
Vetores – Estruturas Estáticas int insere_elemento(int vetor[MAX], int elemento) Parâmetros recebidos { int i=0; while (vetor[i] != 0 && i < MAX) i++; if (i >= MAX) return(1); // indica que não existe mais espaço else Inserção do novo elemento vetor[i]=elemento; return(0); // inserção bem sucedida } Tipo de retorno da função int remove_elemento(int vetor[MAX], int elemento) { int i=0; while (vetor[i] != elemento && i < MAX) i++; if (i >= MAX) return(1); // indica elemento não encontrado vetor[i]=0; return(0); // remoção bem sucedida } 10
Vetores – Estruturas Estáticas • Operações com strings de caracteres •
Concatenação de Strings
#include
concatena(char s1[], char s2[]); main()
concatena(char s1[], char s2[])
{ int i, j;
{ char p1[20], p2[20];
for (i=0; s1[i]!= '\0';i++);
printf("\n Digite a primeira palavra \n");
for (j=0; s2[j]!= '\0';s1[i++]=s2[j++]);
scanf("%s",&p1);
s1[i++]='\0';
printf("\n Digite a segunda palavra \n");
printf("\n A palavra ficou %s",s1);
scanf("%s",&p2); concatena(p1,p2);
}
getchar(); }
11
Ponteiros e Vetores •
Definição : Inicialmente temos que esclarecer que o nome de um vetor é um ponteiro. Dessa forma podemos trabalhar com vetores de duas formas. veja os códigos a seguir. main () { float vet[10], *p; main () int i; { float vet[10]; p=vet; int i; for (i=0;i<10;i++) for (i=0;i<10;i++) { *p=0.0; { vet[i]=0.0; p++; printf("\n %f",vet[i]); } } for (i=0;i<10;i++) getchar(); { printf("\n %f",vet[i]); } p++; } getchar(); } a – No 1 código, cada vez que se faz vet[i] o programa tem que calcular o deslocamento para dar ao ponteiro. Ou seja, o programa tem que calcular 10 deslocamentos. No segundo o único cálculo que deve ser feito é o de um incremento de ponteiro, que é muito mais rápido que calcular 10 deslocamentos completos. 12
Ponteiros e Vetores • Manipulação de vetores através de ponteiros – Sabemos agora que, na verdade, o nome de um vetor é um ponteiro constante. Sabemos também que podemos indexar o nome de um vetor. Como conseqüência podemos também indexar um ponteiro qualquer. Veja o código a seguir. main() { int vet [10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int *p; p=vet; printf ("\n O terceiro elemento do vetor e: %d",p[2]);
Mostra 3
printf ("\n O quinto elemento do vetor e: %d",*(p+4));
Mostra 5
printf ("\n O setimo elemento do vetor e: %d",vet[7]);
Mostra 8
getchar(); } Podemos ver que p[2] equivale a *(p+2) que equivale a vet[2]. 13
Estruturas – tipos definidos pelos usuários • Definição – Uma estrutura agrupa várias variáveis numa só. Funciona como uma ficha pessoal que tenha nome, telefone e endereço. A ficha seria uma estrutura. A estrutura, então, serve para agrupar um conjunto de dados não similares, formando um novo tipo de dados.
• Declaração struct nome_do_tipo_da_estrutura { tipo_1 nome_1; tipo_2 nome_2; ... tipo_n nome_n; } variáveis_estrutura;
•
Exemplo struct conta { int num_conta; char tipo_conta; char nome[80]; float saldo; }; struct conta clientenovo, clienteant;
– No exemplo foram declaradas duas variáveis, clientenovo e clienteant que são do tipo da estrutura, isto é, possuem os campos num_conta, tipo_conta, nome e saldo. 14
Estruturas – Tipos definidos pelos usuários • Uma estrutura pode conter outra estrutura. struct data { int mes; int dia; int ano; };
struct conta { int num_conta; int tipo_conta; char nome[80]; float saldo; struct data ultpag; }
• Inicializando estruturas – struct conta cliente = {12345, 'R', "Joao", 586.30, 5, 24, 30};
• Processando uma estrutura – Acessando num_conta: cliente.num
– Acessando o 3a caracter do vetor nome: cliente.nome[2]
• O uso do operador ponto pode ser estendido a vetores – struct conta cliente[100]; – número da conta do 14o cliente: cliente[13].num_conta – mês do último pagamento do 14o cliente: cliente[13].ultpag.mes 15
Estruturas e Ponteiros •
Os ponteiros para uma estrutura funcionam como os ponteiros para qualquer outro tipo de dados. struct data Ponteiros usam o { int mes; operador -> int dia; int ano; } nascimento, *ptr; ptr -> mes equivale a nascimento.mes
• Possibilidades de definição dos ponteiros. – A primeira é aponta-lo para uma variável struct já existente, da seguinte maneira: struct data nascimento; sizeof é o operador que struct data *ptr; retorna o ptr = &nascimento; – A segunda é alocando memória usando malloc():
tamanho de uma variável ou tipo.
data *ptr = (struct data *) malloc (sizeof (data)); ptr->dia=15; 16
Estruturas auto-referenciais •
Estruturas auto-referenciais são estruturas que possuem um ponteiro como campo do tipo da própria estrutura.
•
Definição struct tag { membro 1; membro 2; ... struct tag *nome; };
•
•
Exemplo struct lista_elem { char item[40]; struct lista_elem *prox; }
Exemplo da aplicabilidade. – Listas Encadeadas
Cabeça da Lista Ponteiro para o primeiro nodo
nodo Dados Próximo
nodo Dados Próximo
nodo
nodo
Dados Próximo
Dados Próximo
null
17
Lista Encadeada em Estrutura Estática • Definição – Como uma lista é apenas um conjunto de nós, um vetor de nós é uma das formas de representa-lá. Entretanto, os nós não podem ser ordenados pelos índices do vetor; cada um deve conter em si mesmo um ponteiro para o seu sucessor. – A forma mais coerente de representar a estrutura é ter uma lista de endereços e uma lista de dados no mesmo vetor. Ambas as listas são acessadas através de variáveis inteiras indicando o início e o final de cada lista. No final de cada lista o campo próximo é igualado a –1.
• Representação Estrutural Inicio da lista de endereços 0
1
2
3
4
5
6
7
8
9
índices
21
18
2
16
45
5
25
7
8
9
informação
1
3
5
4
6
7
-1
8
9
-1
Inicio da lista de dados
Final da lista de dados
próximo
Final da lista de endereços 18
Lista Encadeada em Estrutura Estática #include void inicializa_enderecos(); int obtem_endereco(); void incluir(int, int); void excluir(int); void devolve_endereco(int); void mostra_dados(); const espaco=10; struct nodo { int info; int prox; } typedef T_nodo; T_nodo vet[10]; int inicio1=-1, fim1=-1; int inicio2=-1, fim2=-1;
main() { char op[1]; int informacao,endereco; inicializa_enderecos(); do { printf("\n (I)ncluir (E)xcluir (F)inalizar : "); gets(op); if (strcmp(op,"i")==0 || strcmp(op,"e")==0) { printf("\n Entre com o numero : "); scanf("%d",&informacao); if (strcmp(op,"i")==0) { endereco=obtem_endereco(); if (endereco != -1) incluir(endereco,informacao); } else if (strcmp(op,"e")==0) { excluir(informacao); } mostra_dados(); } } while (strcmp(op,"f")!=0); }
19
Lista Encadeada em Estrutura Estática void inicializa_enderecos() laço para inicializar a lista de endereços { int i; for (i=0; i < espaco; i++) { vet[i].info=i; vet[i].prox=i+1; marca o final da } lista de endereços vet[espaco-1].prox=-1; inicio1=0; inicializa o início e o fim fim1=espaco-1; da lista de endereços } pega um endereço do int obtem_endereco() início da lista de endereços { int end; end=vet[inicio1].info; if (inicio1 == -1) { printf("\n Estouro de capacidade"); return -1; atualiza o início da } lista de endereços else { inicio1=vet[inicio1].prox; return end; } }
inicializa o início da lista de dados
void incluir(int end, int n) { if (inicio2 == -1) indexa a última inicio2=end; informações a else nova vet[fim2].prox=end; fim2=end; vet[end].info=n; atualiza o fim vet[end].prox=-1; da lista } void devolve_endereco(int end) { vet[end].prox=vet[inicio1].info; inicio1=end; aponta o vet[inicio1].info=end; endereço } atualiza a informação no início da lista de endereços
devolvido, p/ o início da lista de endereços
20
Lista Encadeada em Estrutura Estática void excluir(int n) { int atual=inicio2; int ant=inicio2; while ((vet[atual].info != n) && (vet[atual].prox != -1)) { ant=atual; atual=vet[atual].prox; } if (vet[atual].info != n) printf("\n Elemento Não Encontrado"); else { if (atual == inicio2) Remoção no início { inicio2=vet[atual].prox; if (atual == fim2) fim2=-1; } else if (atual == fim2) Remoção no final { fim2=vet[ant].prox; vet[ant].prox=-1; } else Remoção no meio vet[ant].prox=vet[atual].prox; devolve_endereco(atual); } }
percorre a lista de dados até achar o elemento procurado ou final da lista
21
Lista Encadeada em Estrutura Estática void mostra_dados() { int aux1=inicio1; int aux2=inicio2; printf("\n Lista de Endereços"); while (aux1 != -1) { printf("\n %d %d",vet[aux1].info,vet[aux1].prox); aux1=vet[aux1].prox; } Percorre a lista de getchar(); endereços printf("\n Lista de Dados"); while (aux2 != -1) { printf("\n %d %d",vet[aux2].info,vet[aux2].prox); aux2=vet[aux2].prox; } }
• Desafio Reescreva o programa anterior para trabalhar com 3 listas no mesmo vetor.
Percorre a lista de dados
22
Lista Simplesmente Encadeada em Estrutura Dinâmica • Definição – É uma seqüência de estruturas (elementos) interligados, com a capacidade de inserção e remoção em qualquer posição da lista. – A cabeça da lista (nó descritor) contém um ponteiro para o primeiro elemento da lista (nodo), que armazena um conjunto de dados e um ponteiro para o nodo seguinte. Esse nodo, da mesma forma, armazena um item de dados e um ponteiro para o nodo seguinte, e assim por diante. O último nodo possui um ponteiro NULL para indicar o final da lista.
• Critério – O critério utilizado em listas determina que as inserções e remoções podem ser realizadas em qualquer posição da lista. Por conveniência utilizaremos a inserção por ordem de chave (informação única que distingue um elemento de outro).
23
Lista Simplesmente Encadeada em Estrutura Dinâmica #include typedef struct nodo { int info; struct nodo *prox; } T_lista; typedef struct cab_lista { struct nodo *inicio; struct nodo *fim; int qtd; } T_cabeca; T_cabeca *cabeca; void inserir(int n); T_lista *obtem_endereco(); int pesquisa(int n); void remover(int n); void mostra(); T_cabeca *ini_cabeca();
void mostra() { T_lista *aux = cabeca->inicio; printf("\n Dados atuais da lista \n"); while (aux != NULL) { printf("\n %d",aux->info); aux=aux->prox; } getchar(); } int consulta(int n) { T_lista *atual = cabeca->inicio; while ((atual != NULL) && (atual->info != n)) atual = atual->prox; if (atual == NULL) return -1; // pesquisa mal sucedida else return atual->info; // pesquisa bem sucedida }
24
Lista Simplesmente Encadeada em Estrutura Dinâmica T_cabeca *ini_cabeca() { cabeca=(T_cabeca *) malloc(sizeof(struct cab_lista)); if (cabeca == NULL) { printf("\n Memória insuficiente para alocar estrutura"); exit(1); } cabeca->inicio=NULL; cabeca->fim=NULL; cabeca->qtd=0; return cabeca; } T_lista *obtem_endereco() { T_lista *novo; novo=(T_lista *) malloc(sizeof(struct nodo)); if (novo == NULL) { printf("\n Memória insuficiente para alocar estrutura"); exit(1); } return(novo); }
25
Lista Simplesmente Encadeada em Estrutura Dinâmica void inserir(int n) { T_lista *atual, *aux; T_lista *novo = obtem_endereco(); if (cabeca->inicio == NULL) { cabeca->fim = novo; cabeca->inicio = novo; novo->prox=NULL; } else { atual=cabeca->inicio; aux = cabeca->inicio; while ((atual != NULL) && (atual->info < n)) { aux = atual; atual=atual->prox; } if ((atual != NULL) && (atual->info == n)) { printf("\n Elemento ja existente"); return; }
else if (atual == cabeca->inicio) { novo->prox=cabeca->inicio; cabeca->inicio = novo; } else if (atual == NULL) { novo->prox = NULL; cabeca->fim->prox = novo; cabeca->fim = novo; } else { novo->prox = atual; aux->prox = novo; } } cabeca->qtd++; novo->info=n; } 26
Lista Simplesmente Encadeada em Estrutura Dinâmica void remover(int n) { T_lista *aux = cabeca->inicio; T_lista *atual=cabeca->inicio; while ((atual != NULL) && (atual->info != n)) { aux=atual; atual=atual->prox; } if (atual == NULL) // não encontrou o elemento { printf("\n Elemento nao encontrado"); return ; } if (atual == cabeca->inicio) // vai remover o primeiro elemento da lista { cabeca->inicio=atual->prox; if (atual == cabeca->fim) // vai remover o único elemento da lista cabeca->fim=NULL; } else if (atual == cabeca->fim) // vai remover o último elemento da lista { cabeca->fim=aux; cabeca->fim->prox=NULL; } else // vai remover no meio da lista aux->prox = atual->prox; free(atual); cabeca->qtd--;
27
Lista Simplesmente Encadeada em Estrutura Dinâmica main() { int n; char opcao; cabeca= ini_cabeca(); do { printf("\n (I)ncluir (E)xcluir (C)consultar (F)inalisar : "); scanf("%c",&opcao); if ((opcao != 'f') && (opcao != 'F')) { printf("\n Entre com a informacao : "); scanf("%d",&n); if ((opcao == 'i') || (opcao == 'I')) inserir(n); else if ((opcao == 'e') || (opcao == 'E')) remover(n); else if ((opcao == 'c') || (opcao == 'C')) { if (consulta(n) != -1) printf("\n Elemento Encontrado"); else printf("\n Elemento Nao Encontrado"); getchar(); } mostra(); } } while ((opcao != 'f') && (opcao != 'F')); }
28
Lista Duplamente Encadeada • Definição – Em algumas aplicações que utilizam listas encadeadas pode ser de extrema necessidade percorre-lá da esquerda para a direita, bem como da direita para a esquerda. Este tipo de estrutura é chamada de Lista Duplamente Encadeada. – A cabeça da lista contém dois ponteiros, um para o primeiro elemento da lista e outro para o último elemento da lista. Os nodos devem ter dois ponteiros, um para o próximo nodo e um para o nodo anterior.
• Representação Estrutural Cabeça de Lista Ponteiro para o primeiro nodo Ponteiro para o último nodo
null
nodo
nodo
nodo
nodo
Dados Próximo Anterior
Dados Próximo Anterior
Dados Próximo Anterior
Dados Próximo Anterior
null
29
Lista Duplamente Encadeada em Estrutura Dinâmica #include typedef struct nodo { int info; struct nodo *prox; struct nodo *ant; } T_lista; typedef struct cab_lista { struct nodo *inicio; struct nodo *fim; int qtd; } T_cabeca; T_cabeca *cabeca; void inserir(int n); T_lista *obtem_endereco(); int pesquisa(int n); void remover(int n); void mostra(); T_cabeca *ini_cabeca();
void mostra() { T_lista *aux = cabeca->inicio; printf("\n Dados atuais da lista \n"); while (aux != NULL) { printf("\n %d",aux->info); aux=aux->prox; } getchar(); } int consulta(int n) { T_lista *atual = cabeca->fim; while ((atual != NULL) && (atual->info != n)) atual = atual->ant; if (atual == NULL) return -1; // indica pesquisa mal sucedida else return atual->info; // indica pesquisa bem sucedida } 30
Lista Duplamente Encadeada em Estrutura Dinâmica T_cabeca *ini_cabeca() { cabeca=(T_cabeca *) malloc(sizeof(struct cab_lista)); if (cabeca == NULL) { printf("\n Memória insuficiente para alocar estrutura"); exit(1); } cabeca->inicio=NULL; cabeca->fim=NULL; cabeca->qtd=0; return cabeca; } T_lista *obtem_endereco() { T_lista *novo; novo=(T_lista *) malloc(sizeof(struct nodo)); if (novo == NULL) { printf("\n Memória insuficiente para alocar estrutura"); exit(1); } return(novo); }
31
Lista Duplamente Encadeada em Estrutura Dinâmica void inserir(int n) { T_lista *novo = obtem_endereco(); T_lista *atual, *aux; if (cabeca->inicio == NULL) { cabeca->fim = novo; cabeca->inicio = novo; novo->prox=NULL; novo->ant=NULL; } else { atual = cabeca->inicio; aux = cabeca->inicio; while ((atual != NULL) && (atual->info < n)) { aux = atual; atual=atual->prox; } if ((atual != NULL) && (atual->info == n)) { printf("\n Elemento ja existente"); return; }
else if (atual == cabeca->inicio) { novo->prox=cabeca->inicio; atual->ant=novo; cabeca->inicio = novo; } else if (atual == NULL) { novo->prox = NULL; novo->ant = aux; cabeca->fim->prox = novo; cabeca->fim = novo; } else { novo->prox = atual; novo->ant = aux; aux->prox = novo; atual->ant = novo; } } cabeca->qtd++; novo->info=n; 32
Lista Duplamente Encadeada em Estrutura Dinâmica void remover(int n) { T_lista *atual=cabeca->inicio; T_lista *anterior, *posterior; while ((atual != NULL) && (atual->info != n)) atual=atual->prox; if (atual == NULL) { printf("\n Elemento Inexistente"); return; } if (atual == cabeca->inicio) { cabeca->inicio=atual->prox; if (atual == cabeca->fim) cabeca->fim=NULL; else cabeca->inicio->ant=NULL; } else if (atual == cabeca->fim) { cabeca->fim=cabeca->fim->ant; cabeca->fim->prox=NULL; }
else { anterior=atual->ant; posterior=atual->prox; anterior->prox=posterior; posterior->ant=anterior; } cabeca->qtd--; }
33
Listas Circulares • •
Definição : Em algumas aplicações que utilizam listas encadeadas pode ser de extrema necessidade que o último nodo aponte para o primeiro. Este tipo de estrutura é chamada de Lista Circular. Representação Estrutural da lista Circular Cabeça da Lista Ponteiro para o primeiro nodo
•
nodo
nodo
Dados Próximo
Dados Próximo
nodo
nodo
Dados Próximo
Dados Próximo
Representação Estrutural da lista Circular Duplamente Encadeada Cabeça de Lista Ponteiro para o primeiro nodo Ponteiro para o último nodo
nodo
nodo
nodo
nodo
Dados Próximo Anterior
Dados Próximo Anterior
Dados Próximo Anterior
Dados Próximo Anterior
– Obs: É necessário usar um contador a medida que caminha na lista para comparar com a quantidade de elementos existentes a fim de saber se chegou no final da lista. 34
Filas e Pilhas • Definição – Para determinadas aplicações é imposto um critério que restringe a inserção/retirada dos elementos que compõem um conjunto de dados. •
Critério de Pilha
UEPS:
•
dentre os elementos que ainda permanecem no conjunto, o primeiro elemento a ser retirado é o último que tiver sido inserido.
Critério de Fila PEPS:
dentre os elementos que ainda permanecem no conjunto, o primeiro elemento a ser retirado é o primeiro que tiver sido inserido.
35
Fila • PEPS (O Primeiro a Entrar é o Primeiro a Sair) Início
Final A Início
B
Início
C
(a)
B
insere (A) insere (B) insere (C) Final remove(ponteiro)
C
(b)
B
Final C
D
E
insere (D) insere (E)
(c)
36
Fila em Estrutura Estática #include #define MAXFILA 10 typedef struct fila { int elemento[MAXFILA]; int inicio; int fim; int total; } T_fila; T_fila *inicializaFila(); void insere_fila(int, T_fila *); int retira_fila(T_fila *); void mostra_dados(T_fila *);
main() { char opcao; int valor; T_fila *pfila; pfila=inicializaFila(); do { printf("\n (I)ncluir (E)xcluir (F)inalisar : "); scanf("%c",&opcao); if ((opcao == 'I') || (opcao == 'i')) { printf("\n Entre com o numero a incluir : "); scanf("%d",&valor); insere_fila(valor,pfila); } else if ((opcao == 'E') || (opcao == 'e')) { valor = retira_fila(pfila); } if ((opcao != 'F') || (opcao != 'f')) { mostra_dados(pfila); getchar(); } } while ((opcao != 'F') && (opcao != 'f')); }
37
Fila em Estrutura Estática T_fila *inicializaFila() { T_fila *nova_fila; nova_fila=(T_fila *) malloc(sizeof(struct fila)); if (nova_fila == NULL) { printf("Não existe memória para criar a estrutura"); exit(1); } nova_fila->inicio=0; nova_fila->fim=0; nova_fila->total=0; return(nova_fila); } void insere_fila(int valor, T_fila *pfila) { if (pfila->total == MAXFILA)) { printf("\n Fila Cheia"); return; } pfila->elemento[pfila->fim] = valor; pfila->fim = (pfila->fim + 1) % MAXFILA; 38
Fila em Estrutura Estática int retira_fila(T_fila *pfila) { int valor; if (pfila->total == 0) { printf("\n Fila Vazia"); return(-1); } valor = pfila->elemento[pfila->inicio]; pfila->inicio=(pfila->inicio+1) % MAXFILA; pfila->total--; return(valor); } void mostra_dados(T_fila *pfila) { int aux = pfila->inicio; printf("\n Dados existentes na fila"); while (aux != pfila->fim) { printf("\n %d",pfila->elemento[aux]); aux = (aux+1) % MAXFILA; } }
39
Fila em Estrutura Dinâmica #include
typedef struct nodo { int
info;
struct nodo *prox; } T_nodo; typedef struct cab_fila { struct nodo *inicio; struct nodo *fim; } T_fila; T_fila * inicializa_fila(); T_nodo *obtem_endereco(); void insere(int, T_fila *); int retira(T_fila *); void mostra_dados(T_fila *);
main() { char opcao; int valor; T_fila *pfila; pfila=inicializa_fila(); do { printf("\n (I)ncluir (E)xcluir (F)inalisar : "); scanf("%c",&opcao); if ((opcao == 'I') || (opcao == 'i')) { printf("\n Entre com o numero a incluir : "); scanf("%d",&valor); insere(valor,pfila); } else if ((opcao == 'E') || (opcao == 'e')) { retira(pfila); } if ((opcao != 'F') || (opcao != 'f')) { mostra_dados(pfila); getchar(); } } while ((opcao != 'F') && (opcao != 'f')); } 40
Fila em Estrutura Dinâmica T_fila * inicializa_fila() { T_fila *nova_fila =(T_fila *) malloc(sizeof(struct cab_fila)); if (nova_fila == NULL) { printf("Memória insuficiente para alocar estrutura"); exit(1); } nova_fila->inicio=NULL; nova_fila->fim=NULL; return(nova_fila); } T_nodo *obtem_endereco() { T_nodo *novo; novo=(T_nodo *) malloc(sizeof(struct nodo)); if (novo == NULL) { printf("Memória insuficiente para alocar estrutura"); exit(1); } return(novo); }
41
Fila em Estrutura Dinâmica void insere(int valor, T_fila *pfila) { T_nodo *novo; novo=obtem_endereco(); if (pfila->inicio == NULL) { pfila->inicio = novo; pfila->fim=novo; } else { pfila->fim->prox=novo; pfila->fim=novo; } novo->prox=NULL; novo->info=valor; }
int retira(T_fila *pfila) { T_nodo *aux; int valor = -1; if (pfila->inicio == NULL) printf("\n Fila Vazia"); else { aux=pfila->inicio; valor = aux->info; pfila->inicio=aux->prox; free(aux); } return valor; }
void mostra_dados(T_fila *pfila) { T_nodo *aux = pfila->inicio; printf("\n Dados existentes na fila"); while (aux != NULL) { printf("\n %d",aux->info); aux = aux->prox; } } 42
Pilha • UEPS (O Último a Entrar é o Primeiro a Sair) Início
Final A
B (a)
Início A
insere (A) insere (B) insere (C)
C Final
remove(ponteiro)
B (b)
Início A
B
Final D
E
insere (D) insere (E)
(c)
43
Pilha em Estrutura Estática main() { char opcao; int valor; T_pilha *ppilha; ppilha=inicializaPilha(); #define MAXPILHA 10 do typedef struct pilha { printf("\n (E)mpilhar (D)esempilhar (F)inalisar : "); { int elementos[MAXPILHA]; scanf("%c",&opcao); int topo; if ((opcao == 'E') || (opcao == 'e')) } T_pilha; { printf("\n Entre com o numero a incluir : "); scanf("%d",&valor); empilha(valor,ppilha); T_pilha *inicializaPilha(); } void empilha(int, T_pilha *); else if ((opcao == 'D') || (opcao == 'd')) int desempilha(T_pilha *); { valor = desempilha(ppilha); void mostra_dados(T_pilha *); } if ((opcao != 'F') || (opcao != 'f')) { mostra_dados(ppilha); getchar(); } } while ((opcao != 'F') && (opcao != 'f')); #include
}
44
Pilha em Estrutura Estática T_pilha *inicializaPilha() { T_pilha *nova_pilha; nova_pilha=(T_pilha *) malloc(sizeof(struct pilha)); if (nova_pilha == NULL) { printf("\n Nao existe memoria para criar a estrutura"); exit(1); } nova_pilha->topo=0; return(nova_pilha); }
como consultar um elemento
void empilha(int v, T_pilha *ppilha) { if (ppilha->topo >= MAXPILHA) { printf("\n Pilha Cheia"); return; } ppilha->elementos[ppilha->topo] = v; ppilha->topo++; } 45
Pilha em Estrutura Estática int desempilha(T_pilha *ppilha) { if (ppilha->topo == 0) { printf("\n Pilha Vazia"); return(-1); } ppilha->topo--; return(ppilha->elementos[ppilha->topo]); } void mostra_dados(T_pilha *ppilha) { int aux = ppilha->topo-1; printf("\n Dados existentes na pilha"); while (aux != -1) { printf("\n %d",ppilha->elementos[aux]); aux--; } }
46
Pilha em Estrutura Dinâmica main() #include { char opcao; int valor; T_pilha *ppilha; ppilha=inicializaPilha(); do typedef struct nodo { printf("\n (E)mpilhar (D)esempilhar (F)inalisar : "); { int info; scanf("%c",&opcao); struct nodo *prox; if ((opcao == 'E') || (opcao == 'e')) } T_nodo; { printf("\n Entre com o numero a incluir : "); scanf("%d",&valor); typedef struct pilha empilha(valor,ppilha); { struct nodo *topo; } } T_pilha; else if ((opcao == 'D') || (opcao == 'd')) { valor = desempilha(ppilha); void empilha(int, T_pilha *); } int desempilha(T_pilha *); if ((opcao != 'F') || (opcao != 'f')) { mostra_dados(ppilha); T_pilha *inicializaPilha(); getchar(); void mostra_dados(T_pilha *); } } while ((opcao != 'F') && (opcao != 'f')); } 47
Pilha em Estrutura Dinâmica T_pilha *inicializaPilha() {
T_pilha *nova_pilha;
nova_pilha=(T_pilha *) malloc(sizeof(struct pilha)); if (nova_pilha == NULL) { printf("\n Memória insuficiente"); exit(1);
} nova_pilha->topo=NULL;
void empilha(int v, T_pilha *ppilha) { T_nodo *novo; novo=(T_nodo *) malloc(sizeof(struct nodo));
return(nova_pilha);
if (novo == NULL)
}
{ printf("\n Memória insuficiente "); exit(1); } novo->info = v; novo->prox = ppilha->topo; ppilha->topo = novo; } 48
Pilha em Estrutura Dinâmica int desempilha(T_pilha *ppilha)
void mostra_dados(T_pilha *ppilha)
{ int v;
{ T_nodo *aux = ppilha->topo;
T_nodo *aux = ppilha->topo;
printf("\n Dados existentes na pilha");
if (ppilha->topo == NULL)
while (aux != NULL)
{ printf("\n Pilha Vazia");
{ printf("\n %d",aux->info); aux=aux->prox;
return(-1); }
} v = aux->info;
}
ppilha->topo=aux->prox; free(aux); return(v); }
49
Recursividade •
Definição – A recursividade pode ser considerada um método eficaz para resolver um problema originalmente complexo, reduzindo-o em pequenas ocorrências do problema principal. Assim, segue a idéia de dividir para conquistar. Resolvendo, isoladamente, cada uma das pequenas partes, podemos obter a solução do problema original como um todo.
•
Características de uma função recursiva – Definição de parâmetros; – Condição de parada da recursão, para que a rotina não seja chamada infinitamente; – Chamada da função dentro dela própria;
•
Rotinas recursivas e pilhas – O controle de chamadas e de retorno de rotinas é efetuado por uma pilha (criada e mantida dinamicamente pelo sistema). Quando uma rotina é chamada, empilha-se o endereço da rotina e todas as variáveis locais são recriadas. Quando ocorre o retorno da rotina as variáveis locais que foram criadas deixam de existir.
•
Vantagens – Facilidade na resolução de alguns tipos de problemas.
•
Desvantagens – Uso demasiado dos recursos computacionais de um computador.
50
Recursividade #include
if ((op == 'l') || (op == 'L')) indice=busca_linear(numero,0); int busca_linear(int, int); else int busca_binaria(int,int, int); indice=busca_binaria(numero,0,total); int fat(int); if (indice == -1) printf("\n Elemento nao encontrado"); const total=10; else int vet[10]; printf("\n Encontrado no indice : %d",indice); numero=fat(numero); main() printf("\n O fatorial e : %d ",numero); { int i, numero, indice=-1; getchar(); char op; Programa que degetchar(); printf("\n Entre com 10 numeros \n "); monstra Busca Biná} for (i=0; i < total; i++) ria, Busca Linear e Cálculo do Fatorial scanf("%d",&vet[i]); printf("\n Entre com o numero a pesquisar e calcular o fatorial \n "); de forma recursiva. scanf("%d",&numero); printf("\n Qual a pesquisa? (B)inaria ou (L)inear "); scanf("%c",&op);
Para realizar a pesquisa Binária é necessário que o vetor esteja ordenado 51
Recursividade int busca_linear(int n, int i) { if ((i < total) && (vet[i] != n)) return (busca_linear(n,i+1)); else { if (i == total) return(-1); else return(i); } }
int busca_binaria(int n, int inicio, int fim) { int meio; if (inicio <= fim) { meio = (inicio+fim)/2; if (vet[meio] == n) return meio; else if (vet[meio] < n) return busca_binaria(n,meio+1,fim); else return busca_binaria(n,inicio,meio-1); } else return -1; }
Parâmetros int fat(int n) { int res; Variáveis locais if (n == 0) return 1; else Condição de parada { res = fat(n-1); res = res * n; Chamada da própria função return res; } }
52
Árvores • Definição: – –
Relação de hierarquia ou de composição entre os dados (nós). Conjunto finito T de um ou mais nós, tais que: (a) existe um nó denominado raiz da árvore; (b) os demais nós formam m >= 1 conjuntos disjuntos S1,...,Sm, onde cada um desses conjuntos é uma árvore.
–
As árvores Si recebem a denominação de Sub-árvores.
• Terminologia: – – – – – –
Cada nó da árvore é a raiz de uma Sub-árvore. O número de Sub-árvores de um nó é o grau daquele nó. Um nó de grau igual a zero é denominado folha ou nó terminal. A raiz da árvore tem nível 0. Os demais nós: nível = número de "linhas" que o liga à raiz. Altura: nível mais alto da árvore. 53
Árvores • Representação Estrutural: Grau = 3; Nível =0 (raiz)
A C
B E
F
D G
Grau = 1; Nível = 1
H I
J
Grau = 0 (Folha)
Grau = 3; Nível = 2 K
Grau = 0; Nível = 3
Árvore com altura igual a 3.
54
Árvores Binárias • Definição: – Uma árvore binária é uma estrutura de dados útil quando precisam ser tomadas decisões bidirecionais em cada ponto de um processo. – O Grau de cada nó é menor ou igual a 2 (Sub-árvores da esquerda e da direita). – Se grau = 1, deve ser especificado se a sua Sub-árvore é a da esquerda ou a da direita.
– Árvore Estritamente Binária: é a árvore onde todo o nó que não é folha possuí Sub-árvores a esquerda e a direita. – Uma árvore binária completa é uma árvore estritamente binária sendo que todas as folhas devem estar no mesmo nível. 55
Árvores Binárias • Representação Estrutural: Árvore Estritamente Binária
Árvore Binária Completa
4
5
2
8
9
6 5
2
7
1
4
6
9
7 A
B
• • • •
C
Como construir uma árvore? Como percorrer uma árvore ? Aplicações de árvores binárias Exemplos:
E
D
F
G 56
Árvores Binárias - Percurso • A natureza recursiva de uma árvore binária: – Existem três métodos recursivos para que possamos percorrer uma árvore passando por todos os seus elementos: – Em Pré-ordem 1º. visitamos a raiz 2º. Sub-árvore esq. em pré-ordem 3º. Sub-árvore dir. em pré-ordem – Em Ordem 1º. Sub-árvore esq. em ordem 2º. visitamos a raiz 3º. Sub-árvore dir. em ordem. – Em Pós- Ordem 1º. Sub-árvore esq. em pós-ordem 2º. Sub-árvore dir. em pós-ordem 3º. Visitamos a raiz
(Centro, Esquerda, Direita)
(Esquerda, Centro, Direita)
(Esquerda, Direita, Centro)
57
Árvores Binárias - Percurso • Exemplos: 5
4
9
7
2 3
10
Pré-ordem: 5, 4, 2, 3, 9, 7, 6, 8, 10 Em ordem: 2, 3, 4, 5, 6, 7, 8, 9, 10 Pós-ordem: 3, 2, 4, 6, 8, 7, 10, 9, 5
8
6
20 10 5 6
2
4
15 12
7
18
17
19
Pré-ordem: 20, 10, 5, 2, 4, 6, 7, 15, 12, 18, 17, 19 Em ordem: 2, 4, 5, 6, 7, 10, 12, 15, 17, 18, 19, 20 Pós-ordem: 4, 2, 7, 6, 5, 12, 17, 19, 18, 15, 10, 20 58
Árvores Binárias de Pesquisa • Regra Geral de Inserção: – Os valores menores devem ficar a esquerda da raiz e os maiores a direita. – Os valores repetidos não devem ser inseridos. – As inserções sempre são feitas nas folhas, dessa forma, deve se percorrer a árvore até encontrar a folha que será o pai do novo elemento a ser inserido. – O percurso é baseado no valor da informação que está sendo inserida. Se o novo elemento for menor que o nó comparado, deve andar para a esquerda, caso contrário deve andar para a direita.
• Exemplo
•
Exercício: – Crie uma árvore com os seguintes nós: 14, 15, 4, 9, 7, 18, 2, 5, 16, 4, 20, 17, 9, 5.
59
Árvores Binárias de Pesquisa #include
T_arvore *inicializa_arvore(); T_nodo *cria_nodo(int, T_nodo *);
typedef struct nodo
void insere(int, T_arvore *);
{ int
T_nodo *consulta(int, T_arvore *);
info;
struct nodo *pai;
void ordem(T_nodo *);
struct nodo *f_esq;
void pre_ordem(T_nodo *);
struct nodo *f_dir;
void pos_ordem(T_nodo *);
char
void retira(int, T_arvore *);
deletado;
} T_nodo; typedef struct arvore { struct nodo *raiz; int
qtd;
} T_arvore; T_arvore *parvore;
T_arvore *inicializa_arvore() { T_arvore *nova_arvore; nova_arvore=(T_arvore *) malloc(sizeof(struct arvore)); if (nova_arvore == NULL) { printf("\n Memoria insuficiente para alocar estrutura"); exit(1); } nova_arvore->raiz=NULL; nova_arvore->qtd=0; return(nova_arvore); } 60
Árvores Binárias de Pesquisa main() { char opcao; int informacao=0; parvore = inicializa_arvore(); do { printf("\n (I)ncluir (C)onsultar (R)emover (O)rdem Pr(E)-Ordem Po(s)-Ordem (F)im: "); scanf("%c",&opcao); else if ((opcao == 'E')||(opcao == 'e')) if ((opcao == 'I')||(opcao== 'i')) { pre_ordem(parvore->raiz); { printf("\n Entre com a informacao : "); } scanf("%d",&informacao); else if ((opcao == 'S')|| (opcao == 's')) insere(informacao, parvore); { pos_ordem(parvore->raiz); } } else if ((opcao == 'C')||(opcao=='c')) else if ((opcao == 'R')|| (opcao == 'r')) { printf("\n Entre com a informacao : "); { printf("\n Entre com a informacao : "); scanf("%d",&informacao); scanf("%d",&informacao); consulta(informacao,parvore); retira(informacao, parvore); } } else if ((opcao == 'O')||(opcao == 'o')) getchar(); { ordem(parvore->raiz); } while ((opcao != 'F') && (opcao != } 'f')); } 61
Árvores Binárias de Pesquisa T_nodo *cria_nodo(int n, T_nodo *p) { T_nodo *novo; novo=(T_nodo *) malloc(sizeof(struct nodo)); if (novo == NULL) { printf("\n Memoria insuficiente para alocar estrutura");
exit(1); } novo->info=n; novo->pai=p;
novo->f_esq=NULL; novo->f_dir=NULL; novo->deletado='f'; return(novo); }
void pre_ordem(T_nodo *sub_raiz) { if (sub_raiz != NULL) { if (sub_raiz->deletado == 'V') printf("\n * %d",sub_raiz->info); else printf("\n %d",sub_raiz->info); pre_ordem(sub_raiz->f_esq); pre_ordem(sub_raiz->f_dir); } }
62
Árvores Binárias de Pesquisa void insere(int n, T_arvore *parvore) { T_nodo *p, *aux; if (parvore->raiz == NULL) { parvore->raiz = cria_nodo(n,NULL); } else { p=parvore->raiz; aux=parvore->raiz; while (n != p->info && aux != NULL) { p=aux; if (n < p->info) aux = p->f_esq; else aux = p->f_dir; } if (n == p->info) { printf("\n Numero Repetido"); return; }
else if (n < p->info) { p->f_esq=cria_nodo(n, p); } else { p->f_dir=cria_nodo(n, p); }
}
} parvore->qtd++;
void ordem(T_nodo *sub_raiz) { if (sub_raiz != NULL) { ordem(sub_raiz->f_esq); if (sub_raiz->deletado == 'V') printf("\n *%d",sub_raiz->info); else printf("\n %d",sub_raiz->info); ordem(sub_raiz->f_dir); } } 63
Árvores Binárias de Pesquisa void retira(int n, T_arvore *parvore) { T_nodo *aux=parvore->raiz, *remover=parvore->raiz; if (parvore->raiz == NULL) { printf("\n Arvore sem elementos"); } else { while ((aux != NULL) && (n != remover->info)) { remover = aux; if (n < remover->info) aux = remover->f_esq; else aux = remover->f_dir; } if (n == remover->info) { remover->deletado='V'; // remove logicamente parvore->qtd--;
Continuação na próxima transparência 64
Árvores Binárias de Pesquisa while ((remover != NULL) && (remover->deletado == 'V')) { if ((remover->f_esq == NULL) && (remover->f_dir == NULL)) { if (remover != parvore->raiz) { aux=remover->pai; // remove fisicamente um nodo if (aux->f_esq == remover) aux->f_esq=NULL; else aux->f_dir=NULL; } else { parvore->raiz=NULL; // remove fisicamente a raiz } } remover=remover->pai; } } else { }
printf("\n Elemento nao encontrado");
} }
65
Árvores Binárias de Pesquisa T_nodo *consulta(int n, T_arvore *parvore)
else
{ T_nodo *p, *aux;
{ printf("\n Informacao Inexistente");
p=parvore->raiz;
return(NULL);
aux=parvore->raiz; while ((n != p->info) && (aux != NULL)) { p=aux; if (n < p->info)
aux = p->f_esq; else aux = p->f_dir; } if (n == p->info) { if (p->deletado != 'V') printf("\n Informacao Existente"); else
} } void pos_ordem(T_nodo *sub_raiz) { if (sub_raiz != NULL) { pos_ordem(sub_raiz->f_esq); pos_ordem(sub_raiz->f_dir); if (sub_raiz->deletado == 'V') printf("\n *%d",sub_raiz->info); else printf("\n %d",sub_raiz->info); } }
printf("\n Informacao removida logicamente"); return(p); } 66
Árvores AVL • Definição: – Uma árvore AVL é uma árvore binária de busca construída de tal modo que a altura de sua Sub-árvore direita difere da altura da Sub-árvore esquerda de no máximo 1.
• O que pode acontecer quando um novo nó é inserido numa árvore balanceada ? – Nós 9 ou 11 podem ser inseridos sem balanceamento . Sub-árvore com raiz 10 passa a ter uma Sub-árvore e Sub-árvore com raiz 8 vai ficar melhor balanceada ! – Inserção dos nós 1, 3, 5 ou 7 requerem que a árvore seja rebalanceada!
• Fator de Balanceamento de um nó: – É a altura da Sub-árvore direita do nó menos a altura da Sub-árvore esquerda do nó . FB= altura direita - altura esquerda Se todos os FB forem [-1, 0, 1] a árvore está balanceada. 67
Árvores AVL • Rebalanceamento: – Nos casos abaixo considere P como sendo o nó raiz de uma Subárvore desbalanceada e U como sendo o nó filho dessa raiz.
– Caso 1: Altura Esquerda de P > Altura Direita de P • Caso 1.1 : Altura Esquerda de U > Altura Direita de U Rotação a direita
• Caso 1.2 : Altura Esquerda de U < Altura Direita de U Rotação para a esquerda e em seguida para a direita 68
Árvores AVL – Caso 2: Altura Direita de P > Altura Esquerda de P • Caso 1.2: Altura Direita de U > Altura Esquerda de U
Rotação a esquerda
• Caso 2.2 : Altura Esquerda de U > Altura Direita de U
Rotação para a direita e em seguida para a esquerda
69
Árvores AVL – Exemplos de Rotações ( Rotação simples a direita): 4
Rotação a Direita
2
8
3
6
1 0
– Exemplos de Rotações ( Rotação dupla a direita):
Rotação a Esquerda e a Direita
70
Árvores AVL – Exemplos de Rotações (rotação simples a esquerda) : 1 0
Rotação a Esquerda
1 5
8
4
1 2
9
– Exemplos de Rotações ( Rotação dupla a esquerda): 1 0 5
1 0
2 0
Rotação a Direita e a Esquerda
3 0 25
Inserir 25
2 5
5
2 0
3 0
71
Árvores AVL #include #define true 0 #define false 1 typedef struct nodo { int info; int bal; struct nodo *f_esq; struct nodo *f_dir; int deletado; }T_nodo; T_nodo *raiz; int h;
auxiliar para propagar verificação de Fator de Balanceamento
void mostra_dados(T_nodo *); T_nodo *cria_nodo(int); T_nodo *insere_AVL(int, T_nodo *); T_nodo *caso1(T_nodo *); T_nodo *caso2(T_nodo *); T_nodo *rotacao_direita(T_nodo *); T_nodo *rotacao_esq_dir(T_nodo *); T_nodo *rotacao_esquerda(T_nodo *); T_nodo *rotacao_dir_esq(T_nodo *); main() { int numero=0, achou; raiz=NULL; do { printf("\n Entre com a informacao ou –1 p/ sair : "); scanf("%i",&numero); if (numero != -1) { raiz=insere_AVL(numero,raiz); mostra_dados(raiz); } } while (numero != -1); } 72
Árvores AVL T_nodo *insere_AVL(int x, T_nodo *pt) { if (pt == NULL) Inserção dos Elementos { pt = cria_nodo(x); h=true; } else Recursão Esquerda { if (x < pt->info) { pt->f_esq=insere_AVL(x,pt->f_esq); if (h == true) Verificar Balanceamento { switch (pt->bal) { case 1 : pt->bal = 0; Era mais alto a direita, equilibrou h=false; break; Ficou com a esquerda maior case 0 : pt->bal = -1; Interrompe break; Balanceamento case -1: pt=caso1(pt); Constata caso1 h=false; break; } } 73
Árvores AVL else { if (x > pt->info) Recursão Direita { pt->f_dir = insere_AVL(x,pt->f_dir); if (h == true) Verificar Balanceamento { switch (pt->bal) { case -1: pt->bal=0; Era mais alto a esquerda, equilibrou h=false; break; Ficou com a direita maior case 0 : pt->bal=1; break; Constata caso2 case 1 : pt=caso2(pt); h=false; break; } } } else printf("informação já existente"); } } return pt; }
74
Árvores AVL T_nodo *caso1(T_nodo *pt) { T_nodo *ptu; Caso1.1- sinais ptu=pt->f_esq; iguais e negativos if (ptu->bal == -1) pt=rotacao_direita(pt); else pt=rotacao_esq_dir(pt); pt->bal=0; Caso1.2- sinais return pt; diferentes }
T_nodo *caso2(T_nodo *pt) { T_nodo *ptu; Caso2.1- sinais iguais e positivos ptu=pt->f_dir; if (ptu->bal == 1) pt=rotacao_esquerda(pt); else pt=rotacao_dir_esq(pt); pt->bal=0; Caso2.2- sinais return pt; diferentes }
T_nodo *rotacao_direita(T_nodo *pt) { T_nodo *ptu; ptu=pt->f_esq; pt->f_esq=ptu->f_dir; ptu->f_dir=pt; pt->bal=0; return ptu; }
T_nodo *rotacao_esquerda(T_nodo *pt) { T_nodo *ptu; ptu=pt->f_dir; pt->f_dir=ptu->f_esq; ptu->f_esq=pt; pt->bal=0; return ptu; } 75
Árvores AVL T_nodo *rotacao_esq_dir(T_nodo *pt) { T_nodo *ptu, *ptv; ptu=pt->f_esq; ptv=ptu->f_dir; ptu->f_dir=ptv->f_esq; ptv->f_esq=ptu; pt->f_esq=ptv->f_dir; ptv->f_dir=pt; if (ptv->bal == -1) pt->bal=1; else pt->bal=0; if (ptv->bal == 1) ptu->bal=-1; else ptu->bal=0; return ptv; }
T_nodo *rotacao_dir_esq(T_nodo *pt) { T_nodo *ptu, *ptv; ptu=pt->f_dir; ptv=ptu->f_esq; ptu->f_esq=ptv->f_dir; ptv->f_dir=ptu; pt->f_dir=ptv->f_esq; ptv->f_esq=pt; if (ptv->bal == 1) pt->bal=-1; else pt->bal=0; if (ptu->bal == -1) ptu->bal=1; else ptu->bal=0; return ptv; } 76
Árvores AVL T_nodo *cria_nodo(int n) { T_nodo *novo; novo=(T_nodo *) malloc(sizeof(struct nodo)); if (novo == NULL) { printf("Memória insuficiente"); exit(1); } novo->info=n; novo->bal=0; novo->f_esq=NULL; novo->f_dir=NULL; novo->deletado='f'; return(novo); }
void mostra_dados(T_nodo *sub_raiz) { if (sub_raiz != NULL) { mostra_dados(sub_raiz->f_esq); mostra_dados(sub_raiz->f_dir); printf("\n%d",sub_raiz->info); } } função recursiva para percorrer a árvore. Baseada na função pós-ordem
77
Árvores - B • Definição: – É a Construção e manutenção de árvores de busca de grandes dimensões. – Ponteiros referem-se a áreas de memória secundária, em vez de representarem endereços da memória principal. – Busca: acesso a disco (com os inerentes atrasos de acesso). – Sub-árvores representadas em unidades, do ponto de vista de acesso páginas – Reduz o número de acessos ao disco. – Necessita de esquema de crescimento controlado. – Todo nó, exceto a raiz, deve possuir entre n e 2n chaves, para uma dada constante n.
• Características: – Cada página (nó) contém no máximo, 2n elementos (chaves); – cada página, exceto a que contém a raiz, contém no mínimo n chaves; – os nós chamados folhas não têm descendentes e os demais(nós de derivação) possuem m + 1 descendentes, onde m é a quantidade de chaves; – todas as folhas têm o mesmo nível. 78
Árvores - B • Representação Estrutural:
K1 P0
K2 P1
... ...
P2
Km Pm-1
Pm
• Exemplo: Árvore B (ordem 2): Raiz
30 15
2689
22
17 18 20 21
40 50
27 29
36 38 39
42 45 48
51 53 55 56
79
Árvores – B : Operações • Inserção: 20
20 30
Inserção da chave 22 7 10 15 18
26 30 35 40
7 10 15 18
22 26
35 40
• Algoritmo Simplificado de Pesquisa: x - argumento de pesquisa Ki - valores das chaves dos nós de derivação
K1 P0
K2 P1
P2
... ...
Km Pm-1
Pm
(i) Se Ki < x < Ki+1; seguir Pi (ii) Se x < K1; seguir P0 (iii) Se x > Km; o caminho será indicado por Pm 80
Árvores – B : Operações • Inserção – 3 etapas: (i) localizar a folha apropriada a partir da raiz; (ii) Se o registro encontra lugar em um nó folha não completamente preenchido =>PROCESSO LIMITADO ÀQUELE NÓ (iii) NÓ COMPLETO => PARTIÇÃO (criação de um novo nó), podendo se propagar até a RAIZ aumentando a altura da árvore.
• Algoritmo Simplificado: INSERE( chave, no) Localizar lugar de inclusão; Se (nó cheio) então Criar novo nó; Divide nó cheio; INSERE (chave-do-meio, nó-de-cima); Senão Coloca chave no nó; Ajusta ponteiros; fim-se; fim. 81
Árvores – B : Operações •
Retirada: A chave a ser retirada pode residir no nó folha ou num nó de derivação.
•
Exemplo:
5 15
•
20
60
30 40 50
Remoção da chave 60
70 80 90
5 15
20
70
30 40 50
80 90
Algoritmo Simplificado: REMOVE( x, no) Se (x está no nó folha) então Retira x; Se (restaram n-1 chaves) então Se (vizinho possui m>n chaves) então Empresta chave do vizinho; Desce chave separadora do nó ascendente substituindo pela emprestada; Senão Concatena nó com o vizinho; Desce chave do meio do nó ascendente; fim-se fim-se Senão Substitui x por adjacente; REMOVE(adjacente, no); fim-se fim. 82
Árvores – B: Implementação em C Pesquisa (Registro *x, Ponteiro Ptr) { int i; if (Ptr == NULL) { printf("Registro não esta presente na arvore \n"); return; } i = 1; while (i < Ptr -> n) && (x -> Chave > Ptr -> r[i-1].chave) i++; typedef struct { if (x -> chave == Ptr -> r[i-1].chave) TipoChave Chave; { *x == Ptr -> r[i-1]; /* - outros componentes - */ return; } Registro; } if (x -> chave < Ptr -> r[i-1].chave) Pesquisa(x, Ptr -> p[i-1]); typedef struct Página_st else *Ponteiro; Pesquisa(x, Ptr -> p[i]); } /* Pesquisa */
typedef struct Página_str { int n; Registro r[mm]; Ponteiro p[mm + 1]; } Página; 83