You are on page 1of 200

Estrutura de Dados I

Docente: Msc

Dikiefu Fabiano,

Sumrio
1.

2.

Introduo 1.1 Tipo de dados Abstracto -TDA 1.2 Ponteiros 1.3 Funes 1.4 Estruturas e tipos de dados definidos pelo programador Listas Lineares 2. 1 Listas Sequenciais 2.2 Listas ligadas 2.3 Listas Circulares 2.4 Listas duplamente ligadas 2.5 Pilhas 2.5.1Implementao sequencial da pilha 2.5.2Implementao dinmica da pilha 2.6 Filas 2.6.1Implementao sequencial da fila 2.6.2Implementao dinmica da fila 2.6.3Fila circular

3.

rvores

3.1 Introduo
3.2 Representao de rvores 3.2 Definio 3.3 Terminologia

3.4 rvores binrias


3.5 rvores balanceadas 3.6 Definio da estrutura de dados
4.

Ordenao

4.1 Ordenao por Seleco


4.2 Ordenao por Insero 4.3 Shellsort 4.4 Quicksort 4.5 Heapsort
5.

Pesquisa 5.1 Pesquisa Sequencial 5.2 Pesquisa Binria 5.3 rvores de Pesquisa

Capitulo I: Introduo
Sumrio:
1.1 Tipo de Dado Abstracto (TDA 1.2 Ponteiros 1.3 Funes 1.4 Estruturas 1.5 Tipos de dados definidos pelo programador

1.1 Tipo de Dados Abstracto TDA

Tipos de Dados Tipo de dados de uma variveis define o conjunto de valores que a varivel pode assumir. Especifica a quantidade de bytes que deve ser reservadas a ela. Tipos de dados podem ser vistos como mtodos para interpretar o contedo da memria do computador Podemos ver o conceito de tipo de dados de uma outra perspectiva: no em termos do que um computador pode fazer (interpretar os bits ) mas em termos do que o utilizador desejam fazer (somar dois inteiros)

1.1 Tipo de Dado Abstracto - TDA

Tipo de Dado Abstracto


Agrupa a estrutura de dados juntamente com as operaes que podem ser feitas sobre esses dados O TDA encapsula a estrutura de dados. Os usurios do TDA s tem acesso a algumas operaes disponibilizadas sobre esses dados Usurio do TDA x Programador do TDA Usurio s enxerga a interface, no a implementao Dessa forma, o usurio pode abstrair da implementao especfica. Qualquer modificao nessa implementao fica restrita ao TDA A escolha de uma representao especfica fortemente influenciada pelas operaes a serem executadas

1.1 Tipo de Dado Abstracto TDA

Estrutura de Dados - ED um mtodo particular de se implementar um TDA Cada ED construda dos tipos primitivos (inteiro, real, char, ) ou dos tipos compostos (array, registo, ) de uma linguagem de programao. Algumas operaes realizadas em um TDA so: criao, incluso, busca e remoo de dados.

Exemplos de TDA
Lineares: Listas ligadas Pilhas Filas No Lineares: . rvores . Grafos

TDA-Exemplo
Existem vrios mtodos para especificar um TDA. O mtodo que usaremos semiformal e faz uso intensivo da notao de C. Para ilustrar o conceito de um TDA e mtodo de especificao, examinemos o TDA RACIONAL que corresponde ao conceito matemtico de um nmero racional. Um nmero racional o que pode ser expresso como o quociente de dois inteiros. As operaes sobre nmeros racionais que definimos so: Criao de um nmero racional Adio Multiplicao Teste de igualdade.

TDA-Exemplo
//definio de valor abstract typedef <integer, integer> RACIONAL; condiction RACIONAL [1] <> 0; //definio de operador abstract RACIONAL criaracional(a, b) int a, b; precondition b <> 0; postcondition criaracional[0]== a; criaracional[1]== b; abstract RACIONAL soma (a, b) RACIONAL a, b; postcondition soma[1]== a[1]*b[1]; soma[0]==a[0]*b[1]+b[0]*a[1];

abstract RACIONAL mult(a, b) RACIONAL a, b; postcondition mult[0]==a[0]*b[0]; mult[1]==a[1]*b[1];


abstract RACIONAL igual(a,b) RACIONAL a, b; postcondition igual==(a[0]*b[1]==a[1]*b[0]);

1.2 Apontadores
Na realidade, C permite que o programador referencie a posio de objectos bem como os prprios objectos (isto , o contedo de suas posies) Por exemplo, se x for declarado como um inteito, &x se referir posio reservada para conter x. &x chamado ponteiro.

1.2 Apontadores

O objectivo:
Armazenar o endereo de outra varivel, o qual , por sua vez, um nmero.

Sintaxe
tipo * ptr
ptr - o nome da varivel do tipo apontador tipo o tipo da varivel para qual apontar. * - indica que uma varivel do tipo apontador

Exemplo 1:
char *pc; int *pi; float *pf

1.2 Apontadores

Um ponteiro como qualquer outro tipo de dado em C. O valor de um ponteiro uma posio de memria da mesma forma que o valor de um inteiro um nmero. Os valores dos ponteiros podem ser atribudos como qualquer outro valor. A converso de pf do tipo ponteiro para um nmero de ponto flutuante para o tipo ponteiro para um inteiro pode ser feita escrevendo-se: pi = (int *) pf; Se pi um ponteiro para um inteiro, ento pi +1 o ponteiro para o inteiro imediatamente seguinte ao inteiro *pi em memria, pi1 o ponteiro para o inteiro imediatamente anterior a *pi.

Apontadores
Por exemplo, suponha que determinada mquina usa endereamento de bytes, que um inteiro exija 4 bytes e que valor de pi seja 100 (isto , pi aponta para inteiro *pi na posio 100). Sendo assim, o valor de pi1 96, o valor de pi+1 104. De modo semelhante, se o valor da varivel pc 100 e um caractere tem um byte, pc 1 refere-se a posio 99 e pc+1 posio 101.

Apontadores
Uma rea na qual os ponteiros de C desempenham um notvel papel passagem de parmetro para funes. Normalmente, os parmetros so passados para uma funo em C por valor, isto , os valores sendo passados so copiados nos parmetros da funo de chamada no momento em que a funo for chamada. Se o valor de um parmetro for alterado dentro da funo, o valor no programa chamada no ser modificado.

x =5 printf(%d\n, x) // imprime 5

func(x);
func(y)

// imprime 6

printf(%d\n, x) // imprime 5

int y
{ ++y; printf(%d\n, y); }

Se precisar usar func para modificar o valor de x, precisaremos passar o endereo de x

x =5 printf(%d\n, x) // imprime 5 func(&x); // imprime 6 printf(%d\n, x) //imprime 6 func(py) int *py {


++(*py); printf(%d\n, *py);
}

1.2.1 Inicializao automtica de apontadores

Um bom hbito para evitar problemas de programao a inicializao sempre dos apontadores A constante simblica NULL, quando colocada num apontador, indica que este no aponta para nenhuma varivel.
int x = 5; float pi = 3.1415; int px = &x; float * ppi = &pi;

1.3 Funes

Conceito:
uma unidade autnoma de cdigo do programa e desenhada para cumprir uma tarefa particular.

Sintaxe
tipo nome_da_funo (parametros){ comandos; }

1.3 Funes

Quando uma funo no retorna um valor para funo que a chamou ela declarada como void. Ex:
#include<stdio.h>
void linha (char ch, int size){ int i; for (i=1; i size; i++) putchar(ch); } main(){ char lin; int tamanho; printf(Introduza o tipo de linha); scanf(%c, &lin); printf(Introduza o tamanho da linha); scanf(%d, &tamanho); linha(lin, tamanho); getchar(); }

1.3 Funes
1.3.3 Funo com retorno

O tipo de retorno tem que ser declarada.

Ex1 : int potencia (int base, int expoente){ int i; If (expoente<0) return; for (i=1; i <= expoente; i++) i=base*i; return i; }

main(){ int b, e; printf(Introduza a base e expoente); scanf(%d%d, &b, &e); printf(valor=%d\n, potencia(b,e)); getchar(); }

