ciência da computação estrutura de dados i professores: artur henrique kronbauer josé maria...
TRANSCRIPT
Ciência da ComputaçãoCiência da Computação
Estrutura de Dados IEstrutura de Dados I
Professores:Professores:
Artur Henrique KronbauerArtur Henrique Kronbauer
José Maria DavidJosé Maria David
Maria Luiza BragaMaria Luiza Braga
1
2
PonteirosPonteiros
• Definiçã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.
– “X” o “ponteiro”, aponta para o “inteiro” A.
– Possibilitam manipular endereços de memória e informações contidas nesses endereços.
A B X Nome das Variáveis
Informação de Memória
1022 1038 1042 1061 1084 1092 Endereços de Memória
8 10225
3
PonteirosPonteiros
• 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 aritmético de multiplicação de mesmo símbolo.
4
PonteirosPonteiros
• Exemplo 1: Utilização dos operadores & e *.
#include <stdio.h>;void main(){ int destino, origem;
int *m; origem = 10; m = &origem; destino = *m; printf(“Valor da variavel destino:
%i”,destino);}
Declaração de um ponteiro.
m obtém o endereço de memória da variável origem.
destino recebe a informação contida no endereço apontado por m.
destino origem m Nome das Variáveis
Informação de Memória
1038 1061 1092 Endereços de Memória
10 10 1061
5
PonteirosPonteiros
• Exemplo 2: Atribuição de ponteiros
#include <stdio.h>;void main(){ float destino, origem;
float *end1, *end2; origem = 5.5;
end1 = &origem; end2 = end1; destino = *end2; printf(“O resultado é : %f”,destino);
}
Declaração dos ponteiros.
end1 recebe o endereço de memória da variável origem.
end2 recebe a posição de memória da variável origem que está guardada em end1.
destino recebe a informação contida no endereço apontada por end2.
destino origem end1 end2 Nome das Variáveis
Informação de Memória
1022 1038 1084 1092 Endereços de Memória
5.5 1038 10385.5
6
Ponteiros e as Funções malloc e freePonteiros e as Funções malloc e free• malloc(): Essa função atribui 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:
int *p, *q; int x; p = (int *) malloc (sizeof (int)); *p = 3; q = p;(a) printf ("%d %d \n", *p, *q); x = 7; *q = x;(b) printf ("%d %d \n", *p, *q);(c) p = (int *) malloc (sizeof (int));(d) *p = 5;
printf ("%d %d \n", *p, *q);
(a) p
q
(b) P x
q
x
(c) p q
x
(d) p q
3
7 7
7 7
5 77
7
Ponteiros e as Funções malloc e freePonteiros e as Funções malloc e free
• Free: Essa função libera para o sistema operacional uma determinada região de memória alocada por um ponteiro.
• Veja o Código a seguir:
int *p, *q; int x; p = (int *) malloc (sizeof (int)); *p = 5; q = (int *) malloc (sizeof (int));(a) *q = 8;(b) free(p);(c) p = q; q = (int *) malloc (sizeof (int));(d) *q = 6;
printf ("%d %d \n", *p, *q);
(a) p q
(b) p q
(c) p
q
(d) p q
5
8
8
8
6
8
8
Vetores – Estruturas EstáticasVetores – Estruturas Estáticas
• Definição– São tipos de dados compostos ou estruturados.
– É um conjunto finito e ordenado de dados.
– São chamados 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. 1 4 14 6 21 18 10 25 7 5
0 1 2 3 4 5 6 7 8 9 índices
informação
9
Vetores – Estruturas EstáticasVetores – Estruturas Estáticas
• Exemplo de manipulação de vetores
#include <stdio.h>#include <stdlib.h>#define MAX 4
int insere_elemento(int [], int);int remove_elemento(int[], int);
void main(){ int vetorA[MAX], numero, espaco=0, i; for (i=0; i < MAX; vetorA[i++]=0); do
espaco=insere_elemento(vetorA, random(100)); while (espaco == 0); do
espaco=remove_elemento(vetorA, random(100)); while (espaco == 0);}
Inclusão das bibliotecas
Declaração de uma constante
Definição dos protótipos, ou seja, especificação das funções do programa
Inicialização do vetor
Declaração das variáveis
10
Vetores – Estruturas EstáticasVetores – Estruturas Estáticas
int insere_elemento(int vetor[MAX], int elemento){ int i=0; while (vetor[i] != 0 && i < MAX) i++; if (i >= MAX) return(1); // indica que não existe mais espaço else vetor[i]=elemento; return(0); // inserção bem sucedida}
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}
Parâmetros recebidos
Inserção do novo elemento
Tipo de retorno da função
11
Vetores – Estruturas EstáticasVetores – Estruturas Estáticas
• Operações com strings de caracteres
• Exemplo1: Tamanho de uma String
– Em C – Em peseudocódigo
int tamanho(char string[]) inteiro tamanho(caracter string[])
{ int i=0; início
while (string[i] != ‘\0’) enquanto (string[i] <> ‘\0’)
i++; i=i+1;
return i; fim-enquanto;} retorna i;
fim;
• Exemplo2: Concatenação de Stringsvoid concatena(char s1[], char s2[]){ for (int i=0; s1[i]!= ‘\0’;i++); for (int j=0; s2[j]!= ‘\0’;s1[i++]=s2[j++]); s1[i++]=‘\0’ printf("A palavra concatenada é %s",s1);}
12
Ponteiros e VetoresPonteiros e Vetores• Definição
– Na verdade o nome de um vetor é um ponteiro. Portanto, podemos trabalhar com vetores de duas formas abaixo.
void main ()
{ float vet[50];
int i;
for (i=0;i<50;i++)
vet[i]=0.0;
}
– No 1o. 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 50 deslocamentos. No segundo o único cálculo que deve ser feito é o de um incremento de ponteiro, que é muito mais rápido que calcular 50 deslocamentos completos.
void main (){ float vet[50]; float *p; int i; p=vet; for (i=0;i<50;i++) { *p=0.0; p++; }}
13
Ponteiros e VetoresPonteiros e Vetores
• Manipulação de vetores através de ponteiros– Como podemos indexar o nome de um vetor e o nome de
um vetor é um ponteiro constante, então podemos também indexar um ponteiro qualquer.
void main()
{ int vet [10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int *p;
p=vet;
printf ("O terceiro elemento do vetor é: %d",p[2]);
printf ("O quinto elemento do vetor é: %d",*(p+4));
printf ("O sétimo elemento do vetor é: %d",vet[7]);
}
– Podemos ver que p[2] equivale a *(p+2) que equivale a
vet[2].
Mostra 3
Mostra 5
Mostra 8
14
Estruturas – tipos definidos pelos usuáriosEstruturas – 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 • Exemplostruct nome_do_tipo_da_estrutura { tipo_1 nome_1; tipo_2 nome_2; ... tipo_n nome_n; } variáveis_estrutura;
– 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.
struct conta
{ int num_conta;
char tipo_conta;
char nome[80];
float saldo;
};
struct conta clientenovo,
clienteant;
15
Estruturas – Tipos definidos pelos usuáriosEstruturas – Tipos definidos pelos usuários• Uma estrutura pode conter outra estrutura.
struct data struct conta { int mes; { int num_conta;
int dia; char tipo_conta; int ano; 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_conta
– 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
16
Estruturas e PonteirosEstruturas e Ponteiros• Os ponteiros para uma estrutura funcionam como os
ponteiros para qualquer outro tipo de dados. struct data { int mes;
int dia; int ano;} nascimento, *ptr;
• Possibilidades de definição dos ponteiros. – A primeira é apontá-lo para uma variável struct já
existente, da seguinte maneira: struct data nascimento;
struct data *ptr; ptr = &nascimento;
– A segunda é alocando memória usando malloc(): struct data *ptr = (struct data *) malloc (sizeof (struct
data)); ptr->dia=15;
ptr -> mes equivale anascimento.mes
Ponteiros usam o operador ->
sizeof é o operador que retorna o tamanho de uma variável ou tipo.
17
Estruturas auto-referenciaisEstruturas auto-referenciais• Estruturas auto-referenciais são estruturas que possuem
um ponteiro como campo do tipo da própria estrutura.
• Definição • Exemplo struct tag
{ membro 1;membro 2;
...struct tag *nome;
};
• Exemplo da aplicabilidade. – Listas Encadeadas
struct lista_elem{ char item[40]; struct lista_elem *prox;}
Cabeça da Lista
Ponteiro parao primeiro nodo
DadosPróximo
DadosPróximo
DadosPróximo
DadosPróximo null
nodo nodonodonodo
18
UniõesUniões• Definição
– Uma declaração union determina uma única localização de memória onde podem estar armazenadas várias variáveis diferentes. A declaração de uma união é semelhante à declaração de uma estrutura:
union angulo { float graus; float radianos; };
– No exemplo temos duas variáveis (graus e radianos) que, apesar de terem nomes diferentes, ocupam o mesmo local da memória. Isto quer dizer que só gastamos o espaço equivalente a um único float.
– Uniões podem ser criadas também com variáveis de diferentes tipos. Neste caso, a memória alocada corresponde ao tamanho da maior variável no union.
19
UniõesUniões• Exemplo
#include <stdio.h> union angulo { int graus; float radianos; }; void main() { union angulo ang; char op; printf("\nNumeros em graus ou radianos? (G/R):"); scanf("%c",&op); if (op == ‘G’) { ang.graus = 180; printf("\nAngulo: %d\n",ang.graus); } else if (op == ‘R’) { ang.radianos = 3.1415; printf("\nAngulo: %f\n",ang.radianos); } else printf("\nEntrada invalida!!\n"); }
20
Lista EncadeadaLista Encadeada em Estrutura Estáticaem 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
9 8 7 25 5 45 16 2 18 21
0 1 2 3 4 5 6 7 8 9 índices
informação
-1 9 8 -1 7 6 4 5 3 1 próximo
Inicio da lista de dados
Inicio da lista de endereços
Final da lista de endereços
Final da lista de dados
21
Lista Encadeada em Estrutura EstáticaLista Encadeada em Estrutura Estática#include <stdio.h>#include <conio.h>#include <stdlib.h>#include <string.h>
void inicializa_enderecos(void);int obtem_endereco(void);void incluir(int, int);void excluir(int);void devolve_endereco(int);void mostra_dados(void);
const espaco=10;
struct nodo{ int info; int prox;} typedef T_nodo;
T_nodo vet[10];int inicio_led=-1;int inicio_dados=-1;int fim_dados=-1;
void main(){ char op[1]; int informacao,endereco; inicializa_enderecos(); do { printf("(I)ncluir (E)xcluir (F)inalizar :\n"); gets(op); if (strcmp(op,"i")==0 || strcmp(op,"e")==0) { printf("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);}
22
Lista Encadeada em Estrutura EstáticaLista Encadeada em Estrutura Estáticavoid inicializa_enderecos(){ int i; for (i=0; i < espaco; i++) vet[i].prox=i+1; vet[espaco-1].prox=-1; inicio_led=0; }
int obtem_endereco(){ int end; end=inicio_led; if (inicio_led == -1) { gotoxy(20,23); printf("Estouro de capacidade"); return -1; } else { inicio_led=vet[inicio_led].prox; return end; }}
void incluir(int end, int n){ if (inicio_dados == -1) inicio_dados=end; else vet[fim_dados].prox=end; fim_dados=end; vet[end].prox=-1; vet[end].info=n;}
void devolve_endereco(int end){ vet[end].prox=inicio_led; inicio_led=end; }
23
Lista Encadeada em Estrutura EstáticaLista Encadeada em Estrutura Estáticavoid excluir(int n){ int atual=inicio_dados; int ant=inicio_dados; while ((vet[atual].info != n) && (vet[atual].prox != -1)) { ant=atual; atual=vet[atual].prox; } if (vet[atual].info != n) printf("Elemento Não Encontrado"); else { if (atual == inicio_dados) { inicio_dados=vet[atual].prox;
if (atual == fim_dados) fim_dados=-1;
} else if (atual == fim_dados) { fim_dados=ant;
vet[ant].prox=-1; } else vet[ant].prox=vet[atual].prox; devolve_endereco(atual); }}
Remoção no meio
Remoção no início
Remoção no final
percorre a lista de dados até achar o elemento procurado ou final da lista
24
Lista Encadeada em Estrutura EstáticaLista Encadeada em Estrutura Estática
Percorre a lista de endereços
void mostra_dados(){ int atual=inicio_led; printf("Lista de Endereços"); while (atual != -1) { printf("%d \n",vet[atual].prox); atual=vet[atual].prox; } atual=inicio_dados; printf(“\nLista de Dados"); while (atual != -1) { printf("%d %d \n",vet[atual].info); atual=vet[atual].prox; }}
Percorre a lista de dados
• Desafio
Reescreva o programa anterior para trabalhar com 3 listas no mesmo vetor.
25
Lista Simplesmente EncadeadaLista Simplesmente Encadeada em Estrutura em Estrutura DinâmicaDinâ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).
26
Lista Simplesmente Encadeada em Estrutura Lista Simplesmente Encadeada em Estrutura DinâmicaDinâmica
/* include das bibliotecas do C */#include <string.h>#include <stdio.h>#include <conio.h>#include <stdlib.h>#include <alloc.h>#include <process.h>
/* definição da estrutura */typedef struct nodo { int chave;
char pessoa[30];struct nodo *prox;
} T_lista;
struct nodo *inicio=NULL;
/* inclusão de protótipos */
T_lista *obtem_endereco(void);void insere_elemento(char [4], char [30]);void retira_elemento(char [4]);T_lista *consulta_elemento(char[4]); void mostra_dados(void);
27
Lista Simplesmente Encadeada em Estrutura Lista Simplesmente Encadeada em Estrutura DinâmicaDinâmicavoid main()
{ int i; char codigo[4],nome[30], opcao[1]; clrscr(); do { printf("(I)ncluir (E)xcluir (C)consultar (F)inalizar : ");
gets(opcao);printf("Entre com o código da pessoa : ");if (strcmp(opcao,"E") == 0 || strcmp(opcao,"e") == 0){ gets(codigo); retira_elemento(codigo);}else if (strcmp(opcao,"I") == 0 || strcmp(opcao,"i") == 0){ gets(codigo);
printf("Entre com o nome da pessoa.. : "); gets(nome); insere_elemento(codigo,nome);
} else if (strcmp(opcao,"C") == 0 || strcmp(opcao,"c") == 0) // consulta_elemento(codigo); // mostra_dados(); } while (strcmp(opcao,"F") != 0 && strcmp(opcao,"f") != 0); clrscr();}
Desenvolva essas funções
28
Lista Simplesmente Encadeada em Estrutura Lista Simplesmente Encadeada em Estrutura DinâmicaDinâmica
/* função de alocação de uma nova estrutura do tipo celula na memória e obtenção de seu endereço */
T_lista *obtem_endereco(){ T_lista *novo; novo=(T_lista *) malloc(sizeof(struct nodo)); if (novo == NULL) { gotoxy(25,22); printf("Memória insuficiente para alocar estrutura"); exit(1); } return(novo);}
29
Lista Simplesmente Encadeada em Estrutura Lista Simplesmente Encadeada em Estrutura DinâmicaDinâmica
/* função que coloca o elemento dentro da lista em ordem crescente de acordo com o código = chave */
void insere_elemento(char codigo[4], char nome[30]){ T_lista *novo, *aux, *ant; novo=obtem_endereco(); aux=inicio; if ((aux == NULL) || (aux->chave > atoi(codigo))) { inicio = novo; novo->prox=aux; } else { while ((aux->chave <= atoi(codigo)) && (aux != NULL)) { ant=aux; aux=aux->prox; } novo->prox=ant->prox; ant->prox=novo; } novo->chave=atoi(codigo); strcpy(novo->pessoa,nome); }
Inserção no começo
Inserção no meio ou final da lista
30
Lista Simplesmente Encadeada em Estrutura Lista Simplesmente Encadeada em Estrutura DinâmicaDinâmicavoid retira_elemento(char codigo[4])
{ T_lista *ret, *aux; if (inicio == NULL) { printf("Lista Vazia"); return; } ret=inicio; aux=inicio; if (ret->chave == atoi(codigo)) inicio = ret->prox; else { while ((ret->chave != atoi(codigo)) && (ret != NULL)) { aux=ret; ret=ret->prox; } if (ret == NULL) { printf("Elemento Inexistente");
return; } else aux->prox=ret->prox; } free(ret); }
Testa se a lista está vazia
Retira do início da lista
Retira no meio ou final da lista
Testa se a chave pesquisada não existe
Indexa os nodos
Libera da memória
31
Lista Duplamente EncadeadaLista 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 EstruturalCabeça de Lista
Ponteiro parao primeiro nodoPonteiro para oúltimo nodo
nullDadosPróximoAnterior
nodo
DadosPróximoAnterior
nodo
DadosPróximoAnterior
nodo
DadosPróximoAnterior
nodo
null
32
Lista Duplamente Encadeada em Estrutura Lista Duplamente Encadeada em Estrutura DinâmicaDinâmica#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <alloc.h>
#include <process.h>
typedef struct nodo
{ int chave;
char pessoa[30];
struct nodo *prox;
struct nodo *ant;
} T_lista;
typedef struct cab_lista
{ struct nodo *inicio;
struct nodo *fim;
} T_cabeca;
T_cabeca cabeca;
// protótipos do programa
void ini_cabeca();
T_lista *obtem_endereco();
void insere_elemento(char [4], char [30]);
void retira_elemento(char [4]);
T_lista *consulta_elemento(char[4]);
void mostra_dados();
Observação: As rotinas de consultar e mostrar dados devem ser desenvolvidas pelos alunos como exercício.
33
Lista Duplamente Encadeada em Estrutura Lista Duplamente Encadeada em Estrutura DinâmicaDinâmicavoid ini_cabeca()
{ cabeca.inicio=NULL;
cabeca.fim=NULL;
}
T_lista *obtem_endereco()
{ T_lista *novo;
novo=(T_lista *) malloc(sizeof(struct nodo));
if (novo == NULL)
{ printf("Memória insuficiente para alocar estrutura");
exit(1);
}
return(novo);
}
34
Lista Duplamente Encadeada em Estrutura Lista Duplamente Encadeada em Estrutura DinâmicaDinâmicavoid insere_elemento(char codigo[4], char nome[30])
{ T_lista *novo, *aux, *esquerda;
novo=obtem_endereco();
aux=cabeca.inicio;
esquerda=cabeca.inicio;
if ((aux == NULL) || (aux->chave > atoi(codigo)))
{ cabeca.inicio = novo;
novo->prox=aux;
novo->ant=NULL;
if (novo->prox == NULL)
cabeca.fim = novo;
else
aux->ant = novo;
}
else
{ while ((aux->chave <= atoi(codigo)) && (aux->prox != NULL))
{ esquerda=aux;
aux=aux->prox;
}
35
Lista Duplamente Encadeada em Estrutura Lista Duplamente Encadeada em Estrutura DinâmicaDinâmica
if ((aux->prox == NULL) && (aux->chave <= atoi(codigo)))
{ cabeca.fim = novo;
novo->prox = NULL;
novo->ant = aux;
aux->prox = novo;
}
else
{ novo->prox=aux;
novo->ant=esquerda;
aux->ant=novo;
esquerda->prox=novo;
}
}
novo->chave=atoi(codigo);
strcpy(novo->pessoa,nome);
}
36
Lista Duplamente Encadeada em Estrutura Lista Duplamente Encadeada em Estrutura DinâmicaDinâmicavoid retira_elemento(char codigo[4])
{ T_lista *ret, *direita, *esquerda;
if (cabeca.inicio == NULL)
{ printf("Lista Vazia");
return;
}
ret=cabeca.inicio;
if (ret->chave == atoi(codigo))
{ cabeca.inicio=ret->prox;
direita=ret->prox;
direita->ant=NULL;
}
else
{ while ((ret->chave != atoi(codigo)) && (ret != NULL))
{ esquerda=ret;
ret=ret->prox;
}
if (ret == NULL)
{ printf("Elemento Inexistente");
return; }
else
{ esquerda->prox=ret->prox;
direita=ret->prox;
direita->ant=esquerda;
if (ret == cabeca.fim)
cabeca.fim=esquerda;
}
}
free(ret);
}
37
Listas CircularesListas 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
• Representação Estrutural da lista Circular Duplamente Encadeada
Cabeça da Lista
Ponteiro parao primeiro nodo
DadosPróximo
DadosPróximo
DadosPróximo
DadosPróximo
nodo nodonodonodo
Cabeça de Lista
Ponteiro parao primeiro nodoPonteiro para oúltimo nodo
DadosPróximoAnterior
nodo
DadosPróximoAnterior
nodo
DadosPróximoAnterior
nodo
DadosPróximoAnterior
nodo
38
Filas e PilhasFilas 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
• Critério de Fila
UEPSUEPS:: dentre os elementos que ainda permanecemdentre os elementos que ainda permanecemno conjunto, ono conjunto, o primeiro elemento a serprimeiro elemento a serretirado é o retirado é o últimoúltimo que tiver sido inserido. que tiver sido inserido.
PEPSPEPS:: dentre os elementos que ainda permanecemdentre os elementos que ainda permanecemno conjunto, ono conjunto, o primeiro elemento a serprimeiro elemento a ser
rretirado é o etirado é o primeiroprimeiro que tiver sido inserido. que tiver sido inserido.
39
FilaFila
• PEPS (O Primeiro a Entrar é o Primeiro a Sair)
A B C
B C
B C D E
(a)
(b)
(c)
Início Final
Início
Início
Final
Final
insere (A)insere (B)insere (C)
remove(ponteiro)
insere (D)insere (E)
40
Fila em Estrutura EstáticaFila em Estrutura Estática#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#define MAX 10
typedef struct fila
{ int elemento[MAX];
int inicio;
int fim;
int tam;
} T_fila;
T_fila *inicializaFila();
void insere_fila(int, T_fila *);
int retira_fila(T_fila *);
void mostra_dados();
void main()
{ char opcao[1],valor[4];
T_fila *pfila;
pfila=inicializaFila();
do
{ printf("(I)ncluir (E)xcluir (F)inalizar : ");
gets(opcao);
if (strcmp(opcao,"E") == 0 )
itoa(retira_fila(pfila),valor,10);
else if (strcmp(opcao,"I") == 0 )
{ printf("Entre com o nº a incluir : ");
gets(valor);
insere_fila(atoi(valor),pfila);
}
// mostra_dados();
} while (strcmp(opcao,"F") != 0);
}
Exercício p/ os alunos
41
Fila em Estrutura EstáticaFila 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=-1;
nova_fila->tam=0;
return(nova_fila);
}
void insere_fila(int valor, T_fila *pfila)
{ if (pfila->tam == MAX)
{ printf("Fila Cheia");
return;
}
pfila->fim = (pfila->fim + 1) % MAX;
pfila->elemento[pfila->fim] = valor;
pfila->tam++;
}
int retira_fila(T_fila *pfila)
{ int valor;
if (pfila->tam == 0)
{ printf("Lista Vazia");
return(-1);
}
valor = pfila->elemento[pfila->inicio];
pfila->inicio=(pfila->inicio+1) % MAX;
pfila->tam--;
return(valor);
}
42
Fila em Estrutura DinâmicaFila em Estrutura Dinâmica#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
typedef struct nodo
{ int chave;
char pessoa[30];
struct nodo *prox;
} T_fila;
typedef struct cab_lista
{ struct nodo *inicio;
struct nodo *fim;
} T_cabeca;
T_cabeca cabeca;
void ini_cabeca(void);
T_fila *obtem_endereco(void);
void insere(char [4], char [30]);
void retira(void);
void mostra_dados(void);
Exercício p/ os alunos
void main(){ int i; char codigo[4],nome[30], opcao[1]; ini_cabeca(); do
{ printf("(I)ncluir (E)xcluir (F)inalizar : ");
gets(opcao);
if (strcmp(opcao,"E") == 0)
{ retira();
mostra_dados();
}
else if (strcmp(opcao,"I") == 0)
{ printf("Entre com o código da pessoa : ");
gets(codigo);
printf("Entre com o nome da pessoa.. : ");
gets(nome);
insere(codigo,nome);
mostra_dados();
}
} while (strcmp(opcao,"F") != 0);
}
43
Fila em Estrutura DinâmicaFila em Estrutura Dinâmicavoid ini_cabeca()
{ cabeca.inicio=NULL;
cabeca.fim=NULL;
}
T_fila *obtem_endereco()
{ T_fila *novo;
novo=(T_fila *) malloc(sizeof(struct nodo));
if (novo == NULL)
{ printf("Memória insuficiente para alocar estrutura");
exit(1);
}
return(novo);
}
44
Fila em Estrutura DinâmicaFila em Estrutura Dinâmica
void insere(char codigo[4], char nome[30])
{ T_fila *novo;
novo=obtem_endereco();
if (cabeca.inicio == NULL)
{ cabeca.inicio = novo;
cabeca.fim=novo;
}
else
{ cabeca.fim->prox=novo;
cabeca.fim=novo;
}
novo->prox=NULL;
novo->chave=atoi(codigo);
strcpy(novo->pessoa,nome);
}
void retira()
{ T_fila *ret;
if (cabeca.inicio == NULL)
{ printf("Fila Vazia");
return;
}
else
{ ret=cabeca.inicio;
cabeca.inicio=ret->prox;
free(ret);
if (cabeca.inicio==NULL)
cabeca.fim=NULL;
}
}
45
PilhaPilha
• UEPS (O Último a Entrar é o Primeiro a Sair)
A B C
A B
A B D E
(a)
(b)
(c)
Início Final
Início
Início
Final
Final
insere (A)insere (B)insere (C)
remove(ponteiro)
insere (D)insere (E)
46
PilhaPilha em Estrutura Estáticaem Estrutura Estática#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#define MAXPILHA 10
typedef struct pilha
{ int valor[MAXPILHA];
int topo;
} T_pilha;
T_pilha *inicializaPilha();
void empilha(int, T_pilha *);
int desempilha(T_pilha *);
void mostra_dados();
void main()
{ char opcao[1],valor[4];
T_pilha *ppilha;
ppilha=inicializaPilha();
do
{ printf("(I)ncluir (E)xcluir (F)inalizar : ");
gets(opcao);
if (strcmp(opcao,"E") == 0)
itoa(desempilha(ppilha),valor,10);
else if (strcmp(opcao,"I") == 0)
{ printf("Entre com o n§ a incluir : ");
gets(valor);
empilha(atoi(valor),ppilha);
}
// mostra_dados();
} while (strcmp(opcao,"F") != 0);
}
Exercício p/ os alunos
47
PilhaPilha em Estrutura Estáticaem Estrutura EstáticaT_pilha *inicializaPilha()
{ T_pilha *nova_pilha;
nova_pilha=(T_pilha *) malloc(sizeof(struct pilha));
if (nova_pilha == NULL)
{ printf("Não existe memória p/ criar a estrutura");
exit(1);
}
nova_pilha->topo=0;
return(nova_pilha);
}
void empilha(int v, T_pilha *ppilha)
{ if (ppilha->topo >= MAXPILHA)
{ printf("Pilha Cheia");
return;
}
ppilha->valor[ppilha->topo] = v;
ppilha->topo++;
}
int desempilha(T_pilha *ppilha)
{ if (ppilha->topo == 0)
{ printf("Pilha Vazia");
return(-1);
}
ppilha->topo--;
return(ppilha->valor[ppilha->topo]);
}
como consultar um elemento
48
PilhaPilha em Estrutura Dinâmicaem Estrutura Dinâmica#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
typedef struct elemento
{ int valor;
struct elemento *prox;
} T_elemento;
struct elemento *topo=NULL;
void empilha(int, T_elemento *);
int desempilha(T_elemento *);
// void mostra_dados(void);
void main()
{ char opcao[1],valor[4];
pcabeca=ini_cabeca();
do
{ printf("(I)ncluir (E)xcluir (F)inalizar : ");
gets(opcao);
if (strcmp(opcao,"E") == 0)
itoa(desempilha(topo),valor,10);
else if (strcmp(opcao,"I") == 0)
{ printf("Entre com o nº a incluir : ");
gets(valor);
empilha(atoi(valor),topo);
}
// mostra_dados();
} while (strcmp(opcao,"F") != 0);
}
Exercício p/ os alunos
49
PilhaPilha em Estrutura Dinâmicaem Estrutura Dinâmicaint desempilha(T_elemento *ppilha)
{ int v;
if (ppilha == NULL)
{ printf("Pilha Vazia");
return(-1);
}
v = ppilha->valor;
topo=ppilha->prox;
free(ppilha);
return(v);
}
void empilha(int valor, T_elemento *ppilha)
{ T_elemento *novo;
novo=(T_elemento *) malloc(sizeof(struct elemento));
if (novo == NULL)
{ printf(" Memória insuficiente ");
exit(1);
}
novo->valor = valor;
novo->prox = ppilha;
topo = novo;
}
50
RecursividadeRecursividade• Definição
– Pode ser considerada um método eficaz para resolver um problema originalmente complexo, reduzindo-o em pequenas ocorrências do problema principal. Dividie 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.
51
RecursividadeRecursividade
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
int busca_linear(int, int);
int busca_binaria(int,int, int);int fat(int);
const total=10;
int vet[10];
void main()
{ int i, numero, indice;
char op;
printf("Entre com 10 números");
for (i=0; i < total; i++)
scanf("%d",&vet[i]);
printf("Entre com o numero a pesquisar e calcular o fatorial");
scanf("%d",&numero);
printf("Qual a pesquisa? (B)inaria ou (L)inear");
scanf("%c",&op);
if (op == 'l')
indice=busca_linear(numero,0);
else
indice=busca_binaria(numero,0,total);
if (indice == -1)
printf("Elemento não encontrado");
else
printf("Elemento encontrado no ¡ndice : %d",indice);
numero=fat(numero); printf("O fatorial e : %d ",numero);}
Programa que de-monstra Busca Biná-ria, Busca Linear e Cálculo do Fatorial de forma recursiva.
52
RecursividadeRecursividadeint busca_linear(n,i)
{ if ((i < total) && (vet[i] != n))
{ i=busca_linear(n,i+1);
return(i);
}
else
{ if (i == total)
return(-1);
else
return(i);
}
}
int busca_binaria(n,inicio,fim)
{ int meio;
if (inicio <= fim)
{ meio = (inicio+fim)/2;
if (vet[meio] == n)
return meio;
else if (vet[meio] < n)
busca_binaria(n,meio+1,fim);
else
busca_binaria(n,inicio,meio-1);
}
else
return -1;
}
int fat(int n){ int res; if (n == 0) return 1; else { res = fat(n-1); res = res * n; return res; }}
Parâmetros
Variáveis locais
Condição de parada
Chamada da própria função
53
ÁrvoresÁ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.
54
ÁrvoresÁrvores
• Representação Estrutural:
Árvore com altura igual a 3.
A
B C D
E F G H
I J K
Grau = 1; Nível = 1
Grau = 3; Nível = 2
Grau = 0; Nível = 3
Grau = 3; Nível =0 (raiz)
Grau = 0 (Folha)
55
Árvores BináriasÁ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.
56
Árvores BináriasÁrvores Binárias
• Representação Estrutural:
• Como construir uma árvore?• Como percorrer uma árvore ? • Aplicações de árvores binárias• Exemplos:
Árvore Estritamente Binária Árvore Binária Completa
5
2 7
1 4 6 9
4
2 8
9
5
6
7A
B C
D E
F G
57
Árvores Binárias - ConstruçãoÁrvores Binárias - Construção
• Definição:– “Uma árvore binária é formada por um conjunto finito de nós.
Este conjunto ou é vazio, ou consiste de um nó raiz com duas sub-árvores binárias disjuntas, denominadas sub-árvores da esquerda e da direita”.
procedimento constroi (a:arvore)
var s: pilha; dado: info; p, q: ref no;inicio
leia (dado);Se dado <> '.' entãoinicio
Aloque (a); Setinfo(a, dado); /* retorna a.informacao <- dado */ constroi (esquerda(a)); constroi (direita(a));
fimsenão p <- NULO;Fim-se
Fim.
58
Árvores Binárias - ConstruçãoÁrvores Binárias - Construçãotipo no: reg ( esquerda : ref nó;
informação : info;
direita : ref nó)
tipo arvore : ref nó;
procedimento constroi (a:arvore)
var s: pilha; dado: info; p, q: ref no;
Inicio
Inicializa (s);
leia (dado);
Se dado <> '.' então
Inicio
Aloque (p);
a <- p;
Setinfo(p, dado); /* retorna p.informacao <- dado */
lado<- e; /* lado = e ou d */
Empilha (s, p);
Enqto. (pilha não vazia) faça
inicio
leia (dado);
Se (lado = e) então /* esquerda */
Se (dado <> '.‘) então
inicio
q <- p; Aloque (p);
Setesq(q,p); /* q.esquerda <- p */
Setinfo(p,dado); /* p.informacao <- dado
*/
Empilha(s, q);
fim
senão /* esquerda vazia' */ inicio Setesq (p, NULO); lado <- d; fim senão /* lado = d */
Se (dado = '.' ) então /* direita */ inicio Setdir (p, NULO); p <- topo(s); Desempilha (s); fim senão /* direita*/ inicio q <- p; Aloque (p); Setdir (q, p); Setinfo (p, dado); lado <- e; fim fim /* fim Se lado = e */
fim /* fim enqto. pilha vazia */ senão /* dado = '.' */ a <- NULO;fim
Proc Setinfo(p: ref no, dado: info)
p.informacao <- dado;
Proc Setesq(p, q: ref no)
p.esquerda <- q;
Proc Setdir(p, q: ref no)
p.direita <- q;
59
Árvores Binárias - PercursoÁ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é-ordem1º. visitamos a raiz2º. Sub-árvore esq. em pré-ordem (Centro, Esquerda, Direita)3º. Sub-árvore dir. em pré-ordem
– Em Ordem1º. Sub-árvore esq. em ordem2º. visitamos a raiz (Esquerda, Centro, Direita)3º. Sub-árvore dir. em ordem.
– Em Pós- Ordem1º. Sub-árvore esq. em pós-ordem2º. Sub-árvore dir. em pós-ordem (Esquerda, Direita, Centro)3º. Visitamos a raiz
60
Árvores Binárias - PercursoÁrvores Binárias - Percurso
• Exemplos:
5
4 9
8
102
6
7
3
10
5 15
19
182
17
12
4
20
6
7
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
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
61
Árvores Binárias de PesquisaÁ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.
62
Árvores Binárias de PesquisaÁrvores Binárias de Pesquisa#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
typedef struct nodo
{ int info;
struct nodo *pai;
struct nodo *f_esq;
struct nodo *f_dir;
char deletado;
} T_nodo;
T_nodo *raiz;
T_nodo *cria_nodo(int,T_nodo*);
void insere(int);
T_nodo *consulta(int);
void ordem(T_nodo *);
void pre_ordem(T_nodo *);
void pos_ordem(T_nodo *);
void retira(int);
As chamadas de pré-ordem e pós-ordem foram suprimidas por serem iguais.
void main()
{ char opcao[1]; int informacao=0;
do { printf("(I)ncluir (C)onsultar (R)emover
(O)rdem Pr(E)-Ordem Pó(s)-Ordem (F)im: ");
scanf("%s",&opcao);
if ((strcmp(opcao,"I") == 0) || (strcmp(opcao,"C")
== 0) || (strcmp(opcao,"R") == 0))
{ printf("Entre com a informação : ");
scanf("%i",&informacao);
}
if (strcmp(opcao,"I") == 0)
insere(informacao);
else if (strcmp(opcao,"C") == 0)
consulta(informacao);
else if (strcmp(opcao,"O") == 0)
ordem(raiz);
else if (strcmp(opcao,"R") == 0)
retira(informacao);
} while (strcmp(opcao,"F") != 0)
}
63
Árvores Binárias de PesquisaÁrvores Binárias de PesquisaT_nodo *cria_nodo(int n, T_nodo *p)
{ T_nodo *novo;
novo=(T_nodo *) malloc(sizeof(struct nodo));
if (novo == NULL)
printf("Memória insuficiente");
novo->info=n;
novo->pai=p;
novo->f_esq=NULL;
novo->f_dir=NULL;
novo->deletado='f';
return(novo);
}
void insere(int n)
{ T_nodo *p, *aux;
if (raiz == NULL)
raiz = cria_nodo(n,NULL);
else
{ p=raiz;
aux=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("%s","Número Repetido");
else if (n < p->info)
p->f_esq=cria_nodo(n, p);
else
p->f_dir=cria_nodo(n, p); } }
void pre_ordem(T_nodo *sub_raiz){ if (sub_raiz != NULL) { printf("%d\n",sub_raiz->info); ordem(sub_raiz->f_esq); ordem(sub_raiz->f_dir); }}
64
Árvores Binárias de PesquisaÁrvores Binárias de PesquisaT_nodo *consulta(int n)
{ T_nodo *p, *aux;
p=raiz;
aux=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("Informação Existente");
return(p); } else
{ printf("Informação Inexistente");
getch();
return(NULL); }}
void ordem(T_nodo *sub_raiz)
{ if (sub_raiz != NULL)
{ ordem(sub_raiz->f_esq);
printf("%d\n",sub_raiz->info);
ordem(sub_raiz->f_dir);
}
}
void pos_ordem(T_nodo *sub_raiz)
{ if (sub_raiz != NULL)
{ ordem(sub_raiz->f_esq);
ordem(sub_raiz->f_dir);
printf("%d\n",sub_raiz->info);
}
}
65
Árvores Binárias de PesquisaÁrvores Binárias de Pesquisa
void retira(int n)
{ T_nodo *aux=raiz, *rem=raiz;
if (raiz == NULL)
{ printf(“Árvore sem elementos");
return();
}
while ((aux != NULL) &&
(n != rem->info))
{ rem = aux;
if (n < rem->info)
aux = rem->f_esq;
else
aux = rem->f_dir;
}
if (n == rem->info)
{ rem->deletado='V';
while ((rem != NULL) && (rem->deletado == 'V'))
{ if (rem->f_esq = NUL) && (rem->f_dir = NUL)
{ if (rem != raiz)
{ aux=rem->pai;
if (aux->f_esq == rem)
aux->f_esq=NULL;
else
aux->f_dir=NULL;
}
else
raiz=NULL;
}
rem=rem->pai;
}
}
else
printf("Elemento não encontrado");
}
Remove logicamente
Remove fisicamente
Remove fisicamente a raiz
ExercícioModificar o programa para que use o campo deletado definido na estrutura da arvore.
66
Árvores AVLÁ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 ?
• 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.
– 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!
67
Árvores AVLÁ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
• Caso 1.2 : Altura Esquerda de U < Altura Direita de U
Rotação a direita
Rotação para a esquerda e em seguida para a direita
68
Árvores AVLÁrvores AVL
– Caso 2: Altura Direita de P > Altura Esquerda de P• Caso 1.2: Altura Direita de U > Altura Esquerda de U
• Caso 2.2 : Altura Esquerda de U > Altura Direita de U
Rotação a esquerda
Rotação para a direita e em seguida para a esquerda
69
Árvores AVLÁrvores AVL– Exemplos de Rotações ( Rotação simples a direita):
– Exemplos de Rotações ( Rotação dupla a direita):
Rotação aEsquerda ea Direita
Rotação aDireita
4
2
3 10
6
8
70
Árvores AVLÁrvores AVL– Exemplos de Rotações (rotação simples a esquerda) :
– Exemplos de Rotações ( Rotação dupla a esquerda):
Rotação aEsquerda
8
4
10
9
15
12
5
10
25
20
30
Inserir 25Inserir 25
5
10
30
25
20
Rotação aDireita ea Esquerda
71
Árvores AVLÁrvores AVL#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#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 *);
void main()
{ int numero=0, achou;
raiz=NULL;
do { printf("Entre com a informação : ");
scanf("%i",&numero);
if (numero != -1)
{ raiz=insere_AVL(numero,raiz);
mostra_dados(raiz); } } while (numero != -1);
}
72
Árvores AVLÁrvores AVLT_nodo *insere_AVL(int x, T_nodo *pt)
{ if (pt == NULL)
{ pt = cria_nodo(x);
h=true;
}
else
{ if (x < pt->info)
{ pt->f_esq=insere_AVL(x,pt->f_esq);
if (h == true)
{ switch (pt->bal)
{ case 1 : pt->bal = 0;
h=false;
break;
case 0 : pt->bal = -1;
break;
case -1: pt=caso1(pt);
h=false;
break;
}
}
}
Inserção dos Elementos
Recursão Esquerda
Verificar Balanceamento
Interrompe Balanceamento
Ficou com a esquerda maior
Era mais alto a direita, equilibrou
Constata caso1
73
Árvores AVLÁrvores AVL else
{ if (x > pt->info)
{ pt->f_dir = insere_AVL(x,pt->f_dir);
if (h == true)
{ switch (pt->bal)
{ case -1: pt->bal=0;
h=false;
break;
case 0 : pt->bal=1;
break;
case 1 : pt=caso2(pt);
h=false;
break; } } } else
printf("informação já existente"); } } return pt;
}
Recursão Direita
Verificar Balanceamento
Era mais alto a esquerda, equilibrou
Ficou com a direita maior
Constata caso2
74
Árvores AVLÁrvores AVLT_nodo *caso1(T_nodo *pt)
{ T_nodo *ptu;
ptu=pt->f_esq;
if (ptu->bal == -1)
pt=rotacao_direita(pt);
else
pt=rotacao_esq_dir(pt);
pt->bal=0;
return pt;
}
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 *caso2(T_nodo *pt)
{ T_nodo *ptu;
ptu=pt->f_dir;
if (ptu->bal == 1)
pt=rotacao_esquerda(pt);
else
pt=rotacao_dir_esq(pt);
pt->bal=0;
return pt;
}
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;
}
Caso1.1- sinais iguais e negativos
Caso1.2- sinais diferentes
Caso2.1- sinais iguais e positivos
Caso2.2- sinais diferentes
75
Árvores AVLÁ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Árvores AVLvoid 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);
}
}
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);
}
função recursiva para percorrer a árvore. Baseada na função pós-ordem
77
Árvores - BÁ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Árvores - B
• Representação Estrutural:
• Exemplo: Árvore B (ordem 2):
K1 K2 ... KmP0 P1 P2 ... Pm-1 Pm
30
15 22 40 50
17 18 20 212 6 8 9 27 29 36 38 39 42 45 48 51 53 55 56
Raiz
79
Árvores – B : OperaçõesÁrvores – B : Operações• Inserção:
• Algoritmo Simplificado de Pesquisa:
x - argumento de pesquisaKi - valores das chaves dos nós de derivação
(i) Se Ki < x < Ki+1; seguir Pi
(ii) Se x < K1; seguir P0
(iii) Se x > Km; o caminho será indicado por Pm
20
7 10 15 18 26 30 35 40
20 30
7 10 15 18 35 4022 26
Inserção da chave 22
K1 K2 ... KmP0 P1 P2 ... Pm-1 Pm
80
Árvores – B : OperaçõesÁ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Árvores – B : Operações• Retirada: A chave a ser retirada pode residir no nó folha ou num nó de
derivação.
• Exemplo:
• 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-seSenão Substitui x por adjacente; REMOVE(adjacente, no);
fim-sefim.
20 60
5 15 70 80 90
Remoção da chave 60
30 40 50 5 15 80 9030 40 50
20 70
82
Árvores – B: Implementação em CÁrvores – B: Implementação em CPesquisa (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++;if (x -> chave == Ptr -> r[i-1].chave) { *x == Ptr -> r[i-1];
return;}if (x -> chave < Ptr -> r[i-1].chave)
Pesquisa(x, Ptr -> p[i-1]);else
Pesquisa(x, Ptr -> p[i]);
} /* Pesquisa */
typedef struct {TipoChave Chave;/* - outros componentes - */
} Registro;
typedef struct Página_st *Ponteiro;
typedef struct Página_str {int n;Registro r[mm];Ponteiro p[mm + 1];
} Página;
83
Árvores Graduadas e Rubro-NegrasÁrvores Graduadas e Rubro-Negras• Definições:
– Uma árvore binária de busca é graduada quando, para todo nó v (Szwarcfiter e Markenzon, 1994):
• (i) posto(v) = 0, se v é um nó externo;• (ii) posto(v) = 1, se v é pai de nó externo;• (iii) posto(v) < posto(w) < posto(v)+ 1, se w é pai de v;• (iv) posto(v) < posto(w), se v possui avô w.
– Uma árvore binária de busca é rubro-negra quando, para todo nó v existe uma coloração tal que (Szwarcfiter e Markenzon, 1994):
• (i) se v é um nó externo, v é negro;• (ii) os caminhos de v para os seus descendentes nós
externos possuem o mesmo número de nós negros;• (iii) se v (não raiz) é um nó rubro então seu pai, w, é um nó
negro.