Estrutura de Dados -...

Post on 27-Dec-2018

221 views 0 download

Transcript of Estrutura de Dados -...

Estrutura de Dados Carlos Eduardo Batista

Centro de Informática - UFPB

bidu@ci.ufpb.br

Estruturas de Dados

Deques

Listas recursivas

Árvores (parte 1)

2

Estrututuras de dados lineares

Próximas aulas

Estruturas de dados não lineares

4

Deques

Conjunto de itens onde as eliminações e inserções podem ser realizadas em qualquer das extremidades (início ou fim fila)

Deque (double-ended-queue) ◦ é uma lista linear onde as operações de inserção e remoção podem ser efetuadas tanto no início quanto no final

5

Deques, filas e pilhas 6

Deque Fila

Pilha

Deques

Deque de saída restrita ◦ A remoção só pode ser efetuada ou no início ou no final de uma lista linear

Deque de entrada restrita ◦ A inserção só pode ser efetuada ou no início ou no final de uma lista linear

7

Deques

Dominó

Composição de um trem

Barca para transporte de automóveis ◦ Carros podem entrar e sair por qualquer uma das extremidades.

Escalonamento de tarefas ◦ fila de processos aguardando os recursos do sistema operacional

8

Deques

Operações ◦ Criar Deque

◦ Inserção no inicio

◦ Inserção no fim

◦ Remoção no inicio;

◦ Remoção no fim

◦ Verificar se deque está cheio

◦ Exibir

◦ Esvaziar

9

Deques

Lista duplamente encadeada (duas cabeças)

Lista duplamente encadeada circular

10

PRIM

ULT

D

Listas

Formadas por um conjunto de dados de forma a preservar a relação de ordem linear entre eles

Esses dados são conhecidos como nós

Os nós podem conter dados primitivos ou compostos

Inserção e remoção de elementos em qualquer posição da lista

11

Listas 12

Listas recursivas

Definição recursiva de lista

Uma lista é ◦ Uma lista vazia ou

◦ Um elemento seguido de uma (sub)lista.

13

Listas recursivas 14

// Tipo base dos elementos da lista

typedef struct elementos {

char nome[50];

} t_elemento;

// Estrutura lista

typedef struct no {

t_elemento dado; // elemento contendo os dados

struct no * prox; // ponteiro para o proximo elemento

} t_no, t_lista; // tipo da estrutura

Listas encadeadas 15

t_lista * criar() {

t_lista * lista = (t_lista*) malloc(sizeof(t_lista));

if (lista)

lista->prox = NULL;

return lista;

}

int isVazia(t_lista * lista) {

return (lista == NULL);

}

Listas encadeada 16

/**

* Percorre toda a lista e verifica o tamanho dela.

*/

void exibir(t_lista * lista) {

if (isVazia(lista))

printf("Lista vazia\n");

while (lista != NULL) {

printf("%s\n", lista->dado.nome);

lista = lista->prox;

}

}

Listas recursivas 17

void exibirRec(t_lista * lista) {

if (isVazia(lista))

printf("Lista vazia\n");

else {

printf("%s\n", lista->dado.nome);

exibirRec(lista->prox);

}

}

Listas encadeadas 18

/**

* Percorre toda a lista e verifica o tamanho dela.

*/

int tamanho(t_lista * lista) {

int n = 0;

while (lista != NULL) {

lista = lista->prox;

n++;

}

return n;

}

Listas recursivas 19

/**

* Percorre toda a lista e verifica o tamanho dela.

*/

int tamanhoRec(t_lista * lista) {

if (lista != NULL) {

return 1 + tamanhoRec(lista->prox);

}

else

return 0;

}

Lista encadeada 20

t_no * getNo(t_lista * lista, int pos)

{

// Retorna 0 se posicao invalida. Do contrario, retorna o elemento

int n = 0;

if (pos<0) return 0; // erro: posicao invalida

while (lista != NULL) {

if (n==pos)

return lista;

lista = lista->prox;

n++;

}

return 0; // erro: posicao invalida

}

Listas recursivas 21

t_no * getNoRec(t_lista * lista, int pos, int n)

{

// Retorna 0 se posicao invalida. Do contrario, retorna o

elemento

if (pos<0) return 0; // erro: posica£o invalida

if ((lista != NULL)) {

if (n==pos)

return lista;

else

return getNoRec(lista->prox, pos, n+1);

}

return 0; // erro: posicao invalida

}

