A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Artur Henrique Kronbauer

Apresentações semelhantes


Apresentação em tema: "Artur Henrique Kronbauer"— Transcrição da apresentação:

1 Artur Henrique Kronbauer
23/03/2017 Ciência da Computação Estrutura de Dados I Professores: Artur Henrique Kronbauer José Maria David Maria Luiza Braga 1 ola mundo

2 Ponteiros A B X Nome das Variáveis 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 Endereços de Memória 8 1022 5

3 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 aritmético de multiplicação de mesmo símbolo.

4 destino origem m Nome das Variáveis
Ponteiros 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); } m obtém o endereço de memória da variável origem. Declaração de um ponteiro. destino recebe a informação contida no endereço apontado por m. destino origem m Nome das Variáveis Informação de Memória Endereços de Memória 10 1061

5 destino origem end1 end2 Nome das Variáveis
Ponteiros 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. destino recebe a informação contida no endereço apontada por end2. end2 recebe a posição de memória da variável origem que está guardada em end1. destino origem end1 end2 Nome das Variáveis Informação de Memória Endereços de Memória 5.5 1038

6 Ponteiros 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 x (c) p q (d) p q 3 7 5

7 Ponteiros 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; (d) *q = 6; printf ("%d %d \n", *p, *q); (a) p q (b) p q (c) p q (d) p q 5 8 6

8 Vetores – 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 índices informação

9 Vetores – 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); Inclusão das bibliotecas Declaração de uma constante Definição dos protótipos, ou seja, especificação das funções do programa 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); espaco=remove_elemento(vetorA, random(100)); } Declaração das variáveis Inicialização do vetor

10 Vetores – 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) while (vetor[i] != elemento && 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á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 Strings void 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 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 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á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 • Exemplo struct 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á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", , 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 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; Ponteiros usam o operador -> ptr -> mes equivale a nascimento.mes sizeof é o operador que retorna o tamanho de uma variável ou tipo.

17 Estruturas 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 para o primeiro nodo Dados Próximo null nodo

18 Uniõ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õ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 = ; printf("\nAngulo: %f\n",ang.radianos); else printf("\nEntrada invalida!!\n");

20 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 9 8 7 25 5 45 16 2 18 21 índices informação -1 6 4 3 1 próximo Inicio da lista de dados Final da lista de dados Final da lista de endereços

21 Lista 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ática
void 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ática
void 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; vet[ant].prox=vet[atual].prox; devolve_endereco(atual); percorre a lista de dados até achar o elemento procurado ou final da lista Remoção no início Remoção no final Remoção no meio

24 Lista Encadeada em Estrutura Estática
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"); { printf("%d %d \n",vet[atual].info); Percorre a lista de endereços Desafio Reescreva o programa anterior para trabalhar com 3 listas no mesmo vetor. Percorre a lista de dados

25 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).

26 Lista Simplesmente Encadeada em Estrutura Dinâ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 Dinâmica
void 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); Desenvolva essas funções

28 Lista Simplesmente Encadeada em Estrutura Dinâ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 Dinâ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 Dinâmica
void 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"); 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 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 Dados Próximo Anterior nodo

32 Lista Duplamente Encadeada em Estrutura Dinâ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 Dinâmica
void 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 Dinâmica
void 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; } { while ((aux->chave <= atoi(codigo)) && (aux->prox != NULL)) { esquerda=aux; aux=aux->prox;

35 Lista Duplamente Encadeada em Estrutura Dinâ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 Dinâmica
void 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 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 para o primeiro nodo Dados Próximo nodo Cabeça de Lista Ponteiro para o primeiro nodo Ponteiro para o último nodo Dados Próximo Anterior nodo

38 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 Critério de Fila UEPS: dentre os elementos que ainda permanecem no conjunto, o primeiro elemento a ser retirado é o último que tiver sido inserido. PEPS: dentre os elementos que ainda permanecem no conjunto, o primeiro elemento a ser retirado é o primeiro que tiver sido inserido.

39 PEPS (O Primeiro a Entrar é o Primeiro a Sair)
Fila PEPS (O Primeiro a Entrar é o Primeiro a Sair) A B C D E (a) (b) (c) Início Final insere (A) insere (B) insere (C) remove(ponteiro) insere (D) insere (E)

40 Fila 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á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â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); 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); } while (strcmp(opcao,"F") != 0); Exercício p/ os alunos

43 Fila em Estrutura Dinâmica
void 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â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; 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 UEPS (O Último a Entrar é o Primeiro a Sair)
Pilha UEPS (O Último a Entrar é o Primeiro a Sair) A B C D E (a) (b) (c) Início Final insere (A) insere (B) insere (C) remove(ponteiro) insere (D) insere (E)

