Preview only show first 10 pages with watermark. For full document please download

Apostila Estrutura De Dados

Apostila Estrutura de Dados,UNIP

   EMBED


Share

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