Listas recursivas 22

/**

* Retorna a posicao do elemento ou -1 caso nao seja encontrado

*/

int getPosicaoRec(t_lista * lista, t_elemento * dado, int n) {

if (lista != NULL) {

if (compara(&(lista->dado), dado))

return n;

else

return getPosicaoRec(lista->prox, dado, n+1);

}

return -1;

}

Lista encadeada 23

int inserir(t_lista **lista, int pos, t_elemento * dado) {

t_lista * p, * novo;

if (pos == 0) {

novo = criar();

if (novo == NULL) return 0; // erro: memoria insuficiente

novo->dado = *dado;

novo->prox = *lista;

*lista = novo;

return 1;

}

p = getNo(*lista, pos-1);

if (p == NULL) return 0; // erro: posicao invalida

novo = criar();

if (novo == NULL) return 0; // erro: memoria insuficiente

novo->dado = *dado;

novo->prox = p->prox;

p->prox = novo;

return 1;

}

Lista encadeada 24

int remover(t_lista **lista, int pos) {

t_lista *anterior, *p;

if (isVazia(*lista)) return 0; // erro: lista vazia

if (pos<0) return 0; // erro: posicao invalida

// remocao da primeira posicao em lista nao vazia

if (pos == 0) {

p = *lista;

*lista = p->prox;

} else { // remocao em qualquer posicao

anterior = getNo(*lista, pos-1);

if (anterior == NULL) return 0; // posicao invalida

p = anterior->prox;

if (p == NULL) return 0; // erro: posicao invalida

anterior->prox = p->prox;

}

free(p);

return 1;

}

Árvores

Organização dos dados: ◦ Linear:

Listas, pilhas, filas.

Relação sequencial.

◦ Não-linear:

Outros tipos de relação entre dados;

Hierarquia;

Árvores

Grafos.

25

Árvores

Estrutura não-linear que representa uma relação de hierarquia

Exemplo:

◦Árvore de diretórios;

◦Árvore genealógica.

26

Árvores 27

Presidência

Consultoria Diretoria A Diretoria B

Informática Jurídica

Árvores 28

Estrutura de Dados

Capítulo 1

1.1 Listas

1.2 Pilha

1.3 Fila

Capítulo 2

2.1 Recursividade

2.1.1 Hanoi

Capítulo 3

3.1 Árvores

3.2 Árvores binárias

(a + (b * ( (c / d) - e) )

Árvores – Representação

Diagrama de Inclusão

Parentes aninhados

29

( A (B) ( C (D (G) (H)) (E) (F (I)) ) )

Árvores

Caracterização de uma árvore: ◦ Composta por um conjunto de nós

◦ Existe um nó r, chamado nó raiz

Este nó contém zero ou mais sub-árvores, cujas raízes são ligadas diretamente a r

Os nós raízes das sub-árvores são ditos filhos do nó pai r ◦ “Nós” que não têm filhos são chamados de folhas

É tradicional desenhar as árvores com a raiz para cima e folhas para baixo

30

Árvores

◦Um nó filho não pode ter dois pais.

◦O filho não sabe quem é o pai.

31

Este exemplo não é árvore! É um grafo.

Árvores 32

raiz

A B C D …

Sub-árvores do

nó raiz

Filhos de C Filhos de A

Árvores

O número de sub-árvores de um nó determina o “grau de saída“ desse nó. Ou seja, a quantidade de filhos.

Grau Máximo, ou grau da árvore ◦ Maior grau de seus nós.

Nós que não tem grau (grau == 0), são denominados de nó folha

Para identificar os nós de uma estrutura, usamos a relação de hierarquia existente em uma árvore genealógica ◦ Filho, pai, neto, irmão

33

Árvores

Nível ◦ Representa a distância de um nó até a raiz

◦ O nó de maior nível nos fornece a altura

◦ Só existe um caminho da raiz para qualquer nó

34

nível 0

nível 1

nível 2

nível 3

Árvores

Árvore cheia ◦ Árvore com número máximo de nós.

◦ Uma árvore de grau d tem número máximo de nós se cada nó, com exceção das folhas, tem grau d.

35

Árvores

a) Quais os nós folhas?

b) Qual o grau de cada nó?

c) Qual o grau da árvore?

