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

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

Ciência da Computação Estrutura de Dados I Professores: Artur Henrique Kronbauer José Maria David Maria Luiza Braga 1.

Apresentações semelhantes


Apresentação em tema: "Ciência da Computação Estrutura de Dados I Professores: Artur Henrique Kronbauer José Maria David Maria Luiza Braga 1."— Transcrição da apresentação:

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

2 2 Ponteiros 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

3 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 4 Ponteiros Exemplo 1: Utilização dos operadores & e *. #include ; void main() { int destino, origem; int *m; origem = 10; m = &origem; destino = *m; printf(Valor da variavel destino: %i,destino); } Declaração de um ponteiro. m obtém o endereço de memória da variável origem. destino recebe a informação contida no endereço apontado por m. destino origem m Nome das Variáveis Informação de Memória Endereços de Memória

5 5 Ponteiros Exemplo 2: Atribuição de ponteiros #include ; void main() { float destino, origem; float *end1, *end2; origem = 5.5; end1 = &origem; end2 = end1; destino = *end2; printf(O resultado é : %f,destino); } Declaração dos ponteiros. end1 recebe o endereço de memória da variável origem. end2 recebe a posição de memória da variável origem que está guardada em end1. destino recebe a informação contida no endereço apontada por end2. destino origem end1 end2 Nome das Variáveis Informação de Memória Endereços de Memória

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

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

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

9 9 Vetores – Estruturas Estáticas Exemplo de manipulação de vetores #include #define MAX 4 int insere_elemento(int [], int); int remove_elemento(int[], int); void main() { int vetorA[MAX], numero, espaco=0, i; for (i=0; i < MAX; vetorA[i++]=0); do espaco=insere_elemento(vetorA, random(100)); while (espaco == 0); do espaco=remove_elemento(vetorA, random(100)); while (espaco == 0); } Inclusão das bibliotecas Declaração de uma constante Definição dos protótipos, ou seja, especificação das funções do programa Inicialização do vetor Declaração das variáveis