Estrutura de dados e tipo de dados definido pelo utilizador


Estruturas so peas contguas de armazenamento que contm vrios tipos simples agrupados numa entidade. Estrutura so manifestadas atravs da palavra reservada struct seguida pelo nome da estrutura e por uma rea delimitada por colchetes que contm campos. struct pessoa { char nome[30]; int idade; char sexo; }; Para criao de novos tipos de estrutura de dados utiliza-se a palavra-chave: typedef
typedef struct pessoa { char nome[30]; int idade; char sexo; } PESSOA;

Estrutura
Para obter directamente o valor de um campo, a forma <nome_da_estrutura>.<campo>. Para obter o valor de um campo apontado por um ponteiro a forma <nome_da_estrutura> -> <campo> Ex

PESSOA func, *estud, &docente = func ; func.nome=Adriano; //atribui o valor Adriano para o campo nome func.idade=25; //atribui o valor 25 para o campo idade func.sexo=M; //atribui o valor M para o campo sexo estud=&func; //faz estud apontar para func estud->nome=Joana; //muda o valor do campo nome para Joana estud ->idade =22; //muda o valor do campo idade para 22 estud ->sexo =F; //muda o valor do campo sexo para F docente.Nome=Pedro; //Referncias usam a notao de ponto

Estruturas

Estruturas podem ser recursivas, i.e., podem conter ponteiros para si mesmas. Esta peculiaridade ajuda a definir estruturas do tipo lista.
struct lista{ struct lista *prox; int dado; }

Capitulo II: Listas


Sumrio
2. Listas Lineares 2. 1 2.2 2.3 2.4 2.5 Listas Sequenciais Listas ligadas Listas Circulares Listas duplamente ligadas Pilhas 2.5.1 Implementao sequencial da pilha 2.5.2 Implementao dinmica da pilha Filas 2.6.1 Implementao sequencial da fila 2.6.2 Implementao dinmica da fila 2.6.3 Fila circular

2.6

Listas

Listas so uma coleco de objectos, onde os itens podem ser adicionados em qualquer posio arbitrria.

Listas
Propriedades Uma lista pode ter zero ou mais elementos Um novo item pode ser adicionado a lista em qualquer ponto Qualquer item da lista pode ser eliminado Qualquer item da lista pode ser acessado

Listas - Formas de Representao

Sequencial Explora a sequencialidade da memria do computador, de tal forma que os ns de uma lista sejam armazenados em endereo sequencias. Podem ser representado por um vector na memria principal ou um arquivo sequencial em disco.
L

Ligada Esta estrutura tida como uma sequencia de elementos ligados por ponteiros, ou seja, cada elemento deve conter, alm do dado propriamente dito, uma referencia para o prximo elemento da lista.
Ado Adelina Bastos Daniel Josefina

Ad 0 o

Adelin 1 a

Basto Danie Josefin 2 3 4 s l a

MAX-1

Listas sequenciais
Uma lista representada de forma sequencial um conjunto de registos onde esto estabelecidas regras de precedncia entre seus elementos. Implementao de operaes pode ser feita utilizando array e registo, associando o elemento a[i] com o ndice i. Caractersticas Os elementos na lista esto armazenados fisicamente em posies consecutivas A insero de um elemento na posio a[i] causa o deslocamento a direita do elemento a[i] ao ltimo. A eliminao do elemento a[i] requer o deslocamento esquerda do a[i+1] ao ltimo.

Listas Sequenciais

Vantagens Acesso directo a qualquer dos elementos da lista. Tempo constante para acessar o elemento i - (depende somente de ndice) Desvantagens Para inserir ou remover elementos temos que deslocar muitos outros elementos Tamanho mximo pr-estimado Quando usar Listas pequenas Insero e remoo no fim da lista Tamanho mximo bem definido

Listas sequenciais
Operaes bsicas

Definio
#define MAX 50 //tamanho mximo da lista typedef char elem[20]; // tipo base dos elementos da lista typedef struct tlista{ elem v[MAX]; //vector que contm a lista int n; //posio do ltimo elemento da lista }; Tlista n=5

v 0 Ado 1 Albert o 2 Ana 3 Daniel a 4 Carme n 5 6 MAX 1

1.Criar uma lista vazia


void criar(tlista *L) { L -> n = 0; }

2. Verificar se uma lista est vazia


int vazia(tlista L) { return (L .n == 0); }

Listas sequenciais
Operaes bsicas
3. Verificar se uma lista est cheia
int cheia( tlista L) { return (L .n == MAX); }

4. Obter o tamanho de uma lista


int tamanho ( tlista L){ return (L.n); }

5. Obter o i-simo elemento de uma lista


int elemento( tlista L, int pos, elem *dado ) { if ((pos > L.n) || (pos <=0)) return (0); *dado = L.v [pos - 1]; return 1; }

6. Pesquisar um dado elemento,


retornando a sua posio.
int posicao( tlista L, elem dado ) { int i; for (i=1; i<L.n; i++) if(L.v[i-1] == dado) return i; return 0; }

Listas Sequenciais
Operaes bsicas 7. Insero de um elemento em uma
determinada posio
(requer o deslocamento direita dos elementos v(i+1) v(n)) // retorna 0 se a posio for invlida ou se a lista // estiver cheia, caso contrrio retorna 1 int inserir( tlista *L, int pos, elem dado ) { int i; if (( L->n == MAX) || ( pos > L->n + 1 )) return (0); for (i = L->n; i >= pos; i--) L->v[i] = L->v [i-1]; L->v[pos-1] = dado; (L->n)++; return (1); }

8. Remoo do elemento de uma


determinada posio
(requer o deslocamento esquerda dos elementos v(p+1) v(n))
/* o parmetro dado ir receber o elemento encontrado. Retorna 0 se a posio for invlida , caso contrrio retorna 1 */

int remover( tlista *L, int pos, elem *dado ) { int i; if ( ( pos > L->n) || (pos <= 0) ) return (0); *dado = L-> v[pos-1]; for (i = pos; i <= (L->n) - 1; i++) L->v[i-1] = L->v [i]; (L->n)--; return (1); }

Listas Ligadas

Uma lista ligada ou lista encadeada uma estrutura de dados linear e dinmica. Ela composta por clulas que apontam para o prximo elemento da lista. Para "ter" uma lista ligada/encadeada, basta guardar seu primeiro elemento, e seu ltimo elemento aponta para uma clula nula. Vantagens
A insero ou a retirada de um elemento na lista no implica na mudana de lugar de outros elementos; No necessrio saber, anteriormente, o nmero mximo de elementos que uma lista pode ter, o que implica em no desperdiar espao na Memria Principal (Memria RAM) do computador.

Desvantagens
manipulao torna-se mais "perigosa" uma vez que, se o encadeamento (ligao) entre elementos da lista for mal feito, toda a lista pode ser perdida; Para acessar o elemento na posio n da lista, deve-se percorrer os n - 1 anteriores.

Listas ligadas

As listas ligadas so conjunto de elementos ligados, onde cada elemento contem uma ligao com um ou mais elementos da lista. Uma lista ligada tem necessariamente uma varivel ponteiro apontando para o seu primeiro elemento. Essa varivel ser utilizada sempre, mesmo que esteja vazia, e dever apontar sempre para o incio da lista. Cada elemento da lista ligada ser composta por duas/trs partes principais: uma parte conter informaes e a(s) outra(s) as conexes

Listas Ligadas - Propriedades


Uma lista pode ter zero ou mais elementos Um novo item pode ser adicionado a lista em qualquer ponto Qualquer item da lista pode ser eliminado Qualquer item da lista pode ser acessado.

Listas Ligadas
Uma lista ligada composta por elementos alocadas em memria. Utiliza-se duas funes para alocar (desalocar) memria dinamicamente:

malloc() free()

Ex:
L = (lista) malloc(sizeof(lista)); free(L);

Lista Simplesmente Ligada