d) Liste os ancestrais dos nós B, G e I.

e) Liste os descendentes do nó D.

f) Dê o nível e altura do vértice F.

g) Dê o nível e a altura do vértice A.

h) Qual a altura da árvore ?

36

Árvores Binárias

◦Tipo de árvore em que seus nós possuem no máximo duas sub-árvores

Árvore de grau máximo igual a 2

◦As duas sub-árvores de cada nó são denominadas:

sub-árvore esquerda

sub-árvore direita

Árvore binária completa

◦Árvore em que cada nó possui dois filhos, exceto o nó folha.

37

Árvores Binárias

38

A

B C

D E F

G

Nivel 1

Nivel 2

Nivel 3

Raízes das sub-árvores

Raiz

Esquerda Direita

Grau máximo: 02

Folhas

Árvores Binárias 39

dado

Filho esquerdo Filho direito nó

typedef struct no {

struct no * esq;

t_elemento dado;

struct no * dir;

} t_no;

Árvores Binárias

A maioria das funções de manipulação de árvores são implementadas de forma recursiva

Que operações serão necessárias? Criação/Iniciliazação da árvore Cria nó raiz Árvore vazia Imprimir a árvore Inserir filho esquerdo Inserir filho direito Remover um determinado nó

40

Árvores Binárias

Considerações Uma árvore é representada pelo endereço do nó

raiz Uma árvore vazia é representada pelo valor NULL Algoritmos em C Estrutura da árvore Inicialização Criação de nós Criação de filhos esquerdo e direito Deslocamento para o filho esquerdo ou direito Impressão (exibição) da árvore Pesquisa

41

Árvores Binárias

Percurso ◦Um percurso define a ordem em que os nós de uma árvore serão processados

Tipos de percurso: ◦Pré-ordem Utiliza o nó

Percorre a sub-árvore esquerda

Percorre a sub-árvore direita

◦In-ordem Percorre a sub-árvore esquerda

Utiliza o nó

Percorre a sub-árvore direita

42

Árvores Binárias

◦Pós-ordem

Percorre a sub-árvore esquerda

Percorre a sub-árvore direita

Utiliza o nó

43

A

B C

D E GF

Árvores Binárias 44

A

B C

D E GF

Pré-ordem:

In-ordem

Pós-ordem

ABDECFG

DBEAFCG

DEBFGCA

Árvores Binárias 45

void exibirPreOrdem(t_arvore tree)

{

if (tree!=NULL) {

printf("%s ", tree->dado.nome);

exibirPreOrdem(tree->esq);

exibirPreOrdem(tree->dir);

}

}

Árvores Binárias 46

void exibirInOrdem(t_arvore tree)

{

if (tree!=NULL) {

exibirInOrdem(tree->esq);

printf("%s ", tree->dado.nome);

exibirInOrdem(tree->dir);

}

}

Árvores Binárias 47

void exibirPosOrdem(t_arvore tree)

{

if (tree!=NULL) {

exibirPosOrdem(tree->esq);

exibirPosOrdem(tree->dir);

printf("%s ", tree->dado.nome);

}

}

Árvores Binárias 48

void inordem_ (arvore arv) {

pilha p;

arvore aux;

criapilha(&p);

aux = arv;

if (vazia(arv)) return;

do {

while (aux != NULL) {

empilha(&p, aux);

aux = (aux->esq);

}

if (!pilhavazia(p)) {

desempilha(&p, &aux);

printf("%d ", aux->dado);

aux = (aux->dir);

}

} while (!(pilhavazia(p) && aux == NULL));

}

void inordem(arvore arv) {

if (!vazia(arv)) {

inordem(arv->esq);

printf("%d", arv->info);

inordem(arv->dir);

}

}

Árvores binárias 49

// Tipo base dos elementos da arvore

typedef struct elementos {

char nome[100];

} t_elemento;

typedef struct no {

struct no * esq;

t_elemento dado;

struct no * dir;

} t_no;

typedef t_no* t_arvore;

Árvores binárias 50

// Cria um no vazio

t_no * criar ()

{

t_no * no = (t_no*) malloc(sizeof(t_no));

if (no)

no->esq = no->dir = NULL;

return no;

}

Árvores binárias 51

// isVazia - testa se um no eh vazio

int isVazia (t_no * no)

{

return (no == NULL);

}

Árvores binárias 52