10 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) { int i=0; while (vetor[i] != elemento && i < MAX) i++; if (i >= MAX) return(1); // indica elemento não encontrado vetor[i]=0; return(0); // remoção bem sucedida } Parâmetros recebidos Inserção do novo elemento Tipo de retorno da função

11 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 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 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 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 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 3 a 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 14 o cliente: cliente[13].num_conta –mês do último pagamento do 14 o cliente: cliente[13].ultpag.mes

16 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; ptr -> mes equivale a nascimento.mes Ponteiros usam o operador -> sizeof é o operador que retorna o tamanho de uma variável ou tipo.

17 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 Dados Próximo Dados Próximo Dados Próximo null nodo

18 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 19 Uniões Exemplo #include 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 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 índices informação próximo Inicio da lista de dados Inicio da lista de endereços Final da lista de endereços Final da lista de dados

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

24 24 Lista Encadeada em Estrutura Estática Percorre a lista de endereços void mostra_dados() { int atual=inicio_led; printf("Lista de Endereços"); while (atual != -1) { printf("%d \n",vet[atual].prox); atual=vet[atual].prox; } atual=inicio_dados; printf(\nLista de Dados"); while (atual != -1) { printf("%d %d \n",vet[atual].info); atual=vet[atual].prox; } Percorre a lista de dados Desafio Reescreva o programa anterior para trabalhar com 3 listas no mesmo vetor.

25 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 26 Lista Simplesmente Encadeada em Estrutura Dinâmica /* include das bibliotecas do C */ #include /* 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 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); clrscr(); } Desenvolva essas funções

28 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 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 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"); return; } else aux->prox=ret->prox; } free(ret); } Testa se a lista está vazia Retira do início da lista Retira no meio ou final da lista Testa se a chave pesquisada não existe Indexa os nodos Libera da memória

31 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 Dados Próximo Anterior nodo Dados Próximo Anterior nodo Dados Próximo Anterior nodo null

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

35 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 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 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 Dados Próximo Dados Próximo Dados Próximo nodo Cabeça de Lista Ponteiro para o primeiro nodo Ponteiro para o último nodo Dados Próximo Anterior nodo Dados Próximo Anterior nodo Dados Próximo Anterior nodo Dados Próximo Anterior nodo

38 38 Filas e Pilhas Definição –P ara 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, oprimeiro elemento a ser retirado é o primeiro que tiver sido inserido. retirado é o primeiro que tiver sido inserido.

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

40 40 Fila em Estrutura Estática #include #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 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 42 Fila em Estrutura Dinâmica #include typedef struct nodo { int chave; char pessoa[30]; struct nodo *prox; } T_fila; typedef struct cab_lista { struct nodo *inicio; struct nodo *fim; } T_cabeca; T_cabeca cabeca; void ini_cabeca(void); T_fila *obtem_endereco(void); void insere(char [4], char [30]); void retira(void); void mostra_dados(void); Exercício p/ os alunos void main() { int i; char codigo[4],nome[30], opcao[1]; ini_cabeca(); do { printf("(I)ncluir (E)xcluir (F)inalizar : "); gets(opcao); if (strcmp(opcao,"E") == 0) { retira(); mostra_dados(); } else if (strcmp(opcao,"I") == 0) { printf("Entre com o código da pessoa : "); gets(codigo); printf("Entre com o nome da pessoa.. : "); gets(nome); insere(codigo,nome); mostra_dados(); } } while (strcmp(opcao,"F") != 0); }

43 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 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; cabeca.fim=novo; } novo->prox=NULL; novo->chave=atoi(codigo); strcpy(novo->pessoa,nome); } void retira() { T_fila *ret; if (cabeca.inicio == NULL) { printf("Fila Vazia"); return; } else { ret=cabeca.inicio; cabeca.inicio=ret->prox; free(ret); if (cabeca.inicio==NULL) cabeca.fim=NULL; }

45 45 Pilha UEPS (O Último a Entrar é o Primeiro a Sair) ABC AB ABDE (a) (b) (c) InícioFinal Início Final insere (A) insere (B) insere (C) remove(ponteiro) insere (D) insere (E)

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

48 48 Pilha em Estrutura Dinâmica #include 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 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 50 Recursividade Definição –Pode ser considerada um método eficaz para resolver um problema originalmente complexo, reduzindo-o em pequenas ocorrências do problema principal. Dividie para conquistar. Resolvendo, isoladamente, cada uma das pequenas partes, podemos obter a solução do problema original como um todo. Características de uma função recursiva –Definição de parâmetros; –Condição de parada da recursão, para que a rotina não seja chamada infinitamente; –Chamada da função dentro dela própria; Rotinas recursivas e pilhas –O controle de chamadas e de retorno de rotinas é efetuado por uma pilha (criada e mantida dinamicamente pelo sistema). Quando uma rotina é chamada, empilha-se o endereço da rotina e todas as variáveis locais são recriadas. Quando ocorre o retorno da rotina as variáveis locais que foram criadas deixam de existir. Vantagens –Facilidade na resolução de alguns tipos de problemas. Desvantagens –Uso demasiado dos recursos computacionais de um computador.

51 51 Recursividade #include int busca_linear(int, int); int busca_binaria(int,int, int); int fat(int); const total=10; int vet[10]; void main() { int i, numero, indice; char op; printf("Entre com 10 números"); for (i=0; i < total; i++) scanf("%d",&vet[i]); printf("Entre com o numero a pesquisar e calcular o fatorial"); scanf("%d",&numero); printf("Qual a pesquisa? (B)inaria ou (L)inear"); scanf("%c",&op); if (op == 'l') indice=busca_linear(numero,0); else indice=busca_binaria(numero,0,total); if (indice == -1) printf("Elemento não encontrado"); else printf("Elemento encontrado no ¡ndice : %d",indice); numero=fat(numero); printf("O fatorial e : %d ",numero); } Programa que de- monstra Busca Biná- ria, Busca Linear e Cálculo do Fatorial de forma recursiva.

52 52 Recursividade int busca_linear(n,i) { if ((i < total) && (vet[i] != n)) { i=busca_linear(n,i+1); return(i); } else { if (i == total) return(-1); else return(i); } int busca_binaria(n,inicio,fim) { int meio; if (inicio <= fim) { meio = (inicio+fim)/2; if (vet[meio] == n) return meio; else if (vet[meio] < n) busca_binaria(n,meio+1,fim); else busca_binaria(n,inicio,meio-1); } else return -1; } int fat(int n) { int res; if (n == 0) return 1; else { res = fat(n-1); res = res * n; return res; } Parâmetros Variáveis locais Condição de parada Chamada da própria função

53 53 Árvores Definição: – Relação de hierarquia ou de composição entre os dados (nós). – Conjunto finito T de um ou mais nós, tais que: (a) existe um nó denominado raiz da árvore; (b) os demais nós formam m >= 1 conjuntos disjuntos S1,...,Sm, onde cada um desses conjuntos é uma árvore. – As árvores Si recebem a denominação de Sub-árvores. Terminologia: – Cada nó da árvore é a raiz de uma Sub-árvore. – O número de Sub-árvores de um nó é o grau daquele nó. – Um nó de grau igual a zero é denominado folha ou nó terminal. – A raiz da árvore tem nível 0. – Os demais nós: nível = número de "linhas" que o liga à raiz. – Altura: nível mais alto da árvore.

54 54 Árvores Representação Estrutural: Árvore com altura igual a 3. A B CD E FG 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 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 56 Árvores Binárias Representação Estrutural: Como construir uma árvore? Como percorrer uma árvore ? Aplicações de árvores binárias Exemplos: Árvore Estritamente Binária Árvore Binária Completa A B C D E FG

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

58 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 Inicio Aloque (p); a <- p; Setinfo(p, dado); /* retorna p.informacao <- dado */ lado<- e; /* lado = e ou d */ Empilha (s, p); Enqto. (pilha não vazia) faça inicio leia (dado); Se (lado = e) então /* esquerda */ Se (dado <> '.) então inicio q <- p; Aloque (p); Setesq(q,p); /* q.esquerda <- p */ Setinfo(p,dado); /* p.informacao <- dado */ Empilha(s, q); fim senão /* esquerda vazia' */ inicio Setesq (p, NULO); lado <- d; fim senão /* lado = d */ Se (dado = '.' ) então /* direita */ inicio Setdir (p, NULO); p <- topo(s); Desempilha (s); fim senão /* direita*/ inicio q <- p; Aloque (p); Setdir (q, p); Setinfo (p, dado); lado <- e; fim fim /* fim Se lado = e */ fim /* fim enqto. pilha vazia */ senão /* dado = '.' */ a <- NULO; fim Proc Setinfo(p: ref no, dado: info) p.informacao <- dado; Proc Setesq(p, q: ref no) p.esquerda <- q; Proc Setdir(p, q: ref no) p.direita <- q;

59 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 60 Árvores Binárias - Percurso Exemplos: l Pré-ordem: 5, 4, 2, 3, 9, 7, 6, 8, 10 l Em ordem: 2, 3, 4, 5, 6, 7, 8, 9, 10 l Pós-ordem: 3, 2, 4, 6, 8, 7, 10, 9, 5 l Pré-ordem: 20, 10, 5, 2, 4, 6, 7, 15, 12, 18, 17, 19 l Em ordem: 2, 4, 5, 6, 7, 10, 12, 15, 17, 18, 19, 20 l Pós-ordem: 4, 2, 7, 6, 5, 12, 17, 19, 18, 15, 10, 20

61 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 62 Árvores Binárias de Pesquisa #include typedef struct nodo { int info; struct nodo *pai; struct nodo *f_esq; struct nodo *f_dir; char deletado; } T_nodo; T_nodo *raiz; T_nodo *cria_nodo(int,T_nodo*); void insere(int); T_nodo *consulta(int); void ordem(T_nodo *); void pre_ordem(T_nodo *); void pos_ordem(T_nodo *); void retira(int); As chamadas de pré-ordem e pós- ordem foram suprimidas por serem iguais. void main() { char opcao[1]; int informacao=0; do { printf("(I)ncluir (C)onsultar (R)emover (O)rdem Pr(E)-Ordem Pó(s)-Ordem (F)im: "); scanf("%s",&opcao); if ((strcmp(opcao,"I") == 0) || (strcmp(opcao,"C") == 0) || (strcmp(opcao,"R") == 0)) { printf("Entre com a informação : "); scanf("%i",&informacao); } if (strcmp(opcao,"I") == 0) insere(informacao); else if (strcmp(opcao,"C") == 0) consulta(informacao); else if (strcmp(opcao,"O") == 0) ordem(raiz); else if (strcmp(opcao,"R") == 0) retira(informacao); } while (strcmp(opcao,"F") != 0) }

63 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 info) aux = p->f_esq; else aux = p->f_dir; } if (n == p->info) printf("%s","Número Repetido"); else if (n info) p->f_esq=cria_nodo(n, p); else p->f_dir=cria_nodo(n, p); } } void pre_ordem(T_nodo *sub_raiz) { if (sub_raiz != NULL) { printf("%d\n",sub_raiz->info); ordem(sub_raiz->f_esq); ordem(sub_raiz->f_dir); }

64 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 info) aux = p->f_esq; else aux = p->f_dir; } if (n == p->info) { printf("Informação Existente"); return(p); } else { printf("Informação Inexistente"); getch(); return(NULL); } void ordem(T_nodo *sub_raiz) { if (sub_raiz != NULL) { ordem(sub_raiz->f_esq); printf("%d\n",sub_raiz->info); ordem(sub_raiz->f_dir); } void pos_ordem(T_nodo *sub_raiz) { if (sub_raiz != NULL) { ordem(sub_raiz->f_esq); ordem(sub_raiz->f_dir); printf("%d\n",sub_raiz->info); }

65 65 Árvores Binárias de Pesquisa void retira(int n) { T_nodo *aux=raiz, *rem=raiz; if (raiz == NULL) { printf(Árvore sem elementos"); return(); } while ((aux != NULL) && (n != rem->info)) { rem = aux; if (n info) aux = rem->f_esq; else aux = rem->f_dir; } if (n == rem->info) { rem->deletado='V'; while ((rem != NULL) && (rem->deletado == 'V')) { if (rem->f_esq = NUL) && (rem->f_dir = NUL) { if (rem != raiz) { aux=rem->pai; if (aux->f_esq == rem) aux->f_esq=NULL; else aux->f_dir=NULL; } else raiz=NULL; } rem=rem->pai; } else printf("Elemento não encontrado"); } Remove logicamente Remove fisicamente Remove fisicamente a raiz Exercício Modificar o programa para que use o campo deletado definido na estrutura da arvore.

66 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 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 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 69 Árvores AVL –Exemplos de Rotações ( Rotação simples a direita): –Exemplos de Rotações ( Rotação dupla a direita): Rotação a Esquerda e a Direita Rotação a Direita

70 70 Árvores AVL –Exemplos de Rotações (rotação simples a esquerda) : –Exemplos de Rotações ( Rotação dupla a esquerda): Rotação a Esquerda Inserir Rotação a Direita e a Esquerda

71 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 *); void main() { int numero=0, achou; raiz=NULL; do { printf("Entre com a informação : "); scanf("%i",&numero); if (numero != -1) { raiz=insere_AVL(numero,raiz); mostra_dados(raiz); } } while (numero != -1); }

72 72 Árvores AVL T_nodo *insere_AVL(int x, T_nodo *pt) { if (pt == NULL) { pt = cria_nodo(x); h=true; } else { if (x info) { pt->f_esq=insere_AVL(x,pt->f_esq); if (h == true) { switch (pt->bal) { case 1 : pt->bal = 0; h=false; break; case 0 : pt->bal = -1; break; case -1: pt=caso1(pt); h=false; break; } Inserção dos Elementos Recursão Esquerda Verificar Balanceamento Interrompe Balanceamento Ficou com a esquerda maior Era mais alto a direita, equilibrou Constata caso1

73 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; break; case 1 : pt=caso2(pt); h=false; break; } else printf("informação já existente"); } return pt; } Recursão Direita Verificar Balanceamento Era mais alto a esquerda, equilibrou Ficou com a direita maior Constata caso2

74 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) { T_nodo *ptu; ptu=pt->f_esq; pt->f_esq=ptu->f_dir; ptu->f_dir=pt; pt->bal=0; return ptu; } T_nodo *caso2(T_nodo *pt) { T_nodo *ptu; ptu=pt->f_dir; if (ptu->bal == 1) pt=rotacao_esquerda(pt); else pt=rotacao_dir_esq(pt); pt->bal=0; return pt; } T_nodo *rotacao_esquerda(T_nodo *pt) { T_nodo *ptu; ptu=pt->f_dir; pt->f_dir=ptu->f_esq; ptu->f_esq=pt; pt->bal=0; return ptu; } Caso1.1- sinais iguais e negativos Caso1.2- sinais diferentes Caso2.1- sinais iguais e positivos Caso2.2- sinais diferentes

75 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 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 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: –C ada 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 78 Árvores - B Representação Estrutural : Exemplo: Árvore B (ordem 2): K1K2...Km P0P1P2...Pm-1Pm Raiz

79 79 Árvores – B : Operações Inserção : Algoritmo Simplificado de Pesquisa: x - argumento de pesquisa K i - valores das chaves dos nós de derivação (i) Se K i < x < K i+1 ; seguir P i (ii) Se x < K 1 ; seguir P 0 (iii)Se x > K m ; o caminho será indicado por P m Inserção da chave 22 K1K2...Km P0P1P2...Pm-1Pm

80 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 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ãoSubstitui x por adjacente; REMOVE(adjacente, no); fim-se fim Remoção da chave

82 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 n) && (x -> Chave > Ptr -> r[i-1].chave) i++; if (x -> chave == Ptr -> r[i-1].chave) {*x == Ptr -> r[i-1]; return; } if (x -> chave 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 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 "Ciência da Computação Estrutura de Dados I Professores: Artur Henrique Kronbauer José Maria David Maria Luiza Braga 1."

Apresentações semelhantes


Anúncios Google