46 Pilha em 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 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ã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++; como consultar um elemento int desempilha(T_pilha *ppilha) { if (ppilha->topo == 0) { printf("Pilha Vazia"); return(-1); } ppilha->topo--; return(ppilha->valor[ppilha->topo]);

48 Pilha em 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 Pilha em Estrutura Dinâmica
int 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 Recursividade Definição Características de uma função recursiva
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 Recursividade #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"); 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 Recursividade int busca_linear(n,i) int busca_binaria(n,inicio,fim)
{ if ((i < total) && (vet[i] != n)) { i=busca_linear(n,i+1); return(i); } else { if (i == total) return(-1); 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); } 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 Definição: Terminologia:
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 Representação Estrutural: A B C D E F G H I J K
Á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 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 Representação Estrutural: 5 8 2 7
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 8 A B C D E F G

57 Á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ão Aloque (a); Setinfo(a, dado); /* retorna a.informacao <- dado */ constroi (esquerda(a)); constroi (direita(a)); fim senão p <- NULO; Fim-se Fim.

58 Árvores Binárias - Construção
tipo 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 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 Se (lado = e) então /* esquerda */ Se (dado <> '.‘) então 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 */ Setdir (p, NULO); p <- topo(s); Desempilha (s); senão /* direita*/ q <- p; Aloque (p); Setdir (q, p); Setinfo (p, dado); lado <- e; fim /* fim Se lado = e */ fim /* fim enqto. pilha vazia */ senão /* dado = '.' */ a <- NULO; 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
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 (Centro, Esquerda, Direita) 3º. Sub-árvore dir. em pré-ordem Em Ordem 1º. Sub-árvore esq. em ordem 2º. visitamos a raiz (Esquerda, Centro, Direita) 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 (Esquerda, Direita, Centro) 3º. Visitamos a raiz

60 Árvores Binárias - Percurso
Exemplos: 5 4 9 8 10 2 6 7 3 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 10 5 15 19 18 2 17 12 4 20 6 7 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
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
#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); 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) As chamadas de pré-ordem e pós-ordem foram suprimidas por serem iguais.

63 Á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("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; 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); 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
T_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); { 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)

65 Árvores Binárias de Pesquisa
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; } raiz=NULL; rem=rem->pai; printf("Elemento não encontrado"); Remove logicamente 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; Remove fisicamente Remove fisicamente a raiz Exercício Modificar o programa para que use o campo deletado definido na estrutura da arvore.

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 ? 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 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 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 Rotação a Direita Rotação a Esquerda e a Direita
Exemplos de Rotações ( Rotação simples a direita): Exemplos de Rotações ( Rotação dupla a direita): 4 2 3 10 6 8 Rotação a Direita Rotação a Esquerda e a Direita

70 Árvores AVL Rotação a Esquerda Rotação a Direita e a Esquerda
Exemplos de Rotações (rotação simples a esquerda) : Exemplos de Rotações ( Rotação dupla a esquerda): 10 15 Rotação a Esquerda 8 12 4 9 5 10 25 20 30 10 Rotação a Direita e a Esquerda 25 5 20 30 Inserir 25

71 Árvores AVL void mostra_dados(T_nodo *); #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; 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); auxiliar para propagar verificação de Fator de Balanceamento

72 Árvores AVL T_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; case -1: pt=caso1(pt); Inserção dos Elementos Recursão Esquerda Verificar Balanceamento Era mais alto a direita, equilibrou Ficou com a esquerda maior Interrompe Balanceamento Constata caso1

73 Á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; case 1 : pt=caso2(pt); } 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 T_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) pt->f_esq=ptu->f_dir; ptu->f_dir=pt; 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) pt->f_dir=ptu->f_esq; ptu->f_esq=pt; return ptu; Caso2.1- sinais iguais e positivos Caso1.1- sinais iguais e negativos Caso2.2- sinais diferentes Caso1.2- sinais diferentes

75 Árvores AVL T_nodo *rotacao_dir_esq(T_nodo *pt)
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; 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; ptu->bal=0; return ptv; }

76 Árvores AVL 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); } 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 Definição: Características:
É 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: Exemplo: Árvore B (ordem 2): 30
K1 K Km P0 P1 P2 ... Pm-1 Pm 30 27 29 Raiz

79 Árvores – B : Operações Inserção: Algoritmo Simplificado de Pesquisa:
x - argumento de pesquisa Ki - 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 35 40 22 26 Inserção da chave 22 K1 K Km P0 P1 P2 ... Pm-1 Pm

80 Árvores – B : Operações Inserção – 3 etapas: Algoritmo Simplificado:
(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: 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 Senão Substitui x por adjacente; REMOVE(adjacente, no); fim. 20 60 5 15 Remoção da chave 60 80 90

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++; if (x -> chave == Ptr -> r[i-1].chave) { *x == Ptr -> r[i-1]; 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
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.


Carregar ppt "Artur Henrique Kronbauer"

Apresentações semelhantes


Anúncios Google