t_no * busca(t_arvore tree, t_elemento dado)

{

t_no* achou;

if (tree == NULL)

return NULL;

if (compara(tree->dado, dado)==0)

return tree;

achou = busca(tree->esq, dado);

if (achou == NULL)

achou = busca(tree->dir, dado);

return achou;

}

Árvores binárias 53

// Insere um noh raiz numa arvore vazia.

//Retorna 1 se a insercao for bem sucedida, ou 0 caso contrario.

int insereRaiz(t_arvore* tree, t_elemento dado)

{

t_no* novo;

if (*tree != NULL)

return 0; // erro: ja existe raiz

novo = criar();

if (novo == NULL)

return 0; // erro: memoria insuficiente

novo->dado = dado;

*tree = novo;

return 1;

}

Árvores binárias 54

// Inserir um filho aa direita de um dado noh

int insereDireita(t_arvore tree, t_elemento pai, t_elemento filho)

{

t_no * f, *p, *novo;

// verifica se o elemento ja nao existe

f = busca(tree,filho);

if (f != NULL)

return 0; // erro: dado ja existente

// busca o pai e verifica se ja nao possui filho direito

p = busca(tree,pai);

if (p == NULL)

return 0; // erro: pai nao encontrado

if (p->dir != NULL) return 0; // erro: ja existe filho direito

novo = criar();

if (novo == NULL)

return 0; // erro: memoria insuficiente

novo->dado = filho;

p->dir = novo;

return 1;

}

Árvores binárias 55

// Inserir um filho a esquerda de um dado noh

int insereEsquerda(t_arvore tree, t_elemento pai, t_elemento filho)

{

t_no * f, *p, *novo;

// verifica se o elemento ja nao existe

f = busca(tree,filho);

if (f != NULL)

return 0; // erro: dado ja existente

// busca o pai e verifica se ja nao possui filho esquerdo

p = busca(tree,pai);

if (p == NULL)

return 0; // erro: pai nao encontrado

if (p->esq != NULL) return 0; // erro: ja existe filho esquerdo

novo = criar();

if (novo == NULL)

return 0; // erro: memoria insuficiente

novo->dado = filho;

p->esq = novo;

return 1;

}

Árvores binárias 56

void exibirPreOrdem(t_arvore tree) {

if (tree!=NULL) {

printf("%s ", tree->dado.nome);

exibirPreOrdem(tree->esq);

exibirPreOrdem(tree->dir);

}

}

void exibirInOrdem(t_arvore tree) {

if (tree!=NULL) {

exibirInOrdem(tree->esq);

printf("%s ", tree->dado.nome);

exibirInOrdem(tree->dir);

}

}

void exibirPosOrdem(t_arvore tree){

if (tree!=NULL) {

exibirPosOrdem(tree->esq);

exibirPosOrdem(tree->dir);

printf("%s ", tree->dado.nome);

}

}

Árvores binárias 57

// Exibir a arvore - Procedimento recursivo, usando um percurso pre-ordem.

// sugestao de uso: exibirGraficamente(arvore, 10, 10, 3);

void exibirGraficamente(t_arvore tree, int col, int lin, int desloc)

{

// col e lin sao as coordenadas da tela onde a arvore ira iniciar,

// ou seja, a posicao da raiz, e desloc representa o deslocamento na tela

// (em colunas) de um no em relacao ao no anterior.

if (tree == NULL)

return; // condicao de parada do procedimento recursivo

gotoxy(col,lin);

printf("%s",tree->dado.nome);

if (tree->esq != NULL)

exibirGraficamente(tree->esq,col-desloc,lin+2,desloc/2+1);

if (tree->dir != NULL)

exibirGraficamente(tree->dir,col+desloc,lin+2,desloc/2+1);

}

Árvores binárias 58

void esvaziar(t_arvore *tree)

{

if (*tree == NULL)

return;

esvaziar((&(*tree)->esq));

esvaziar((&(*tree)->dir));

free(*tree);

*tree = NULL;

}

Próximas aulas

Árvore binária de pesquisa

59

Referências

Notas de Aula do Prof. Bruno B. Boniati

Notas de Aula do Prof. João Luís Garcia Rosa

Notas de Aula do Prof. Derzu Omaia

60

Estrutura de Dados Carlos Eduardo Batista

Centro de Informática - UFPB

bidu@ci.ufpb.br