Cada elemento da lista possui uma nica conexo. Assim, cada elemento ser formado por um bloco de dados e um ponteiro para prximo elemento. Chamaremos cada elemento n. Um n um conjunto de informaes de tipos diferentes, portanto ela uma estrutura definida pelo programador: struct no{ int dado; struct no *prox; //ponteiro para o

prximo n

Listas Simplesmente Ligadas

Sendo que uma memria alocada dinamicamente no possui o nome como no caso das variveis declaradas no programa, toda lista dever ter uma varivel que apontar para o seu primeiro elemento.
struct no *head; //cabea da lista head=null; //inicia a lista com nulo

Listas Simplesmente Ligadas


Podemos nos referenciar a uma lista ligada atravs do seu primeiro n. Entretanto, toda vez que realizarmos uma insero no incio da lista teremos que garantir que todas as partes do programa que referenciam a lista tenha suas referencias actualizadas. Para evitar este problema, comum usar um n especial chamado n cabea, e um ponteiro para o primeiro elemento da lista.

Listas Simplesmente Ligadas


A implementao em C de uma lista simplesmente ligada com n cabea. Precisamos de dois tipos de dados:

Um tipo n, representa cada elemento da lista. e um tipo lista que contm um ponteiro para n cabea.

Listas Simplesmente Ligadas


typedef struct no{ int dado; // o dado poderia ser de qualquer tipo struct no *prox; // ponteiro para prximo
elemento

} NO;
typedef struct lista{ NO *head; }LISTA;

Listas Simplesmente Ligadas


1.

As operaes bsicas sobre a estrutura so: criao da lista e de n. Criao de lista

LISTA *criaLista(){ LISTA *L; L=(LISTA *)malloc(sizeof(LISTA)); L->head = NULL; return L; }


2.

Criao de n NO *criaNo(int dado){ NO *no; no = (NO *)malloc(sizeof(NO)); no->dado = dado; no->prox = NULL; return no; }

Listas Simplesmente Ligadas


Ao contrrio dos vectores, onde acessamos qualquer elemento usando um ndice numrico, com uma lista ligada temos apenas acesso sequencial, por exemplo, para chegar ao decimo elemento temos que passar por todos nove elementos anteriores. Para percorrer uma lista, precisamos obter seu primeiro elemento e ento obtemos os elementos subsequentes seguindo os ponteiros de prximo elemento em cada n.

NO *primeiro(LISTA *L){ return (L->head); } NO *proximo(NO *no){ return (no->prox); }

Listas Simplesmente Ligadas

Andar para trs em uma lista simplesmente ligada no to simples, requer que a lista seja percorrida desde o incio verificado se, para cada elemento x, proximo(x) o elemento do qual procuramos o elemento anterior.

NO *anterior(LISTA *L, NO *no){ NO *p; if(no==L->head) se no==head quer dizer que o no anterior o head return NULL; porque o head aponta para no p = primeiro(L); e o anterior a no o head while(proximo(p)!=NULL){ if(proximo(p) == no) return p; p = proximo(p); } return NULL; }

Listas Simplesmente Ligadas

Obter o ltimo elemento tambm requer que toda a lista seja percorrida.

NO *ultimo(LISTA *L){ NO *p; p = primeiro(L); if (p == NULL) return NULL; while(proximo(p)!=NULL) p = proximo(p); return p; }

Listas Simplesmente Ligadas

Podemos querer 3 tipos de inseres em uma lista:


no incio, no fim, ou em uma posio arbitrria.

Na lista simplesmente ligada a insero no incio trivial: Fazemos o prximo do novo elemento apontar para o primeiro elemento da lista e fazemos com que o novo elemento seja o primeiro elemento (cabea) da lista. A insero em posio arbitrria pode ser feito em tempo constante se tivermos um ponteiro para o elemento que ser o elemento anterior ao novo elemento: void insere_apos(NO *novo, NO *anterior){ novo->prox = anterior->prox; antrior->prox = novo; }

A insero no final da lista exige que encontremos seu ltimo elemento.

Listas Simplesmente Ligadas

Remoo de um elemento arbitrrio requer que encontremos o elemento anterior ao removido.

void remove(LISTA *lista, NO *no){ NO *ant; if(no == lista->head){ lista->head = no->prox; } else{ ant = anterior(lista, no) if(ant!=NULL) ant->prox = no->prox; } free(no); }

Listas duplamente ligadas

Na presena de um problema que exija uma movimentao eficiente desde um n quer para o seu antecessor, quer para o seu sucessor, podemos utilizar aquilo que se chama uma lista duplamente ligada.
valor valor valor NULL Atrs

frent e NULL

Listas duplamente ligadas


Uma das virtudes de listas duplamente ligadas, o facto de nos podemos deslocar para o n anterior ou para n seguinte, a um n dado com facilidade. Uma lista duplamente ligada permite-nos remover um n qualquer da lista em tempo constante, usando apenas um ponteiro para essa clula.

Listas duplamente ligadas operaes


anterior(): devolve o elemento anterior a um determinado elemento. cria(): devolve uma lista com um elemento insere(): insere um determinado elemento na lista. mostra(): mostra o contedo da lista. procura(): devolve a posio de um determinado elemento. remove(): remove o elemento desejado da lista.

Lista duplamente Ligada operaes


#include<stdio.h> #include<stdlib.h> typedef struct listadl{ struct listadl *prox; //prximo elemento da lista struct listadl *ant; //elemento anterior da lista int dado; }LDL;

Lista duplamente Ligada operaes


Devolve uma lista com elemento elem.
LDL *cria(int elem){ LDL*tmp; tmp =(LDL *)malloc(sizeof(tmp)); tmp->dado = elem; tmp->prox = NULL; tmp->ant = NULL; return tmp; }

Lista duplamente Ligada operaes


Insere o elemento elem na lista L.
void *insere(int elem, LDL *L){ LDL*tmp; tmp=L; while((tmp->prox ==NULL)==0) tmp = tmp->prox; tmp->prox = cria(elem); (tmp->prox)-> ant = tmp; }

Lista duplamente Ligada operaes


Imprime todos os elementos da lista.

void *mostra(LDL *L){ LDL*tmp, *no1, *no2; tmp=L; while((tmp->prox ==NULL)==0){ no1 = tmp->prox; no2 = tmp->ant; printf(O elemento: %d, tmp->dado);

if((no1 == NULL)==0) printf(O proximo:%d, no1>dado); else printf(No possui prximo.); if((no2 == NULL)==0) printf(O anterior:%d, no2>dado); else printf(No possui anterior.); tmp= tmp->prox; } }

Lista duplamente Ligada operaes


Remove o elemento elem da lista L.

LDL *remove(int elem, LDL *L){ LDL*tmp, *proxno, *noant; tmp=L; while((tmp->prox ==NULL)==0){ proxno = tmp->prox; noant = tmp->ant; if((tmp->dado == elem) if((noant == NULL)==0) if((proxno == NULL)==0){ noant->prox =proxno; proxno->ant =noant; free(tmp); return L; } else{ noant->prox=NULL; free(tmp); return L; }

else if((proxno == NULL)==0){ proxno->ant =NULL; free(tmp); L = proxno; return L; } else { L = NULL; free(tmp); return L; } else{ tmp = tmp -> prox; } printf(O elemento %d no se encontra na lista\n, elem); }

Lista duplamente Ligada operaes


Devolve a posio do elemento elem.
int *procura(int elem, LDL *L){ LDL*tmp; int pos = 0; tmp=L; while((tmp->prox ==NULL)==0) if((tmp->dado) == elem){ printf(A posio do elemento %d %d\n, elem, pos); return pos; } else{ pos++; tmp = tmp->prox; } printf(O elemento no se encontra na lista); }

Lista duplamente Ligada operaes Devolve o elemento anterior a elem.


void *anterior(int elem, LDL *L){ LDL*tmp, *noant; tmp=L; while((tmp==NULL)==0) if((tmp->dado) == elem){ noant = tmp->ant; printf(O elemento anterior a %d %d\n, elem, noant->dado); else printf(No existe anterior); exit(); } else tmp = tmp->prox; printf(O elemento no se encontra na lista); }

Lista Circular Ligada

As listas circulares so do tipo simples ou duplamente ligadas, em que o n final da lista a ponta para o n inicial. Este tipo de estrutura adapta-se a situaes do tipo FIFO (First In First Out).
Fig. 1 Lista circular ligada ( lista simplesmente ligada)
dado dado dado dado

Fig. 2 Lista circular ligada ( lista duplamente ligada)


dado dado dado dado

Lista circular Ligada - operaes


typedef struct no{ int dado; struct no *prox; }NO, LCSL; NO cabeca; 1. Inicializa a lista circular int inicializa(LCSL *cabeca) { *cabeca=NULL; return 0; } 2. Verifica se a lista est cheia int vazia(LCSL lista){ return (lista==NULL)? 1:0; }

3. Aloca e desaloca n. int aloca(LCSL *lista, int valor){ LCSL *tmp; tmp= (LCSL) malloc(sizeof(no)); if (tmp==NULL) return 1; // Erro *lista = tmp; tmp->dado = valor; tmp->prox = NULL; return 0; } void liberta(LCSL *lista){ free(*lista); *lista=NULL; }

Lista circular Ligada - operaes


4. Insero de um item int insere(LCSL *lista, int valor) { LCSL tmp; if (aloca(&tmp, valor)== 1) return 1; // Erro if (vazia(*lista) == 1){ //True=1 tmp->prox = tmp; *lista=tmp; } else { tmp->prox = *lista->prox; *lista->prox = tmp; } return 0; }

5. Adiciona um item ao fim da lista. int adiciona(LCSL *lista, int valor){ LCSL tmp; if (aloca(&tmp, valor)== 1) return 1; // Erro if (vazia(*lista) == 1) //True=1 tmp->prox = tmp; else{ tmp->prox = *lista->prox; *lista->prox = tmp; } *lista = tmp; return 0; //Ok }

Lista circular Ligada 6. Eliminao de um n operaes int apagaNo(LCSL *lista, LCSL no)
{ LCSL tmp; if(vazia(*lista) == 1) return 1; if(no==no->prox) *lista=NULL; else { for(tmp=*lista->prox; tmp!=*lista && tmp->prox!=no; tmp=tmp->prox) ; if(tmp->prox !=no) return 1; tmp->prox = no->prox; if(no== *lista) *lista=tmp; } free(&no); return 0; }

Pilhas e Filas
1. 2. 3. 4. 5. 6. 7.

8.

Pilhas Implementao sequencial da pilha Implementao dinmica da pilha Filas Implementao sequencial da fila Implementao dinmica da fila Fila circular Exerccios.

Pilhas
Pilhas so listas onde a insero ou a remoo de um item feita no topo. Definio: dada a pilha P= (a[1], a[2], , a[n]), dizemos que a[1] o elemento da base da pilha; a[n] o elemento topo da pilha; e a[i+1] est acima de a[i]. Pilhas so conhecidas como listas LIFO (last in first out)

Implementao de pilhas

Como lista sequencial ou ligada?


No caso geral de listas ordenadas, a maior vantagem da alocao dinmica sobre a sequencial, se a memria no for problema, a eliminao de deslocamento na insero ou eliminao dos elementos. No caso das pilhas, essas operaes de deslocamento no ocorrem. Portanto, alocao sequencial mais vantajosa na maioria das vezes. Como o acesso a pilha limitado ao ltimo elemento inserido, todos os elementos do meio do vector devem estar preenchidos. H desvantagens quando a quantidade de dados a ser armazenados no conhecido antecipadamente.

Pilhas

Implementao Sequencial
#define MAXPILHA 50 #define tpilha(p) (p->topo p->base) typedef struct pilha{ int base[MAXPILHA]; int *topo; }PILHA;

Implementao Sequencial
1.

Inicializa a pilha vazia int inicializa(PILHA *pp){ pp->topo = pp->base; return 1; } Verifica se pilha est vazia
int vazia(PILHA *pp){ return (pp->topo == pp->base) ? 1 : 0; }

2.

3.

Coloca dado na pilha. Apresenta erro se no haver espao. int push(PILHA *pp, int dado){ if(tpilha(pp) == MAXPILHA) return 0; *pp->topo=dado; pp->topo++; return 1; }

Implementao Sequencial
4.

Retira o valor do topo da pilha a atribui a dado. int pop (PILHA *pp, int dado){ if(vazia(pp) == 1) return 0; pp->topo--; *dado = *pp->topo return 1; } Retorna o valor do topo da pilha se remov-lo. int topo(PILHA *pp, int *dado){ if(pop(pp, dado) == 0) return 0; return push (pp, dado)
}

5.

Implementao Dinmica
#define INCR 50 #define tpilha(p) (p->topo p->base) typedef struct pilha{ int *base; int *topo; int tam; }PILHA;

Implementao dinmica
1.

Aloca espao para pilha e inicializa como vazia int inicializa(PILHA *pp){ pp->base = (int *) malloc (INCR *sizeof(int)); if(pp->base == NULL) return 0; pp->topo = pp->base;

pp->tam = INCR;
return 1; }

Implementao Dinmica
2. Coloca dado na pilha. Se no houver mais espao, aloca mais uma parte da memria. int push(PILHA *pp, int dado){ int *novapilha; if(tpilha(pp) == pp->tam){ *novapilha = (int *) realloc(pp->base, pp->tam + INCR)*sizeof(int *)); if(novapilha==NULL) return 0; pp->base=novapilha; pp->topo=pp->base + pp->tam; pp->tam+=INCR; } *pp->topo->dado; pp->topo++; return 1; } As funes pop() e topo() da implementao de pilhas esttica e dinmica so as mesmas.

Fila

Uma Fila uma estrutura de dados do tipo FIFO (First In First Out), cujo funcionamento inspirado no de uma fila natural, na qual o primeiro elemento a ser inserido sempre o primeiro elemento a ser retirado.

Filas
Uma fila tem por norma as seguintes funcionalidade:

Colocar e retirar dados da fila:


insere guardar um elemento na fila remove retirar um elemento da fila topo retornar o elemento do topo da fila.

Testar se a fila est vazia ou cheia:


cheia Verificar se a fila est cheia (no pode guardar mais elementos). vazia Verificar se a fila est vazia (no contm elementos)

Inicializar ou limpar:
inicializa Colocar a fila num estado pronto a ser utilizada

Filas

A implementao de uma fila pode ser efectuada atravs da utilizao de diferentes estruturas de dados (vectores, listas ligadas, rvores, etc.). De seguida, apresenta-se duas implementao de uma fila atravs da utilizao de vectores e listas ligadas.

Filas

Caractersticas das filas: Tipos de filas:

Os dados so armazenados pela ordem de entrada Filas de espera (queues) Filas de espera com prioridades (priority queues)
com duplo fim (deque double-ended queue)

Implementao das filas:

usando vectores / arrays (circulares ou no) utilizando um apontador para ns de informao (lista ligada)

Filas
Implementao em C usando arrays Vantagens:

Facilidade de implementao.

Desvantagens:
Vectores possuem um espao limitado para armazenamento de dados. Necessidade de definir um espao grande o suficiente para a fila Necessidade de um indicador para o inicio e para o fim da fila

Mtodo de Implementao
A adio de elementos fila resulta no incremento do indicador do fim da fila A remoo de elementos da fila resulta no incremento do indicador do inicio da fila

Filas
As FILAS so listas lineares que adotam a poltica FIFO (First In First Out - primeiro a entrar o primeiro a sair) para a manipulao de elementos. Inseres so feitas no final da fila (enfileirar elemento); Remoes so feitas no incio da fila (desenfileirar elemento);

Filas Operaes Bsicas


Criao Destruio Insero de um elemento Remoo de um elemento Localizao de um elemento para consulta ou alterao da informao

Filas Outras Operaes


Buscar por elementos que coincidam com certo padro (casamento de padro) Ordenar uma lista Intercalar duas listas Concatenar duas listas Dividir uma lista em duas Fazer cpia da lista

Filas Representao Fsica

Pode ser feita de duas formas:


Garantindo-se a precedncia dos elementos pela contiguidade fsica na memria usando-se vectores. Garantindo-se a precedncia dos elementos pelo seu encadeamento usando-se apontadores.

Filas Implementao Sequencial

Filas Implementao Sequencial

GERAR UMA FILA COM OS ELEMENTOS 15, 10, 23, 7 e 14

max - tamanho mximo da fila n - nmero de elementos na fila

Filas Implementao Sequencial


ENFILEIRAR 15 (inserir o elemento 15 na fila)

Filas Implementao Sequencial


ENFILEIRAR 10 (inserir o elemento 10 na fila)

Filas Implementao Sequencial


ENFILEIRAR 23 (inserir o elemento 23 na fila)

Filas Implementao Sequencial


ENFILEIRAR 7 (inserir o elemento 7 na fila)

Filas Implementao Sequencial

ENFILEIRAR 14 (inserir o elemento 14 na fila)

Filas Implementao Sequencial


DESENFILEIRAR (retirar elemento da fila - sempre do incio)

Filas Implementao Sequencial


DESENFILEIRAR (retirar elemento da fila - sempre do incio)

Filas Implementao Sequencial


DESENFILEIRAR (retirar elemento da fila sempre do incio)

Filas Implementao Sequencial

DESENFILEIRAR (retirar elemento da fila sempre do incio)

Filas Implementao Sequencial


DESENFILEIRAR (retirar elemento da fila sempre do incio)

Filas Implementao Sequencial

DESENFILEIRAR (retirar elemento da fila sempre do incio)

Filas Implementao Sequencial

Ao ENFILEIRAR verificar se fila est cheia (fila=max-1):


se fila cheia, imprimir mensagem fila cheia; seno, enfileirar elemento e actualizar fim da fila.

Ao DESENFILEIRAR verificar se fila est vazia (fim=-1):


se fila vazia, no desenfileirar e imprimir mensagem fila vazia; seno, desenfileirar, mostrar elemento desenfileirado e movimentar elementos das posies i+1 para i, i = 1 .. n-1.

Fila Circular Implementao Sequencial


Para aproveitar as posies do vector liberadas, os ndices se comportam de uma forma circular incr(i) = mod (i+1, MAX) Inicio marca a posio do prximo elemento a ser retirado da fila Fim, marca a posio (vazia) onde ser inserido o prximo elemento

Fila Circular Implementao Sequencial


Fila vazia, se inicio = fim Fila cheia, se fim e inicio esto em posies consecutivas (circularmente), ou seja, incio = incr(fim) A posio indicada por fim permanece sempre vazia

Fila Circular Implementao Sequencial


GERAR UMA FILA COM OS ELEMENTOS 15, 10, 23 RETIRAR 15 e INSERIR 7, 14 e 30 max - tamanho mximo da fila n - nmero de elementos na fila

Fila Circular Implementao Sequencial

ENFILEIRAR 15 (inserir o elemento 15 na fila)

Fila Circular Implementao Sequencial

ENFILEIRAR 10 (inserir o elemento 10 na fila)

Fila Circular Implementao Sequencial

ENFILEIRAR 23 (inserir o elemento 23 na fila)

Fila Circular Implementao Sequencial


DESENFILEIRAR (retirar elemento do incio da fila)

Fila Circular Implementao Sequencial


ENFILEIRAR 7 (inserir o elemento 7 na fila)

Fila Circular Implementao Sequencial

ENFILEIRAR 14 (inserir o elemento 14 na fila)

Fila Circular Implementao Sequencial

Fila Circular Implementao Sequencial

Fila Circular Implementao Sequencial

Fila Circular Implementao Sequencial

Fila Circular Implementao Sequencial

Fila Circular Encadeamento

Capitulo III: rvores

Docente: Dikiefu Fabiano, Msc

Sumrio
3.1 Introduo 3.2 Tipos de rvores 3.3 rvores binrias 3.3.1 Estrutura de uma rvore binria 3.3.2 Descrio 3.3.3 Altura 3.3.4 Representao em C 3.4 rvores Genricas 3.4.1 Estrutura de uma rvore genrica 3.4.2 Representao em C 3.4.3 Problemas com Representao

Introduo

As estruturas anteriores so chamadas de unidimensionais (ou lineares)


Exemplo so listas sequenciais e ligadas

No podem ser usadas como hierarquias. Exemplo: rvore de directrios rvore uma estrutura adequada para representar hierarquias A forma mais natural para definirmos uma estrutura de rvore usando recursividade

Estrutura de rvores

Uma rvore composta por um conjunto de ns. Existe um n r, denominado raiz, que contm zero ou mais sub-rvores, cujas razes so ligadas a r. Esses ns razes das sub-rvores so ditos filhos do n pai, no caso r. Ns com filhos so comumente chamados de ns internos e ns que no tm filhos so chamados de folhas, ou ns externos. tradicional desenhar as rvores com a raiz para cima e folhas para baixo, ao contrrio do que seria de se esperar.

Estrutura de rvores

Por adoptarmos essa forma de representao grfica, no representamos explicitamente a direco dos ponteiros, subentendendo que eles apontam sempre do pai para os filhos.

Tipos de rvores

O nmero de filhos permitido por n e as informaes armazenadas em cada n diferenciam os diversos tipos de rvores existentes. Estudaremos dois tipos de rvores. Primeiro, examinaremos as rvores binrias, onde cada n tem, no mximo, dois filhos. Depois examinaremos as chamadas rvores genricas, onde o nmero de filhos indefinido. Estruturas recursivas sero usadas como base para o estudo e a implementao das operaes com rvores.

rvore Binria
Um exemplo de utilizao de rvores binrias est na avaliao de expresses. Como trabalhamos com operadores que esperam um ou dois operandos, os ns da rvore para representar uma expresso tm no mximo dois filhos. Nessa rvore, os ns folhas representam operandos e os ns

rvores Binrias

Esta rvore representa a expresso (3+6)*(4-1)+5

Estrutura de uma AB
Numa rvore binria, cada n tem zero, um ou dois filhos. De maneira recursiva, podemos definir uma rvore binria como sendo:

uma rvore vazia; ou um n raiz tendo duas sub-rvores, identificadas como a sub-rvore da direita (sad) e a sub-rvore da esquerda (sae).

Estrutura de uma AB
Os ns a, b, c, d, e, f formam uma rvore binria da seguinte maneira: A rvore composta do n a, da subrvore esquerda formada por b e d, e da subrvore direita formada por c, e e f. O n a representa a raiz da rvore e os ns b e c as razes das sub-rvores. Finalmente, os ns d, e e f so folhas da rvore.

Descrio de AB

Para descrever rvores binrias, podemos usar a seguinte notao textual:


A rvore vazia representada por <>, e rvores no vazias por <raiz sae sad>.

Com essa notao, a rvore da Figura anterior representada por:


<a<b<><d<><>>> <c<e<><>><f<><>>>>.

Descrio de AB
Uma sub-rvore de uma rvore binria sempre especificada como sendo a sae ou a sad de uma rvore maior, e qualquer das duas subrvores pode ser vazia. As duas rvores da Figura abaixo so distintas.

Altura de uma AB

Uma propriedade fundamental de todas as rvores que s existe um caminho da raiz para qualquer n. Podemos definir a altura de uma rvore como sendo o comprimento do caminho mais longo da raiz at uma das folhas. A altura de uma rvore com um nico n raiz zero e, por conseguinte, dizemos que a altura de uma rvore vazia negativa e vale -1.

Representao em C

Podemos definir um tipo para representar uma rvore binria. Vamos considerar que a informao a ser armazenada so valores de caracteres simples. Vamos inicialmente discutir como podemos representar uma estrutura de rvore binria em C. Que estrutura podemos usar para representar um n da rvore? Cada n deve armazenar trs informaes: a informao propriamente dita, no caso um caractere, e dois ponteiros para as subrvores, esquerda e direita.

Representao em C
struct arv { char info; struct arv* esq; struct arv* dir; }; typedef struct arv Arv; Da mesma forma que uma lista encadeada representada por um ponteiro para o primeiro n, a estrutura da rvore como um todo representada por um ponteiro para o n raiz.

Criando rvores
Arv* inicializa(void) { return NULL; } Arv* cria(char c, Arv* sae, Arv* sad) {
Arv* p=(Arv*)malloc(sizeof(Arv)); p->info = c; p->esq = sae; p->dir = sad; return p;

rvore Vazia
int vazia(Arv* a) { return a==NULL; }

Exemplo

Exemplo: Usando as operaes inicializa e cria, crie uma estrutura que represente a seguinte rvore.

Exemplo
/* sub-rvore com 'd' */ Arv* a1= cria('d',inicializa(),inicializa()); /* sub-rvore com 'b' */ Arv* a2= cria('b',inicializa(),a1); /* sub-rvore com 'e' */ Arv* a3= cria('e',inicializa(),inicializa()); /* sub-rvore com 'f' */ Arv* a4= cria('f',inicializa(),inicializa()); /* sub-rvore com 'c' */ Arv* a5= cria('c',a3,a4); /* rvore com raiz 'a'*/ Arv* a = cria('a',a2,a5 );

Exemplo

Alternativamente, a rvore poderia ser criada recursivamente com uma nica atribuio, seguindo a sua estrutura. Como isso pode ser feito?

Exemplo
Arv* a = cria('a', cria('b', inicializa(), cria('d', inicializa(), inicializa()) ), cria('c', cria('e', inicializa(), inicializa()), cria('f', inicializa(), inicializa()) ) );

Exibe Contedo da rvore


void imprime (Arv* a) { if (!vazia(a)){ printf("%c ", a->info); /* mostra raiz */ imprime(a->esq); /* mostra sae */ imprime(a->dir); /* mostra sad */ } } Como chamada essa forma de exibio? E para exibir na forma in-fixada? E na psfixada?

Liberando Memria
Arv* libera (Arv* a){ if (!vazia(a)){ libera(a->esq); /* libera sae */ libera(a->dir); /* libera sad */ free(a); /* libera raiz */ } return NULL; }

Criao e Liberao
Vale a pena notar que a definio de rvore, por ser recursiva, no faz distino entre rvores e sub-rvores. Assim, cria pode ser usada para acrescentar uma sub-rvore em um ramo de uma rvore, e libera pode ser usada para remover uma sub-rvore qualquer de uma rvore dada.

Criao e Liberao
Considerando a criao da rvore feita anteriormente, podemos acrescentar alguns ns, com: a->esq->esq = cria('x', cria('y',inicializa(),inicializa()), cria('z',inicializa(),inicializa()) ); E podemos liberar alguns outros, com: a->dir->esq = libera(a->dir->esq); Deixamos como exerccio a verificao do resultado final dessas operaes.

Buscando um Elemento

Essa funo tem como retorno um valor booleano (um ou zero) indicando a ocorrncia ou no do carcter na rvore.
int busca (Arv* a, char c){ if (vazia(a)) return 0; /* no encontrou */ else return a->info==c ||busca(a->esq,c) ||busca(a->dir,c); }

Buscando um Elemento

Podemos dizer que a expresso:

return c==a->info || busca(a->esq,c) || busca(a->dir,c);

equivalente a:
if (c==a->info) return 1; else if (busca(a->esq,c)) return 1; else return busca(a->dir,c);

rvores Genricas

Como vimos, numa rvore binria o nmero de filhos dos ns limitado em no mximo dois. No caso da rvore genrica, esta restrio no existe. Cada n pode ter um nmero arbitrrio de filhos. Essa estrutura deve ser usada, por exemplo, para representar uma rvore de directrios. Supor que no h rvore vazia.

Exemplo

Representao em C

Devemos levar em considerao o nmero de filhos que cada n pode apresentar. Se soubermos que numa aplicao o nmero mximo de filhos 3, podemos montar uma estrutura com 3 campos apontadores, digamos, f1, f2 e f3. Os campos no utilizados podem ser preenchidos com o valor nulo NULL, sendo sempre utilizados os campos em ordem. Assim, se o n n tem 2 filhos, os campos f1 e f2 seriam utilizados, nessa ordem, ficando f3 vazio.

Representao em C
Prevendo um nmero mximo de filhos igual a 3, e considerando a implementao de rvores para armazenar valores de caracteres simples, a declarao do tipo que representa o n da rvore poderia ser:
struct arv3 { char val; struct arv3 *f1, *f2, *f3; };

Exemplo

Problemas com Representao


Como se pode ver no exemplo, em cada um dos ns que tem menos de trs filhos, o espao correspondente aos filhos inexistentes desperdiado. Alm disso, se no existe um limite superior no nmero de filhos, esta tcnica pode no ser aplicvel. O mesmo acontece se existe um limite no nmero de ns, mas esse limite ser raramente alcanado, pois estaramos tendo um grande desperdcio de espao de memria com os campos no utilizados. H alguma soluo para contornar tal problema?

Soluo
Uma soluo que leva a um aproveitamento melhor do espao utiliza uma lista de filhos: um n aponta apenas para seu primeiro (prim) filho, e cada um de seus filhos, excepto o ltimo, aponta para o prximo (prox) irmo. A declarao de um n pode ser:
struct arvgen { char info; struct arvgen *prim; struct arvgen *prox; }; typedef struct arvgen ArvGen;

Exemplo da Soluo

Exemplo da Soluo
Uma das vantagens dessa representao que podemos percorrer os filhos de um n de forma sistemtica, de maneira anloga ao que fizemos para percorrer os ns de uma lista simples. Com o uso dessa representao, a generalizao da rvore apenas conceitual, pois, concretamente, a rvore foi transformada em uma rvore binria, com filhos esquerdos apontados por prim e direitos apontados por prox.

Criao de uma rvoreGen


ArvGen* cria (char c) { ArvGen *a =(ArvGen *)malloc(sizeof(ArvGen)); a->info = c; a->prim = NULL; a->prox = NULL; return a; }

Insero
Como no vamos atribuir nenhum significado especial para a posio de um n filho, a operao de insero pode inserir a subrvore em qualquer posio. Vamos optar por inserir sempre no incio da lista que, como j vimos, a maneira mais simples de inserir um novo elemento numa lista ligada.

void insere (ArvGen* a, ArvGen* f) { f->prox = a->prim; a->prim = f; }

Exemplo Criao rvoreGen

Com as funes cria e insere como construir a rvore abaixo?

Exemplo Criao rvoreGen


/* cria ns como folhas */ ArvGen* a = cria('a'); ArvGen* b = cria('b'); ArvGen* c = cria('c'); ArvGen* d = cria('d'); ArvGen* e = cria('e'); ArvGen* f = cria('f'); ArvGen* g = cria('g'); ArvGen* h = cria('h'); ArvGen* i = cria('i'); ArvGen* j = cria('j'); ...

/* monta a hierarquia */ insere(c,d); insere(b,e); insere(b,c); insere(i,j); insere(g,i); insere(g,h); insere(a,g); insere(a,f); insere(a,b);

Impresso (pr-ordem)
void imprime (ArvGen* a) { ArvGen* p; printf("%c\n",a->info); for (p=a->prim; p!=NULL; p=p>prox) imprime(p); }

Busca de Elemento
int busca (ArvGen* a, char c) { ArvGen* p; if (a->info==c) return 1; else { for (p=a->prim; p!=NULL; p=p->prox) { if (busca(p,c)) return 1; } } return 0; }

Liberao de Memria
O nico cuidado que precisamos tomar na programao dessa funo a de liberar as subrvores antes de liberar o espao associado a um n (isto , usar ps-ordem).

Liberao de Memria
void libera (ArvGen* a){ ArvGen* p = a->prim; while (p!=NULL) { ArvGen* t = p->prox; libera(p); p = t; } free(a); }

Capitulo IV - Ordenao

Docente: Dikiefu Fabiano, Msc

Sumrio
4. Ordenao Interna 4.1 Ordenao por Seleco 4.2 Ordenao por Insero 4.3 Shellsort 4.4 Quicksort 4.5 Heapsort

155

Introduo - Conceitos Bsicos


Ordenar: processo de rearranjar um conjunto de objectos em uma ordem ascendente ou descendente. A ordenao visa facilitar a recuperao posterior de itens do conjunto ordenado. A maioria dos mtodos de ordenao baseada em comparaes das chaves. Existem mtodos de ordenao que utilizam o princpio da distribuio.

Notao utilizada nos algoritmos: Os algoritmos trabalham sobre os registos de um arquivo. Cada registo possui uma chave utilizada para controlar a ordenao. Podem existir outros componentes em um registo.

156

Conceitos bsicos
Um mtodo de ordenao estvel se a ordem relativa dos itens com chaves iguais no se altera durante a ordenao. Alguns dos mtodos de ordenao mais eficientes no so estveis. A estabilidade pode ser forada quando o mtodo noestvel. Sedgewick (1988) sugere agregar um pequeno ndice a cada chave antes de ordenar, ou ento aumentar a chave de alguma outra forma.

157

Classificao dos mtodos de ordenao


1. Ordenao interna: arquivo a ser ordenado cabe todo na memria principal. 2. Ordenao externa: arquivo a ser ordenado no cabe na memria principal. Diferenas entre os mtodos: Em um mtodo de ordenao interna, qualquer registo pode ser imediatamente cessado. Em um mtodo de ordenao externa, os registos so cessados sequencialmente ou em grandes blocos.

158

Classificao dos mtodos de ordenao interna


Mtodos simples: Adequados para pequenos arquivos. Produzem programas pequenos. Mtodos eficientes: Adequados para arquivos maiores. Usam menos comparaes. As comparaes so mais complexas nos detalhes. Mtodos simples so mais eficientes para pequenos arquivos.

159

Ordenao por Seleco


Um dos algoritmos mais simples de ordenao. Algoritmo: Seleccione o menor item do vector. Troque-o com o item da primeira posio do vector. Repita essas duas operaes com os n 1 itens restantes, depois com os n 2 itens, at que reste apenas um elemento.

As chaves em negrito sofreram uma troca entre si.


160

Ordenao por Seleco


void selectionSort(int vector[],int tam) { int i, j, min, aux; for(i=0; i<tam-1; i++) { min = i; aux = vector[i]; for(j=i+1; j<tam; j++) { if (vector[j] < aux) { min=j; aux=vector[j]; } } aux = vector[i]; vector[i] = vector[min]; vector[min] = aux; } }

161

Bubble Sort

O bubble sort, ou ordenao por flutuao (literalmente "por bolha"), um algoritmo de ordenao dos mais simples. A ideia percorrer o vector diversas vezes, a cada passagem fazendo flutuar para o topo o maior elemento da sequncia. Essa movimentao lembra a forma como as bolhas em um tanque de gua procuram seu prprio nvel, e disso vem o nome do algoritmo

void bubble( int v[], int qtd ) { int i; int j, aux, k = qtd - 1 ; for(i = 0; i < qtd; i++) { for(j = 0; j < k; j++) { if(v[j] > v[j+1]) { aux = v[j]; v[j] = v[j+1]; v[j+1]=aux; } } } }

void swapbubble( int v[], int i ) { aux = v[i]; v[i] = v[i+1]; v[i+1]=aux; } void bubble( int v[], int qtd ) { int i,j; for( j = 0; j < qtd; j++ ) { for( i = 0; i < qtd - 1; i++ ) { if( v[i] > v[i+1] ) { swapbubble( v, i ); } } } }

Mtodo de ordenao Bolha com ordenao de strings. void bubble(int v[], int qtd){ int i, trocou; char aux; do { qtd--; trocou = 0; for(i = 0; i < qtd; i++) if(strcasecmp(v[i],v[i + 1])>0) { strcpy(aux, v[i]); strcpy(v[i], v[i + 1]); strcpy(v[i + 1], aux); trocou = 1; } }while(trocou==1); }

Cdigo da ordenao SelectionSort com strings void ordenar_seleccao() { int i, j; for(i=0; i<n-1; i++) { for(j=i+1; j<n; j++) { if(strcmpi(vector[i], vector[j])>0) { strcpy(aux_char, vector[i]); strcpy(vector[i], vector[j]); strcpy(vector[j], aux_char); } } } }

Ordenao por Seleco


Vantagens: Custo linear no tamanho da entrada para o nmero de movimentos de registos. o algoritmo a ser utilizado para arquivos com registos muito grandes. muito interessante para arquivos pequenos.
Desvantagens: O facto de o arquivo j estar ordenado no ajuda em nada, pois o custo continua quadrtico. O algoritmo no estvel.

167

Ordenao por Insero


Mtodo preferido dos jogadores de cartas. Algoritmo: Em cada passo a partir de i =2 faa: Seleccione o i-simo item da sequncia fonte. Coloque-o no lugar apropriado na sequncia destino de acordo com o critrio de ordenao.

As chaves em negrito representam a sequncia destino.


168

Ordenao por Insero


void insertionSort(int vector[], int tam) { int i, j; int key; for (j = 1; j < tam; ++j) { key = vector[j]; i = j - 1; while (vec[i] > key && i >= 0) { vector[i+1] = vector[i]; --i; } vector[i+1] = key; } }

A colocao do item no seu lugar apropriado na sequncia destino realizada movendo-se itens com chaves maiores para a direita e ento inserindo o item na posio deixada vazia.
169

Ordenao por Insero


Consideraes sobre o algoritmo: O processo de ordenao pode ser terminado pelas condies: Um item com chave menor que o item em considerao encontrado. O final da sequncia destino atingido esquerda. Soluo: Utilizar um registo sentinela na posio zero do vector.

170

Ordenao por Insero


O nmero mnimo de comparaes e movimentos ocorre quando os itens esto originalmente em ordem. O nmero mximo ocorre quando os itens esto originalmente na ordem reversa. o mtodo a ser utilizado quando o arquivo est quase ordenado. um bom mtodo quando se deseja adicionar uns poucos itens a um arquivo ordenado, pois o custo linear. O algoritmo de ordenao por insero estvel.

171

Shellsort
Proposto por Shell em 1959. uma extenso do algoritmo de ordenao por insero. Problema com o algoritmo de ordenao por insero: Troca itens adjacentes para determinar o ponto de insero. So efectuadas n 1 comparaes e movimentaes quando o menor item est na posio mais direita no vector. O mtodo de Shell contorna este problema permitindo trocas de registos distantes um do outro.

172

Shellsort
Os itens separados de h posies so rearranjados. Todo h-simo item leva a uma sequncia ordenada. Tal sequncia dita estar h-ordenada. Exemplo de utilizao:

Quando h = 1 Shellsort corresponde ao algoritmo de insero.


173

Shellsort
Como escolher o valor de h: Sequncia para h: h(s) = 3h(s 1) + 1, para s > 1 h(s) = 1, para s = 1. Knuth (1973, p. 95) mostrou experimentalmente que esta sequncia difcil de ser batida por mais de 20% em eficincia. A sequncia para h corresponde a 1, 4, 13, 40, 121, 364, 1.093, 3.280, . . .

174

Shellsort
void shellsort ( Int v [ ] , int n) { int i,j,x,h = 1; do h = h *3 + 1; while (h < n) ; do { h /= 3; for ( i = h + 1; i <= n; i ++) { x = v[ i ] ; j = i ; while (v[ j h] > x > 0) { v[ j ] = v[ j h] ; j = h; i f ( j <= h) break; } v[ j ] = x; } } while (h != 1) ; }

A implementao do Shellsort no utiliza registos sentinelas. Seriam necessrios h registos sentinelas, uma para

175

Shellsort
Vantagens: Shellsort uma ptima opo para arquivos de tamanho moderado. Sua implementao simples e requer uma quantidade de cdigo pequena. Desvantagens: O tempo de execuo do algoritmo sensvel ordem inicial do arquivo. O mtodo no estvel,

176

Quicksort
Proposto por Hoare em 1960 e publicado em 1962. o algoritmo de ordenao interna mais rpido que se conhece para uma ampla variedade de situaes. Provavelmente o mais utilizado. A ideia bsica dividir o problema de ordenar um conjunto com n itens em dois problemas menores. Os problemas menores so ordenados independentemente. Os resultados so combinados para produzir a soluo final.

177

Quicksort
A parte mais delicada do mtodo relativa ao mtodo partio. O vector v[esq..dir ] rearranjado por meio da escolha arbitrria de um piv x. O vector v particionado em duas partes: A parte esquerda com chaves menores ou iguais a x. A parte direita com chaves maiores ou iguais a x.

178

Quicksort
Algoritmo para o particionamento: 1. Escolha arbitrariamente um piv x. 2. Percorra o vector a partir da esquerda at que v[i] x. 3. Percorra o vector a partir da direita at que v[j] x. 4. Troque v[i] com v[j]. 5. Continue este processo at os apontadores i e j se cruzarem. Ao final, o vector v[esq..dir ] est particionado de tal forma que: Os itens em v[esq], v[esq + 1], . . . , v[j] so menores ou iguais a x. Os itens em v[i], v[i + 1], . . . , v[dir ] so maiores ou iguais a x.
179

Quicksort
Ilustrao do processo de partio:

O piv x escolhido como sendo v[(i+j) / 2]. Como inicialmente i = 1 e j = 6, ento x = v[3] = D. Ao final do processo de partio i e j se cruzam em i = 3e j = 2.
180

Quicksort
void swap(int* a, int* b) { int tmp; tmp = *a; *a = *b; *b = tmp; } int partition(int vec[], int left, int right) { int i, j; i = left; for (j = left + 1; j <= right; ++j) { if (vec[j] < vec[left]) { ++i; swap(&vec[i], &vec[j]); } } swap(&vec[left], &vec[i]); return i; }
181

Quicksort
Mtodo ordena e algoritmo Quicksort : void quickSort(int vec[], int left, int right) { int r; if (right > left) { r = partition(vec, left, right); quickSort(vec, left, r - 1); quickSort(vec, r + 1, right); } }

182

Implementao usando 'fat pivot': void sort(int array[], int begin, int end) { int pivot = array[begin]; int i = begin + 1, j = end, k = end, t; while (i < j) { if (array[i] < pivot) i++; else if (array[i] > pivot) { j--; k--; t = array[i]; array[i] = array[j]; array[j] = array[k]; array[k] = t;

} else {
j--; swap(array[i], array[j]); } } i--; swap(array[begin], array[i]); if (i - begin > 1) sort(array, begin, i); if (end - k > 1) sort(array, k, end); }

Lembrando que quando voc for chamar a funo recursiva ter que chamar a mesma da seguinte forma ordenar_quicksort(0,n-1). O 0(zero) serve para o incio receber a posio zero do vector e o fim ser o tamanho do vector -1.

void ordenar_quicksort(int ini, int fim) { int i = ini, f = fim; char pivo[50]; strcpy(pivo,vector[(ini+fim)/2]); if (i<=f) { while (strcmpi(vector[i],pivo)<0) i++; while (strcmpi(vetor[f],pivo)>0) f--; if (i<=f) { strcpy (aux_char,vetor[i]); strcpy (vetor[i],vetor[f]); strcpy (vetor[f],aux_char); i++; f--; } }

if (f>ini) ordenar_quicksort_nome(ini,f); if (i<fim) ordenar_quicksort_nome(i,fim);


}

Quicksort
Exemplo do estado do vector em cada chamada recursiva do procedimento Ordena:

O piv mostrado em negrito.


188

Quicksort
Vantagens: extremamente eficiente para ordenar arquivos de dados. Necessita de apenas uma pequena pilha como memria auxiliar. Desvantagens: Sua implementao muito delicada e difcil: Um pequeno engano pode levar a efeitos inesperados para algumas entradas de dados. O mtodo no estvel.

189

Heapsort
Possui o mesmo princpio de funcionamento da ordenao por seleco. Algoritmo: 1. Seleccione o menor item do vector. 2. Troque-o com o item da primeira posio do vector. 3. Repita estas operaes com os n 1 itens restantes, depois com os n 2 itens, e assim sucessivamente. O custo para encontrar o menor (ou o maior) item entre n itens n 1 comparaes. Isso pode ser reduzido utilizando uma fila de prioridades.
190

Heaps
uma sequncia de itens com chaves c[1], c[2], . . . , c[n], tal que: c[i] c[2i], c[i] c[2i + 1], para todo i = 1, 2, . . . , n/2. A definio pode ser facilmente visualizada em uma rvore binria completa: rvore binria completa: Os ns so numerados de 1 a n. O primeiro n chamado raiz. O n k/2 o pai do n k, para 1 < k n. Os ns 2k e 2k + 1 so os filhos esquerda e direita do n k, para 1 k k/2
191

Heaps
As chaves na rvore satisfazem a condio do heap. As chaves em cada n so maiores do que as chaves em seus filhos. A chave no n raiz a maior chave do conjunto. Uma rvore binria completa pode ser representada por um arranjo:

A representao extremamente compacta. Permite caminhar pelos ns da rvore facilmente. Os filhos de um n i esto nas posies 2i e 2i + 1. O pai de um n i est na posio i/2.
192

Heaps
Na representao do heap em um arranjo, a maior chave est sempre na posio 1 do vector. Os algoritmos para implementar as operaes sobre o heap operam ao longo de um dos percursos da rvore. Um algoritmo elegante para construir o heap foi proposto por Floyd em 1964. O algoritmo no necessita de nenhuma memria auxiliar. Dado um vector v[1], v[2], . . . , v[n]. Os itens v[n/2 + 1], v[n/2 + 2], . . . , v[n] formam um heap: Neste intervalo no existem dois ndices i e j tais que j = 2i ou j = 2i + 1.
193

Heapsort
void heapsort(tipo a[], int n) { int i = n/2, pai, filho; tipo t; for (;;) { if (i > 0) { i--; t = a[i]; } else { n--; if (n == 0) return; t = a[n]; a[n] = a[0]; }
194

pai = i; filho = i*2 + 1; while (filho < n) { if ((filho + 1 < n) && (a[filho + 1] > a[filho])) filho++; if (a[filho] > t) { a[pai] = a[filho]; pai = filho; filho = pai*2 + 1; } else break; } a[pai] = t; } }
195

Heapsort
Algoritmo:

Os itens de v[4] a v[7] formam um heap. O heap estendido para a esquerda (esq = 3), englobando o item v[3], pai dos itens v[6] e v[7]. A condio de heap violada: O heap refeito trocando os itens D e S. O item R incluindo no heap (esq = 2), o que no viola a condio de heap. O item O incluindo no heap (esq = 1). A Condio de heap violada: O heap refeito trocando os itens O e S, encerrando o processo.

196

Heapsort
Exemplo da operao de aumentar o valor da chave do item na posio i:

O tempo de execuo do procedimento AumentaChave em um item do heap O(log n).


197

Construo de Heap
Algoritmo:

1. Construir o heap. 2. Troque o item na posio 1 do vector (raiz do heap) com o item da posio n. 3. Use o procedimento Refaz para reconstituir o heap para os itens v[1], v[2], . . . , v[n 1]. 4. Repita os passos 2 e 3 com os n 1 itens restantes, depois com os n 2, at que reste apenas um item.

Heapsort
Exemplo de aplicao do Heapsort :

1 S R O N E D A

2 R N N E D A D

3 4 5 O E N O E D A E D A D O A N E

6 7 A D A S R

O caminho seguido pelo procedimento Refaz para reconstituir a condio do heap est em negrito. Por exemplo, aps a troca dos itens S e D na segunda linha da Figura, o item D volta para a posio 5, aps passar pelas posies 1 e 2.

Referncias
1. Levitin, Anany Introduction to the design and analysis of algorithm Addison-Wesley 2003 2. Pedro Neto, Joo Programao, algoritmo e estrutura de dados escola editora 2008 3. Damas, Lus Programao em C 4. Ziviani, Nivio e Botelho, Fabiano Cupertino, Projecto de Algoritmos com implementao em Pascal e C editora Thomson, 2007 5. http://www.icmc.usp.br/~sce182/arvore.html 6. http://w3.ualg.pt/~hshah/ped 7. http://www.liv.ic.unicamp.br/~bergo/mc202/