Você está na página 1de 104

Gerardo Valdisio Rodrigues Viana

Glauber Ferreira Cintra


Ricardo Holanda Nobre

Pesquisa e Ordenao de Dados

2013

Pesq_Ord_de_Dados 1

22/04/13 14:53

Copyright 2013. Todos os direitos reservados desta edio SECRETARIA DE APOIO S TECNOLOGIAS EDUCACIONAIS
(SATE/UECE). Nenhuma parte deste material poder ser reproduzida, transmitida e gravada, por qualquer meio
eletrnico, por fotocpia e outros, sem a prvia autorizao, por escrito, dos autores.

Presidente da Repblica
Dilma Vana Rousseff
Ministro da Educao
Aloizio Mercadante
Presidente da CAPES
Jorge Almeida Guimares
Diretor de Educao a Distncia da CAPES
Joo Carlos Teatini de Souza Climaco
Governador do Estado do Cear
Cid Ferreira Gomes
Reitor da Universidade Estadual do Cear
Jos Jackson Coelho Sampaio

Design instrucional
Laurisa Nuting
Coordenador Editorial
Rocylnia Isidio
Projeto grfico
Rafael Straus Timb Vasconcelos
Marcos Paulo Rodrigues Nobre

Pesq_Ord_de_Dados 2

Pr-Reitora de Graduao
Marclia Chagas Barreto
Coordenador da SATE e UAB/UECE
Francisco Fbio Castelo Branco
Coordenadora Adjunta UAB/UECE
Elosa Maia Vidal
Coordenador da Licenciatura em Informtica
Joaquim Celestino Junior
Coordenadora de Tutoria da Licenciatura em Informtica
Andr Ribeiro Cardoso

Diagramao
Francisco Jos da Silva Saraiva
Ilustrao
Marcos Paulo Rodrigues Nobre
Capa
Emilson Pamplona Rodrigues de Castro

22/04/13 14:53

Apresentao........................................................................................................................ 5
Captulo 1
Introduo............................................................................................................................. 7
Apresentao...................................................................................................................... 9
1. Introduo....................................................................................................................... 9
2. Armazenamento de Informaes.................................................................................... 10
3. Procedimentos e Funes............................................................................................... 11
4. Estruturas Utilizadas nos Algoritmos.............................................................................. 14
5. Exemplo de Uso de Procedimentos e Funes............................................................... 16
Captulo 2
Ordenao Interna................................................................................................................ 17
Apresentao...................................................................................................................... 19
1. Ordenao Interna.......................................................................................................... 19
2. O Problema da Ordenao.............................................................................................. 20
3. Bolha............................................................................................................................... 21
4. Insero........................................................................................................................... 24
5. Seleo............................................................................................................................ 25
6. Shellsort.......................................................................................................................... 26
7. Mergesort....................................................................................................................... 27
8. Quicksort......................................................................................................................... 31
9. Heaps Binrios................................................................................................................ 35
10. Heapsort....................................................................................................................... 38
11. Countingsort................................................................................................................. 38
12. Bucketsort..................................................................................................................... 40
13. Radixsort....................................................................................................................... 41
Captulo 3
Ordenao Externa................................................................................................................ 45
Apresentao...................................................................................................................... 47
1. Definio e mecanismos................................................................................................. 47
2. Intercalao de dois caminhos........................................................................................ 48
3. Intercalao de trs caminhos........................................................................................ 51
4. Intercalao de k caminhos............................................................................................. 53
5. Comparao entre Distribuies Equilibradas................................................................ 53
6. Intercalao Polifsica..................................................................................................... 56

Pesq_Ord_de_Dados 3

22/04/13 14:53

Captulo 4
Tcnicas de pesquisa............................................................................................................. 61
Apresentao...................................................................................................................... 63
1. Tcnicas de Pesquisa....................................................................................................... 63
2. Busca Sequencial............................................................................................................. 64
3. Busca Binria................................................................................................................... 65
4. Tabelas de Disperso....................................................................................................... 66
5. rvores de Busca Balanceadas........................................................................................ 71
Dados dos Autores................................................................................................................ 86
Anexo
Relao de Algoritmos........................................................................................................... 87

Pesq_Ord_de_Dados 4

22/04/13 14:53

O problema da ordenao um dos mais importantes e mais estudados na cincia da computao. Em diversas situaes cotidianas preciso colocar uma lista
em ordem para facilitar a busca de informaes nela contidas. Ordenar, ou classificar
dados, significa armazen-los numa forma adequada de modo a facilitar sua pesquisa,
ou busca, e assim tornar mais gil a recuperao das informaes.
Neste livro sero mostradas inicialmente as tcnicas clssicas de classificao
de dados, seguidas pelos mtodos usuais de pesquisa. Em todos os procedimentos
descritos utilizam-se estruturas de dados conhecidas, como vetores, matrizes, rvores,
listas, pilhas e filas.
Adiantamos que, uma classificao dita interna, quando os dados podem ser
totalmente armazenados na memria principal, e externa, se parte deles estiverem,
durante o processo de ordenao, num meio de armazenamento auxiliar. Os mtodos
de classificao externa so realizados atravs de uma tcnica de projeto de algoritmos denominada diviso e conquista, onde os dados so divididos em sries menores, de tamanho tal que seja possvel orden-los por algum mtodo de classificao
interna; ao final, as sries devem ser intercaladas a fim de gerar uma nica sada,
totalmente ordenada.
A pesquisa, outra tarefa importante na computao, corresponde busca de informaes contidas num arquivo ou, em geral, numa lista ou coleo de dados. Desejase que esse processo seja executado sem que haja a necessidade de inspecionar toda a
coleo de dados, para isto so apresentadas diversas tcnicas e estruturas de dados
que permitem fazer pesquisa com bastante eficincia. Discutimos as operaes de insero, busca e remoo nessas estruturas, analisando sua complexidade temporal e
espacial. Essa anlise tambm feita para os procedimentos de classificao interna.
Ao final de cada captulo so propostos exerccios, cujo objetivo avaliar os conhecimentos adquiridos e rever as definies abordadas no respectivo captulo.
Os Autores

Pesq_Ord_de_Dados 5

22/04/13 14:53

Pesq_Ord_de_Dados 6

22/04/13 14:53

Captulo

Introduo

Objetivos:



Introduzir os conceitos de pesquisa e ordenao de dados


Mostrar as formas de armazenamento das informaes
Definir procedimentos e funes
Apresentar as estruturas dos algoritmos

Pesq_Ord_de_Dados 7

22/04/13 14:53

Pesq_Ord_de_Dados 8

22/04/13 14:53

Apresentao
Nas consideraes gerais contidas neste captulo introdutrio, destacamos inicialmente a importncia da Pesquisa e Ordenao para a computao, e a necessidade do uso de tcnicas eficientes para que seu processamento seja realizado no menor tempo possvel. Mostramos, tambm, que
a abordagem deste assunto deve ser feita de forma integrada entre os dois
tpicos, pesquisa e ordenao, e que requerida uma reviso do assunto
Estrutura de Dados para que seja compreendido como as informaes so
armazenadas e de que forma os processos as utilizam. Por fim, apresentada a forma padro usada para codificao dos algoritmos, bem como de
seus procedimentos e funes.

1. Introduo
A pesquisa e a ordenao so operaes bastante utilizadas nos sistemas de programao, desde a origem da computao. Independente da
gerao ou do ambiente computacional, ordenar, ou classificar dados, significa armazen-los numa forma adequada de modo a facilitar sua pesquisa,
ou busca, e assim tornar mais gil a recuperao das informaes.
O conceito de um conjunto ordenado de elementos tem importncia
tanto na informtica como em nossa vida cotidiana. Imagine quo complicado seria localizar um nmero de telefone num catlogo se o mesmo no
fosse classificado por ordem alfabtica nem por endereo. O processo de
busca somente facilitado porque existe uma ordenao relacionada; observe no exemplo citado que, se temos o nmero de um telefone e desejamos
identificar seu proprietrio, ou seu endereo, a pesquisa seria complexa
caso no existisse uma ordenao numrica, crescente ou decrescente, destes telefones. Em geral, a lista de telefones nesta ordem no existe porque
esta uma consulta incomum.
Aqui sero mostradas inicialmente as tcnicas clssicas de classificao de dados, seguidas pelos mtodos usuais de pesquisa. Em todos os
procedimentos descritos utilizam-se estruturas de dados conhecidas, como
vetores, matrizes, rvores, listas, pilhas e filas. Os algoritmos correspondentes a estes procedimentos so apresentados numa forma de programa
estruturado, sendo ao final apresentados alguns algoritmos de ordenao,
na linguaguem de programao "C". Nosso propsito que o leitor entenda
com facilidade a metodologia empregada.
Adiantamos tambm que uma classificao dita interna se os dados
puderem ser totalmente armazenados na memria principal e dita externa se parte deles estiverem, durante o processo de ordenao, num meio de

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 9

9
22/04/13 14:53

armazenamento auxiliar, ou seja, numa rea de trabalho que geralmente


est gravada em um disco magntico. Os mtodos de classificao externa
so realizados atravs de uma tcnica de projeto de algoritmos denominada
diviso e conquista, onde os dados so divididos em sries menores, de
tamanho tal que seja possvel orden-los por algum mtodo de classificao
interna; ao final, as sries devem ser intercaladas a fim de gerar uma nica
sada, totalmente ordenada.
O termo em ingls correspondente ordenao sort e intercalao
merge, de modo que, comum a literatura afim denominar um programa
utilitrio para classificao, de forma geral, como Sort-Merge.
Nas sees seguintes deste captulo apresentada a forma como os
dados a serem classificados esto armazenados, seguido das definies de
procedimentos e funes e da organizao estruturada dos algoritmos. No
captulo 2 so mostrados os diversos mtodos de classificao interna e no
captulo 3, os de classificao externa e, por fim, no captulo 4, abordaremos as principais tcnicas de pesquisa utilizadas.

2. Armazenamento de Informaes
Na prtica o processo de ordenao no se resume apenas a classificar
dados isolados. Embora a maioria das abordagens a este tema sempre seja
feita com valores numricos, por motivos didticos, devemos estar cientes
que as aplicaes representam informaes em forma de registro, ou coleo de dados, que em geral contm um campo especial chamado chave
que o valor a ser ordenado que pode ser numrico ou no. No caso geral
podemos cham-lo de alfanumrico correspondendo a uma sequncia de
caracteres (letras, dgitos ou especiais) que so geralmente armazenados
em oito bits usualmente codificados em ASCII (American Standard Code for
Information Interchange).
Assim, quando um algoritmo de ordenao, aps a comparao de
duas chaves, necessita troc-las de posio necessrio trocar tambm
todos os dados correspondentes acoplados a cada chave. Numa ordenao
ascendente (do menor para o maior) do exemplo abaixo, se K1>K 2 ento, os
campos Nome e Endereo do registro R1 devem ser permutados pelos
respectivos campos de R 2 , ou seja, os registros trocam de posio (R1R 2).
Chave

Nome

Endereo

...

...

R1 (posio i)

K1

.
.
.
.

.
.
.
.

R2 (posio j)

K2

Guilherme Viana
...
...
...
...
Luan Lima
...

Rua 5 de maio, 2608

i 1
i

...
...
...
...

i +1
.
.
j 1

Rua 29 de julho, 1003

...

j +1

Figura 1.1: Modelo de registros de um arquivo

Para permutar dois registros h necessidade de se utilizar uma varivel auxiliar que tem a mesma estrutura dos registros, conforme mostrado
na Figura 1.2.

10

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 10

22/04/13 14:53

R(aux)

Chave

Nome

Endereo

Figura 1.2: Formato de um registro auxiliar

Usando esta estrutura, escrever os seguintes comandos:


R(aux)R1;

R1R 2;

R 2R(aux);

O conjunto de todos os registros considerados chamado de arquivo


que pode ser visualizado como uma tabela, onde cada linha representa um
registro especfico e cada coluna representa um campo dentro do registro.
Uma classificao pode ocorrer sobre os prprios registros ou sobre uma
tabela auxiliar de ponteiros. De forma abstrata, podemos imaginar sempre
a tabela, ou arquivo, como no modelo Figura 1.2. No caso concreto do uso
de ponteiros, ou apontadores, o processo chamado classificao por endereos e de forma indireta h movimentao somente dos ponteiros em
vez dos dados.
Alm disso, tambm se deve considerar a ocorrncia de mais de uma
chave de classificao. Nesse caso, uma das chaves chamada de primria, ou principal, e as demais secundrias. Para efeito, o processo de
ordenao aplicado tantas vezes quanto seja a quantidade de chaves. H,
no entanto, tcnicas de concatenao de chaves com o objetivo de criar uma
nica chave alfanumrica que ser aquela usada nas comparaes.
possvel ainda observar casos em que dois registros tenham a mesma chave, ou seja, K1=K2. Quando isto ocorre no haver necessidade de permut-los, ou seja, os registros so mantidos nas mesmas posies originais.
Convencionamos que na apresentao dos mtodos de classificao
e de seus algoritmos, as comparaes so feitas apenas com as chaves, ou
valores isolados. Outra conveno til considerar a ordenao sempre ascendente, onde ao final as chaves estaro em ordem crescente, ou de forma
geral em ordem no decrescente, caso existam chaves repetidas.
Para uma ordenao na ordem inversa (no crescente) a nica alterao a ser feita em todos os algoritmos substituir a comparao K1>K2 por
K1<K2 .

3. Procedimentos e Funes
3.1 Blocos de Comandos
Um bloco uma parte delimitada de um algoritmo que contm comandos. Um comando pode ser de atribuio, ou uma declarao de entrada ou sada, ou uma estrutura de controle, ou de repetio, ou ainda pode
referenciar uma chamada a outros blocos. Os blocos, organizados de forma
indentada, podem ser aninhados conforme mostrado na Figura 1.3.

Indentar: Neologismo derivado da palavra em ingls indent que significa


recuar ou abrir pargrafo.

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 11

11
22/04/13 14:53

ALGORITMO <nome>
// <comentrios>
ENTRADA: <lista de variveis>
SADA: <lista de variveis>
BLOCO
// <comentrios>
COMANDOS
BLOCO
// <comentrios>
COMANDOS
FIM {nome}
Figura 1.3: Estrutura geral de um algoritmo

De modo geral, podemos dizer que um algoritmo um bloco nico


correspondente rotina ou mdulo principal; de forma anloga podemos
afirmar que um sub-algoritmo (procedimento ou funo) um bloco auxiliar que corresponde a uma sub-rotina.

3.2 Procedimentos
Um procedimento um bloco criado atravs de uma declarao que
o associa a um nome ou identificador para que seja feita sua chamada ou
referncia. O uso de procedimentos possibilita que um bloco usado repetidas vezes em vrios pontos do algoritmo possa ser escrito uma nica vez e
chamado quando necessrio.
A forma de um procedimento mostrada na Figura 1.4.
PROCEDIMENTO <nome> (parmetros)
// <comentrios>
ENTRADA: <lista de variveis>
SADA: <lista de variveis>
BLOCO
// <comentrios>
COMANDOS
BLOCO
// <comentrios>
COMANDOS
RETORNE
FIM {nome}

Figura 1.4: Estrutura geral de um procedimento

O procedimento um objeto esttico, no sentido de que para ser executado necessrio que seja ativado por uma chamada pelo seu <nome> a
partir do mdulo principal do algoritmo ou atravs de outro procedimento
num nvel hierrquico superior.
Atravs dos parmetros possvel a transferncia de dados entre os
mdulos envolvidos. Cada parmetro pode armazenar um nico valor se a
varivel corresponde simples ou vrios valores se for uma varivel estruturada de forma homognea com uma ou mais dimenso.

3.3 Funes Simples


Uma funo corresponde a um tipo especial de procedimento. Possuem caractersticas prprias como, por exemplo, a necessidade da existncia de uma atribuio de uma expresso ou valor ao seu nome declarado em
pelo menos um ponto da sequncia de comandos.

12

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 12

22/04/13 14:53

Ao declarar uma funo necessrio especificar seu tipo (inteiro, real,


lgico ou literal) de forma anloga a uma funo matemtica.
A forma padro de uma funo simples mostrada a seguir.
FUNO <nome> (parmetros): <tipo bsico>
// <comentrios>
ENTRADA: <lista de variveis>
BLOCO
// <comentrios>
COMANDOS
BLOCO
// <comentrios>
COMANDOS
nome = <expresso>
COMANDOS
DEVOLVA <nome>
FIM {nome}
Figura 1.5: Estrutura geral de uma funo

Na seo 5 mostrado um exemplo para consolidar os conceitos de


funes e procedimentos, bem como, para observar as semelhanas e as
diferenas entre os mesmos.

Mesmo sendo o fatorial


um nmero inteiro, optamos aqui defini-lo como
real para ampliar sua
magnitude ou ordem de
grandeza.

3.4 Funes Recursivas


Uma funo recursiva aquela que faz uma chamada a si prpria. A
ideia consiste em utilizar a prpria funo no escopo de sua definio.
Em todas as funes recursivas devem existir dois passos bem definidos, um deles chamado base cujo resultado imediatamente conhecido e o
outro, recurso em que possvel resolver a funo, ou seja, calcular o valor
final da funo utilizando a mesma sucessivas vezes com entradas menores.
A estrutura de uma funo recursiva semelhante a uma funo simples, com a particularidade de que seu nome surge pelo menos uma vez no
lado direito de um comando de atribuio.
Um exemplo clssico o uso de uma funo para calcular o valor do
fatorial de um nmero inteiro no negativo. A seguir apresentamos duas
formas de implementao, uma atravs de uma funo simples (FAT) e outra usando uma funo recursiva (FATREC).
a) Funo Fatorial Simples

FUNO FAT (N:inteiro): real


ENTRADA: // um nmero inteiro positivo
F = 1
PARA i = 1 at N

F = F * i
// fim para
FAT = F
DEVOLVA FAT
FIM {FAT}

Algoritmo 1.1: Calcula o fatorial de N de forma direta

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 13

13
22/04/13 14:53

b) Funo Fatorial Recursiva


FUNO FATREC (N:inteiro): real
ENTRADA: // um nmero inteiro positivo
SE N < 2
FATREC = 1
SENO
FATREC = N * FATREC(N-1)
DEVOLVA FATREC
FIM {FATREC}
Algoritmo 1.2: Calcula o fatorial de N de forma recursiva

4. Estruturas Utilizadas nos Algoritmos


Os algoritmos apresentados usam uma pseudo-linguagem simples,
comumente chamada de Portugol, de fcil entendimento, que contm resumidamente os seguintes elementos:
Smbolos:
= : atribuio;
{ } : delimitadores para descrever comentrios; pode iniciar por //
( ) : para indicar ordem de execuo das operaes nas expresses ou agrupar parmetros de sub-rotinas;
Termos Bsicos:
BLOCO - contm um ou mais comandos simples;
lista de variveis - variveis separadas por vrgulas;
condio - expresso lgica cujo resultado pode ser verdadeiro
(V) ou falso (F);
inciofim/fim-bloco - delimitadores de bloco (opcionais);
RETORNE - comanda o encerramento de um procedimento ou funo, devolvendo o controle de execuo ao bloco de chamada;
DEVOLVA v mesma funo anterior, indica que retorna para o
bloco de chamada com a estrutura v.
Procedimentos de Entrada e Sada:
ENTRADA: < lista de variveis >
SADA: < lista de variveis >
Figura 1.6: Comandos de entrada e sada de dados

14

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 14

22/04/13 14:53

Estruturas de Controle de Deciso e Desvio:


// Desvio Simples
SE < condio >

BLOCO

// Desvio Duplo
SE < condio >

BLOCO-1

SENO

BLOCO-2

// Desvio Mltiplo
CASE < expresso-teste >
<lista-1>: BLOCO-1
<lista-2>: BLOCO-2

. . .
<lista-n>: BLOCO-n

Figura 1.7: Comandos de Deciso

Estruturas de Repetio:
// Com teste no fim do bloco
FAA

BLOCO

ENQUANTO < condio >


// Com teste no incio do bloco
ENQUANTO < condio >

BLOCO

// Com limites da varivel de controle


PARA v = <valor-inicial> at <valor-final>
BLOCO
Figura 1.8: Comandos de Repetio

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 15

15
22/04/13 14:53

5. Exemplo de Uso de Procedimentos e Funes


Exemplo 1.1: Problema: Binmio de Newton
Dados dois valores inteiros no negativos,

mn,

calcular o valor de

m!
m
=
n n !(m n)!
Utilizar a funo FAT definida em 3.4.a (Algoritmo 1.1).
ALGORITMO BINMIO
ENTRADA: INTEIROS m E n
SADA: REAL b COM O VALOR BINOMIAL
PROCEDIMENTO TROCA ( x , y )
ENTRADA: INTEIROS x E y
SADA: x E y COM VALORES TROCADOS
w = x
x = y
y = w
RETORNA
FIM {TROCA}
FUNO FAT (n)

// mesmo bloco da subseo 1.2.4.a

FIM {FAT}

SE m < n
TROCA ( m , n )
b = FAT (m) / ( FAT (n) * FAT (m-n) )
FIM {BINMIO}
Algoritmo 1.3: Calcula o Binmio de Newton

16

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 16

22/04/13 14:53

Captulo

Ordenao Interna

Objetivos:
Definir o problema da ordenao
Apresentar os mtodos de classificao interna
Analisar a complexidade dos algoritmos de ordenao

Pesq_Ord_de_Dados 17

22/04/13 14:53

Pesq_Ord_de_Dados 18

22/04/13 14:53

Apresentao
Neste captulo iniciamos definindo formalmente o problema da ordenao e os principais critrios de classificao de dados. Em seguida,
apresentamos em detalhes os mtodos de ordenao interna, discutindo
sua eficincia em termos de consumo de tempo e de memria e outros aspectos relevantes. Na ordem, abordaremos os mtodos Bolha, Insero e
Seleo que so bastante simples e servem para introduzir ideias a serem
utilizadas em outros mtodos mais eficientes. Seguimos com os mtodos
Shellsort, Mergesort, Quicksort e Heapsort, considerados superiores aos
anteriores, tambm, como eles, baseados na operao de comparao. Por
fim, discutiremos os mtodos Countingsort, Bucketsort e Radixsort que
tm em comum o fato de no utilizarem a operao de comparao e, sob
algumas hipteses, eles ordenam em tempo linearmente proporcional ao
tamanho da lista.

1. Ordenao Interna
Como dito no captulo anterior, a ordenao de dados um dos problemas mais importantes e mais estudados dentro da cincia da computao.
Em diversas situaes cotidianas preciso colocar uma lista em ordem
para facilitar a busca de informaes nela contidas.
Neste captulo discorremos sobre os principais critrios de ordenao,
definindo antes, na seo 2, formalmente o problema da ordenao. Nas sees seguintes so apresentados em detalhes os diversos mtodos de ordenao interna. Para cada um deles mostrada sua eficincia em termos de
consumo de tempo e de memria e outros aspectos considerados relevantes.
Inicialmente, nas sees 3, 4 e 5, abordaremos os mtodos Bolha,
Insero e Seleo. Tais mtodos, considerados inferiores, so bastante simples, mas introduzem ideias que servem de base para outros mtodos mais
eficientes. Esses mtodos utilizam como uma de suas operaes bsicas a
comparao de elementos da lista.
Em seguida, nas sees 6, 7, 8 e 10, apresentaremos os mtodos
Shellsort, Mergesort, Quicksort e Heapsort. Esses mtodos, considerados
superiores, utilizam estratgias mais sofisticadas como, por exemplo, diviso e conquista e o uso de estruturas de dados conhecidas como heaps
binrios, descritos na Seo 9. Esses mtodos tambm so baseados na
operao de comparao.
Por fim, nas sees 11, 12 e 13, discutiremos os mtodos Countingsort,
Bucketsort e Radixsort. Esses ltimos mtodos tm em comum o fato de no
utilizarem a operao de comparao. Alm disso, sob certas hipteses, eles
ordenam em tempo linearmente proporcional ao tamanho da lista.

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 19

19
22/04/13 14:53

2. O Problema da Ordenao

ASCII - American Standart Code for Information


Interchange - Cdigo padro americano para o intercmbio de informao

Aquilo
que
definimos
como ordem crescente
chamada por alguns autores de ordem no decrescente enquanto que o
que chamamos de ordem
estritamente crescente
chamada por esses mesmos autores de ordem
crescente. O que chamamos de ordem decrescente chamada por alguns
de ordem no crescente
enquanto que a ordem
estritamente decrescente
chamada de ordem decrescente.

20

Para que uma lista possa ser ordenada os seus elementos devem ser
comparveis dois a dois. Isso significa que dados dois elementos da lista
deve ser sempre possvel determinar se eles so equivalentes ou se um deles
menor que o outro. A idia associada ao termo menor depende do critrio de comparao utilizado.
Diz-se que uma lista est em ordem crescente se cada um de seus
elementos menor ou igual ao seu sucessor segundo algum critrio de
comparao. A definio de ordem decrescente anloga. Como dito, uma
lista somente pode ser colocada em ordem se os seus elementos forem dois
a dois comparveis. O problema da ordenao consiste em, dada uma lista,
coloc-la em ordem crescente ou decrescente. Os principais critrios so
comparao numrica, comparao alfabtica e comparao cronolgica.
Comparao numrica: um nmero x menor do que um nmero y
se a expresso x y resulta em um nmero negativo. Esse o tipo
mais comum de comparao e, de certa forma, todos os demais critrios de comparao derivam dele.
Comparao alfabtica: um caractere menor do que outro se precede esse outro na ordem do alfabeto. Por exemplo, o caractere a
precede o b, o b precede o c e assim por diante. No computador,
os caracteres so representados atravs de nmeros (segundo alguma codificao, por exemplo, ASCII, UNICODE etc). Dessa forma, a
comparao entre caracteres acaba sendo uma comparao entre os
seus cdigos numricos e, portanto, uma comparao numrica.
Comparao cronolgica: Uma data menor do que outra se ela antecede essa outra. Uma data pode ser representada atravs de trs
nmeros, um para representar o ano, outro para o ms e outro para
o dia. Ao comparar uma data com outra, comparamos o ano. Em
caso de empate, comparamos o ms. Em caso de novo empate, comparamos o dia. Sendo assim, a comparao cronolgica tambm
feita comparando-se nmeros.
possvel definir outros critrios de comparao. Por exemplo, podemos comparar caixas, considerando menor aquela que apresentar menor
volume. Como o volume expresso por um nmero, esse tipo de comparao tambm uma comparao numrica.
Poderamos, no entanto, considerar uma caixa menor do que outra
se ela cabe nessa outra. Nesse caso, podemos ter caixas incomparveis.
Utilizando esse critrio de comparao, podemos ter uma lista de caixas
que no pode ser ordenada. Alm disso, quando temos listas heterogneas, pode no ser possvel orden-la. Por exemplo, a lista (4, bola, 2,
15/02/2011) no pode ser ordenada, pois seus elementos no so todos
dois a dois comparveis.
Dizemos que uma lista est em ordem crescente se cada elemento da
lista menor ou igual (segundo o critrio de comparao adotado) ao seu sucessor. Se cada elemento da lista estritamente menor do que seu sucessor,
dizemos que a lista est em ordem estritamente crescente. Analogamente,
dizemos que uma lista est em ordem decrescente se cada elemento da lista
maior ou igual ao seu sucessor. Se cada elemento da lista estritamente
maior do que seu sucessor, dizemos que a lista est em ordem estritamente
decrescente. Obviamente, ordenao estrita somente possvel se todos os
elementos da lista forem distintos.

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 20

22/04/13 14:53

O problema da ordenao consiste em, dada uma lista cujos elementos


sejam todos dois a dois comparveis, permutar a ordem de seus elementos
de modo a deixar a lista em ordem crescente ou decrescente.
Se a lista no for muito grande ela pode ser armazenada na memria
principal (interna) do computador e ser ordenada usando apenas a memria
interna. Os algoritmos que ordenam utilizando apenas memria interna so
chamados de mtodos de ordenao de interna.
Em contrapartida, os algoritmos que fazem uso de memria externa
so chamados de mtodos de ordenao de externa. Alguns desses mtodos
sero discutidos no Captulo 3.
No restante deste captulo descreveremos diversos mtodos de ordenao interna. Embora uma lista possa ser armazenada usando-se uma
lista encadeada, descreveremos os algoritmos considerando que a lista est
armazenada num vetor indexado a partir da posio zero. Alm disso, consideraremos que o vetor armazena nmeros e, portanto, o critrio de comparao ser numrico. Na descrio dos algoritmos de ordenao, vamos
sempre considerar que o vetor passado por referncia.
Convm salientar que a lista pode ser constituda de registro e podemos orden-la por um de seus campos, que chamamos de chave de ordenao. A comparao entre os elementos da lista feita comparando-se os
valores das chaves de ordenao dos dois elementos.
Obviamente, os mtodos aqui descritos podem ser facilmente adaptados por ordenar listas encadeadas cujos elementos so registros. Em alguns
exerccios tais adaptaes so requeridas.

3. Bolha
O Mtodo Bolha bastante simples e intuitivo. Nesse mtodo os elementos da lista so movidos para as posies adequadas de forma contnua,
assim como uma bolha move-se num lquido. Se um elemento est inicialmente numa posio i e, para que a lista fique ordenada, ele deve ocupar a
posio j, ento ele ter que passar por todas as posies entre i e j.
Em cada iterao do mtodo, percorremos a lista a partir de seu incio comparando cada elemento com seu sucessor, trocando-os de posio
se houver necessidade. possvel mostrar que, se a lista tiver n elementos,
aps no mximo (n1) iteraes a lista estar em ordem. A seguir fornecemos uma descrio em pseudocdigo do Bolha.
ALGORITMO BOLHA
ENTRADA: UM VETOR L COM N POSIES
SADA: O VETOR L EM ORDEM CRESCENTE
PARA i = 1 at n - 1
PARA j = 0 at n 1 - i
SE L[j] > L[j+1]
AUX = L[j] // SWAP
L[j] = L[j+1]
L[j+1] = AUX
FIM {BOLHA}
Algoritmo 2.1: Bolha

Na descrio do Algoritmo Bolha deixamos claro como realizar a troca


(swap) de elementos da lista. No restante deste captulo, faremos o swap
PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 21

21
22/04/13 14:53

A letra grega "" usada


para denotar a ordem de
complexidade media e "O"
para o pior caso.

In situ: Expresso latina,


usada em vrios contextos,
que significa no lugar.

22

usando o procedimento troca. Assim, a chamada troca(L[i], L[j]) serve para


trocar os contedo das posies i e j do vetor L.
fcil perceber que ao final da primeira iterao do lao mais externo
do Algoritmo Bolha, o maior elemento da lista estar na ltima posio do
vetor. Sendo assim, na iterao seguinte no precisamos mais nos preocupar com a ltima posio do vetor. Ao final da segunda iterao, os dois
maiores valores da lista estaro nas duas ltimas posies do vetor L, em
ordem crescente. No precisamos ento nos preocupar com as duas ltimas
posies do vetor.
De fato, no Algoritmo Bolha vlido o seguinte invariante: ao final da
iterao k do lao mais externo, os k maiores valores da lista estaro nas k ltimas posies do vetor, em ordem crescente. A corretude do algoritmo decorre
desse invariante. Alm disso, o invariante explica porque no lao mais interno
o contador j s precisa variar de 0 (primeira posio do vetor) at n 1 i.
Claramente, a instruo crtica do Algoritmo Bolha a comparao
(se). Em cada iterao do lao mais interno feita uma comparao. Como
a quantidade de iteraes do lao interno diminui medida que i aumenta,
o nmero de comparaes realizadas pelo algoritmo :
i

Comparaes

0
1
...

n1
n2
...

n1

Total

(n - n)/2
2

Assim, a complexidade temporal do Algoritmo Bolha pertence a (n2).


Alm dos parmetros de entrada (L e n), o algoritmo utiliza apenas trs variveis escalares (i, j e aux). Dessa forma, a quantidade extra de memria
utilizada pelo algoritmo constante. Sendo assim, sua complexidade espacial pertence a O(1). Os mtodos de ordenao cuja complexidade espacial
pertence a O(1) so chamados mtodos de ordenao in situ. Esse o caso
do Mtodo Bolha.
Outro aspecto importante dos mtodos de ordenao a estabilidade.
Dizemos que um mtodo de ordenao estvel se ele preserva a ordem
relativa existente entre os elementos repetidos da lista. Por exemplo, se a
ordenao da lista (4, 7, 6, 7, 2) resulta em (2, 4, 6, 7, 7), a ordenao foi estvel. Observe que o sete sublinhado estava direita do outro sete e ao final
da ordenao ele continuou direita. Se todas as ordenaes produzidas
por um mtodo de ordenao so estveis, dizemos que o mtodo estvel.
Observe que no Algoritmo Bolha, quando comparamos dois elementos
da lista, somente fazemos o swap se o antecessor for menor do que o sucessor, pois tivemos o cuidado de utilizar uma desigualdade estrita na comparao. Como consequncia, o Algoritmo Bolha estvel.
A seguir exibimos o contedo de um vetor aps cada iterao do lao
mais externo do Algoritmo Bolha.

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 22

22/04/13 14:53

Lista original
1 iterao
2 iterao
3 iterao
4 iterao
5 iterao

0
9
4
4
4
4
4

1
4
5
5
5
5
5

2
5
9
5
5
5
5

3
10
5
8
8
8
8

4
5
8
9
9
9
9

5
8
10
10
10
10
10

Figura 2.1: Ordenao com o Algoritmo Bolha

Neste exemplo percebemos que no final da segunda iterao a lista


j estava ordenada. Na terceira iterao no houve nenhuma alterao na
lista. Essa fato nos permitiria concluir que a lista j estava em ordem, de
modo que as duas ltimas iteraes foram inteis.
Podemos introduzir uma pequena modificao no Mtodo Bolha de
modo a torn-lo um pouco mais esperto e evitar iteraes inteis. Tal
modificao consiste em usar uma varivel ( flag) para sinalizar se foi realizada alguma troca de elementos numa iterao do mtodo. Caso nenhuma troca tenha sido realizada, a lista j estar em ordem e, portanto, o
mtodo deve parar. No exemplo anterior, aps a terceira iterao a ordenao seria finalizada.
Essa variante do Bolha conhecida como Bolha com Flag e seu pseudocdigo fornecido no Algoritmo 2.2.
ALGORITMO BOLHA_COM_FLAG
ENTRADA: UM VETOR L COM N POSIES
SADA: O VETOR L EM ORDEM CRESCENTE
i = 0
FAA
FLAG = FALSO
PARA j = 0 at n 1 - i
SE L[j] > L[j+1]
TROCA(L[J], L[J+1])
FLAG = VERDADEIRO
i = i + 1
ENQUANTO FLAG = VERDADEIRO
FIM {BOLHA_COM_FLAG}
Algoritmo 2.2: Bolha com Flag

Enquanto que o tempo requerido pelo Bolha sempre quadrtico em


relao ao tamanho da lista, o comportamento do Bolha com Flag sensvel
ao tipo de lista fornecida como entrada. No melhor caso, que ocorre quando a lista fornecida j esta ordenada, o Algoritmo Bolha_com_Flag requer
tempo (n) pois a comparao ser sempre falsa e a varivel flag jamais
receber o valor verdadeiro. Dessa forma, aps a primeira iterao do lao
externo o algoritmo ser finalizado.
Suponha agora que o menor elemento est inicialmente na ltima posio da lista. Observe que a cada iterao do lao externo o menor elemento
ser movido apenas uma posio para a esquerda. Sero necessrias n 1
iteraes para que o menor elemento alcance a primeira posio da lista.
Nesse caso, o comportamento do Algoritmo Bolha_com_Flag ser idntico ao do Algoritmo Bolha. Conclumos que no pior caso o Bolha com Flag
requer tempo (n2). Finalmente, possvel mostrar que o desempenho do
Bolha com Flag no caso mdio tambm pertence a (n2).

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 23

23
22/04/13 14:53

4. Insero
O Mtodo Insero, tambm conhecido como Insero Direta, bastante simples e apresenta um desempenho significativamente melhor que
o Mtodo Bolha, em termos absolutos. Alm disso, como veremos no final
dessa seo, ele extremamente eficiente para listas que j estejam substancialmente ordenadas.
Nesse mtodo consideramos que a lista est dividida em parte esquerda, j ordenada, e parte direita, em possvel desordem. Inicialmente, a parte
esquerda contm apenas o primeiro elemento da lista. Cada iterao consiste em inserir o primeiro elemento da parte direita (piv) na posio adequada da parte esquerda, de modo que a parte esquerda continue ordenada.
fcil perceber que se a lista possui n elementos, aps n 1 inseres ela
estar ordenada.
Para inserir o piv percorremos a parte esquerda, da direita para a
esquerda, deslocando os elementos estritamente maiores que o piv uma
posio para direita. O piv deve ser colocado imediatamente esquerda do
ltimo elemento movido.
ALGORITMO INSERO
ENTRADA: UM VETOR L COM N POSIES
SADA: O VETOR L EM ORDEM CRESCENTE
PARA i = 1 at n - 1
PIVO = L[i]
j = i - 1
ENQUANTO j 0 e L[i] > PIVO
L[j+1] = L[j]
j = j - 1
L[j+1] = PIVO
FIM {INSERO}
Algoritmo 2.3: Insero

No melhor caso, que ocorre quando a lista fornecida como entrada j


est ordenada, cada insero feita em tempo constante, pois o piv maior
ou igual a todos os elementos da parte esquerda e a condio do lao interno nunca verdadeira. Nesse caso, a complexidade temporal do Algoritmo
Insero pertence a (n).
No pior caso, que ocorre quando a lista est inversamente ordenada,
cada insero requer que todos os elementos da parte esquerda sejam movidos para a direita, pois todos eles sero maiores do que o piv. Nesse caso,
a quantidade total de iteraes do lao interno ser (n2 - n)/2 e a complexidade temporal do Algoritmo Insero ser (n2).
A complexidade temporal do Algoritmo Insero no caso mdio tambm
pertence a (n2). Isso decorre do fato de que, em mdia, cada iterao requer
que metade dos elementos da parte esquerda sejam movidos para a direita.
possvel mostrar ainda que se todos os elementos da lista esto inicialmente distncia no mximo c (onde c uma constante) da posio em
que deve ficar quando a lista estiver ordenada, o Mtodo Insero requer
tempo linear.
O Algoritmo Insero requer o uso de apenas trs variveis escalares.
Sendo assim, sua complexidade espacial O(1). Observe que um elemento
da parte esquerda somente movido para a direita se ele for estritamente
maior do que o piv. Por conta disso, o Algoritmo Insero estvel.

24

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 24

22/04/13 14:53

Na Figura 2.2 exibimos o contedo de um vetor aps cada iterao do


lao mais externo do Algoritmo Insero. A parte esquerda da lista aparece
sombreada.
Lista original
1 iterao
2 iterao
3 iterao
4 iterao
5 iterao

0
9
4
4
4
4
4

1
4
9
5
5
5
5

2
5
5
9
9
5
5

3
4
5
10 5
8
10 5
8
10 5
8
10 5
8
9 10 8
8
9 10

Figura 2.2: Ordenao com o Algoritmo Insero

5. Seleo
O Mtodo Seleo tem como ponto forte o fato de que ele realiza poucas operaes de swap. Seu desempenho, em termos absolutos, costuma
ser superior ao do Mtodo Bolha, mas inferior ao do Mtodo Insero.
Assim como no Mtodo Insero, nesse mtodo consideramos que a
lista est dividida em parte esquerda, j ordenada, e parte direita, em possvel desordem. Alm disso, os elementos da parte esquerda so todos menores ou iguais aos elementos da parte direita.
Cada iterao consiste em selecionar o menor elemento da parte direita (piv) e troc-lo com o primeiro elemento da parte direita. Com isso, a
parte esquerda aumenta, pois passa a incluir o piv, e a parte direita diminui. Note que o piv maior que todos os demais elementos da parte esquerda, portanto a parte esquerda continua ordenada. Alm disso, o piv era o
menor elemento da parte direita e, portanto, continua sendo verdade que
os elementos da parte esquerda so todos menores ou iguais aos elementos
da parte direita. Inicialmente, a parte esquerda vazia. Se a lista possui n
elementos, aps n 1 iteraes ela estar ordenada.
ALGORITMO SELEO
ENTRADA: UM VETOR L COM N POSIES
SADA: O VETOR L EM ORDEM CRESCENTE
PARA i = 0 ate n - 2
MIN = i
PARA j = i + 1 at n - 1
SE L[j] < L[MIN]
MIN= j
TROCA(L[i], L[MIN])
FIM {SELEO}
Algoritmo 2.4: Seleo

A anlise do Algoritmo Seleo semelhante anlise do Algoritmo


Bolha. Os dois algoritmos so constitudos de dois laos contados encaixados que realizam as mesmas quantidades de iteraes. Dessa forma, se
torna evidente que o Algoritmo Seleo realiza (n2 - n)/2 comparaes e sua
complexidade temporal pertence a (n2). Assim como no Bolha, no faz sentido falar em melhor nem pior caso. Ambos os algoritmos requerem tempo
quadrtico, qualquer que seja a lista.
O Algoritmo Seleo necessita de apenas quatro variveis escalares
para fazer o seu trabalho (uma varivel auxiliar usada no procedimento
troca). Sendo assim, a complexidade espacial do Seleo O(1).
PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 25

25
22/04/13 14:53

Exibimos na Figura 2.3 o contedo de um vetor aps cada iterao do


lao mais externo do Algoritmo Seleo. A parte esquerda da lista aparece
sombreada. Por esse exemplo percebemos que o Mtodo Seleo no-estvel.

Lista original
1 iterao
2 iterao
3 iterao
4 iterao
5 iterao

0
10
2
2
2
2
2

1
4
4
3
3
3
3

2
5
5
5
4
4
4

3
3
3
4
5
5
5

4
10
10
10
10
10
10

5
2
10
10
10
10
10

Figura 2.3: Ordenao com o Algoritmo Seleo

6. Shellsort
O Mtodo Shellsort foi proposto por Donald Shell em 1959 e um
exemplo de um algoritmo fcil de descrever e implementar, mas difcil de
analisar. Uma explicao precisa para seu surpreendente desempenho
um dos enigmas que desafiam os pesquisadores h dcadas.
Para descrever o Shellsort com mais facilidade conveniente definir o
termo h-lista. Dada uma lista L, uma h-Lista de L uma sublista maximal
de L na qual cada elemento est a distncia h de seu sucessor. Por exemplo, para h = 3, a lista a seguir contm trs h-listas. A primeira h-lista
constituda dos elementos nas posies 0, 3 e 6 do vetor. A segunda h-lista
contm os elementos nas posies 1, 4 e 7. A terceira h-lista constituda
dos elementos nas posies 2 e 5.
0
10

1
4

2
5

3
3

4
10

5
2

6
1

7
12

Figura 2.4: Uma lista dividida em h-listas (h = 3)

No Shellsort, a lista subdividida em h-listas, as quais so ordenadas


com um mtodo de ordenao qualquer. Esse procedimento repetido para
valores decrescentes de h, sendo que o ltimo valor de h tem que ser 1. A
lista estar ento ordenada.
Observe que o Shellsort permite diversas implementaes diferentes.
Cabe ao programador decidir qual mtodo de ordenao ele usar para ordenar as h-listas. Uma boa opo utilizar o mtodo Insero.
Alm disso, o programador tambm ter decidir quais valores de h ele
utilizar. Donald Shell sugeriu usar potncias de 2 como valores de h. Por
exemplo, para ordenar uma lista de 100 elementos, seriam utilizados os
nmeros 64, 32, 16, 8, 4, 2 e 1 como valores de h.
Posteriormente, outro pesquisador, Donald Knuth, mostrou que o desempenho do Shellsort no bom se os valores que h assume ao longo da
execuo do mtodo so mltiplos uns dos outros. Ele ento sugeriu calcular os valores de h atravs da seguinte frmula de recorrncia: h = 3 * h + 1.
Como o ltimo valor de h tem que ser 1, usando essa frmula, o valor anterior de h seria 4. Antes de 4, o valor de h seria 13, e assim por diante.
Por exemplo, para ordenar uma lista de 100 elementos, seriam utilizados
os nmeros 40, 13, 4 e 1 como valores de h. Donald Knuth mostrou empiricamente que o desempenho do Shellsort rivaliza com o desempenho dos

26

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 26

22/04/13 14:53

melhores mtodos de ordenao ao ordenar listas de pequeno e mdio porte


quando usada a frmula sugerida por ele.
ALGORITMO SHELLSORT
ENTRADA: UM VETOR L COM N POSIES
SADA: O VETOR L EM ORDEM CRESCENTE
H = 1
ENQUANTO H < n FAA H = 3
FAA
H = H / 3 //
PARA i = H at n 1 //
PIVO = L[i]
j = i - H
ENQUANTO j 0 e L[j]
L[j + H] = L[j]
j= j - H
L[j + H] = PIVO
ENQUANTO H > 1
FIM {SHELLSORT}

* H + 1
diviso inteira
Insero adaptado para h-listas
> PIVO

Algoritmo 2.5: Shellsort

Note que os valores de h decrescem praticamente numa progresso


geomtrica de razo 1/3. Isso implica que a quantidade de iteraes do
lao mais externo pertence a (logn). No melhor caso, que ocorre quando
a lista fornecida j est ordenada, a condio do lao interno nunca verdadeira. Nesse caso, cada iterao do lao mais externo feita em tempo
linear e, portanto, a complexidade temporal do Algoritmo Shellsort pertence
a (nlogn). No se conhece a exata complexidade do Shellsort no pior caso.
Sabe-se, no entanto, que tal complexidade est entre (nlogn) e (n1,5).
O Shellsort mais um mtodo de ordenao in situ, pois sua complexidade espacial constante. Sobre a estabilidade, o exemplo da Figura 2.5
deixa claro que ao ordenar as h-listas o Shellsort pode inverter a ordem
existente entre os elementos repetidos, mesmo que seja usado um mtodo
de ordenao estvel (como o Insero) para ordenar as h-listas. Consequentemente, o Shellsort no-estvel.
0
1

1
4

2
2

3
3

4
10

5
5

6
10

Em 2001, Marcin Ciura mostrou que utilizar


a sequncia 1, 4, 10, 23,
57, 132, 301, 701 e 1750
como valores de h produz
resultados ainda melhores que utilizar a frmula proposta por Knuth.
A sequncia de Ciura a
melhor conhecida atualmente.

7
12

Figura 2.5: h-listas da Figura 2.4 em ordem crescente

7. Mergesort
Esse mtodo, proposto por John Von Neumann em 1945, baseado
numa estratgia de resoluo de problemas conhecida como diviso e conquista. Essa tcnica consiste, basicamente, em decompor a instncia a ser
resolvida em instncias menores do mesmo tipo de problema, resolver tais
instncias (em geral, recursivamente) e por fim utilizar as solues parciais
para obter uma soluo da instncia original.
Naturalmente, nem todo problema pode ser resolvido atravs de diviso e conquista. Para que seja vivel aplicar essa tcnica a um problema ele
deve possuir duas propriedades estruturais. O problema deve ser decompoPESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 27

27
22/04/13 14:53

nvel, ou seja, deve ser possvel decompor qualquer instncia no trivial do


problema em instncias menores do mesmo tipo de problema.
Vale salientar que a tcnica de diviso e conquista costuma apresentar desempenho melhor quando as instncias obtidas com a decomposio
tm aproximadamente o mesmo tamanho.
Uma instncia trivial uma instncia que no pode ser decomposta,
mas cuja soluo muito simples de ser calculada. Por exemplo, ordenar
uma lista constituda de apenas um elemento uma instncia trivial do
problema da ordenao.
Alm disso, deve ser sempre possvel utilizar as solues obtidas com
a resoluo das instncias menores para chegar a uma soluo da instncia original. Como veremos mais adiante, o problema da ordenao tem
essas duas propriedades estruturais e, portanto, pode ser resolvido por
diviso e conquista.
No Mergesort dividimos a lista em duas metades. Essas metades so
ordenadas recursivamente (usando o prprio Mergesort) e depois so intercaladas. Embora seja possvel descrever o Mergesort sem fazer uso de recursividade, a verso recursiva desse algoritmo elegante e sucinta, como
vemos no Algoritmo 2.6.
ALGORITMO MERGESORT
ENTRADA: UM VETOR L E AS POSIES INICIO E FIM
SADA: O VETOR L EM ORDEM CRESCENTE DA POSIO INICIO AT
A POSIO FIM
SE inicio < fim
meio = (inicio + fim)/2 // diviso inteira
SE inicio < meio
MERGESORT(L, inicio, meio)
SE meio + 1 < fim
MERGESORT(L, meio + 1, fim)
MERGE(L, inicio, meio, fim)
FIM {MERGESORT}
Algoritmo 2.6: Mergesort

Observe que a intercalao do intervalo a ser ordenado feita com o


Procedimento Merge descrito no Algoritmo 2.7. Tal procedimento a parte
principal do Mergesort e nele onde os elementos so movimentados para
as posies adequadas.
Nesse procedimento fazemos uso das variveis i e j para percorrer a
metade esquerda e a metade direita, respectivamente. Em cada iterao
comparamos o elemento na posio i com o elemento na posio j. O menor
deles copiado para um vetor auxiliar. Esse procedimento repetido at
que uma das duas metades tenha sido totalmente copiada para o vetor auxiliar. Se alguns elementos da metade esquerda no tiverem sido copiados
para o vetor auxiliar, eles devem ser copiados para o final do intervalo. Finalmente, copiamos os elementos do vetor auxiliar de volta para o intervalo.

28

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 28

22/04/13 14:53

PROCEDIMENTO MERGE
ENTRADA: UM VETOR L E AS POSIES INICIO, MEIO E FIM
(L TEM QUE ESTAR EM ORDEM CRESCENTE DA POSIO
INICIO AT MEIO E DA POSIO MEIO + 1 AT FIM)
SADA: O VETOR L EM ORDEM CRESCENTE DA POSIO INICIO AT
A POSIO FIM
i = inicio, j = meio + 1, k = 0
ENQUANTO i meio e j fim
SE L[i] L[j]
AUX[k] = L[i], i = i + 1
SENAO
AUX[k] = L[j], j = j + 1
k = k + 1
SE i meio
PARA j = meio at i(passo -1)
L[fim-meio+j] = L[j]
PARA i=0 ate k-1
L[i+inicio] = AUX[i]
FIM {MERGE}
Algoritmo 2.7: Procedimento Merge

Uma anlise cuidadosa desse procedimento nos leva a concluir que ele
requer tempo linearmente proporcional ao tamanho do intervalo. Vamos chamar de n o tamanho do intervalo, ou seja, n = fim inicio + 1. Observe que
a condio do primeiro lao somente verdadeira se i meio e j fim. Logo,
para que o lao continue e ser executado preciso termos i + j meio + fim.
Observe que inicialmente i + j = inicio + meio + 1. Como a cada iterao
do primeiro lao ou i ou j incrementado, aps n 1 iteraes teremos:
i
i
i
i

+
+
+
+

j
j
j
j

=
=
=
=

inicio + meio + 1 + n 1
inicio + meio + n
inicio + meio + fim inicio + 1
meio + fim + 1

Dessa forma, aps no mximo n 1 iteraes a condio do primeiro


lao ser violada. Claramente, o segundo lao, se executado, ter no mximo n/2 iteraes. Note que a cada iterao do primeiro lao a varivel k
incrementada. Dessa forma, a quantidade de iteraes do primeiro lao
ser k. Como k no mximo n 1 e o ltimo lao ter k iteraes, conclumos que o Procedimento Merge requer tempo linear. Observe ainda que o
Procedimento Merge faz uso do vetor AUX e, portanto, requer espao linear.
Alm disso, note que na comparao contida no primeiro lao, se L[i] e
L[j] forem iguais, copiado L[i] para o vetor auxiliar e isso remover preserva
a ordem relativa entre os elementos repetidos. Esse cuidado na implementao faz com que o Procedimento Merge faa sempre intercalaes estveis.
Como consequncia, o Mergesort tambm estvel.
A Figura 2.6 ilustra o funcionamento do Procedimento Merge. Observe
que o intervalo de L que vai da posio INICIO at MEIO e o intervalo que
vai de MEIO + 1 at FIM j esto em ordem crescente.

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 29

29
22/04/13 14:53

...

10

11

12

13

14

15

16

17

13

INICIO

AUX

...

MEIO

...

FIM

10

11

12

13

14

15

16

17

13

INICIO

...

FIM

Figura 2.6: Exemplo de intercalao

Esse mtodo descrito e


exemplificado no excelente
livro Algoritmos Teoria e
Prtica, de Cormen et al.

Como o Algoritmo Mergesort foi descrito de maneira recursiva, podemos facilmente fazer sua anlise utilizando frmulas de recorrncia. Para
isso, vamos denotar por T(n) o tempo requerido para ordenar um intervalo
de tamanho n. Sendo assim o tempo necessrio para ordenar um intervalo
de tamanho n/2 ser T(n/2). Como o Procedimento Merge requer tempo
linear, podemos supor que ele requer tempo cn (onde c uma constante
positiva). Temos ento a seguinte frmula de recorrncia para T:
T(n) = 2T(n/2) + cn
T(1) = c
Podemos resolver essa frmula facilmente utilizando o mtodo da iterao supondo n = 2k. A partir da recorrncia original, podemos obter as
seguintes recorrncias:
T(n) = 2T(n/2) + cn
2T(n/2) = 4T(n/4) + cn
4T(n/4) = 8T(n/8) + cn
...
2k-1T(n/2k-1) = 2k T(n/2k) + cn
2k T(n) = 2kc
Somando tais frmulas chegamos a T(n) = cnk + 2kc. Lembre-se de
que supomos n = 2k, logo, k = log 2n. Sendo assim, T(n) = cnlog 2n + cn.
Conclumos que a complexidade temporal do Algoritmo Mergesort pertence a (n log n).
Vamos agora denotar por E(n) o espao extra de memria requerido
para ordenar um intervalo de tamanho n. Como o Procedimento Merge requer espao linear e a memria utilizada numa chamada recursiva pode

30

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 30

22/04/13 14:53

ser reaproveitada na chamada recursiva seguinte, temos ento a seguinte


frmula de recorrncia para E:
E(n) = max(E(n/2), cn)
E(1) = c
Novamente podemos resolver essa frmula utilizando o mtodo da iterao, obtendo E(n) = cn. Conclumos que a complexidade espacial do Algoritmo Mergesort pertence a (n). Diferente de todos os mtodos que estudamos anteriormente, o Mergesort no in situ.

8. Quicksort
Esse mtodo, desenvolvido em 1960 por C. A. R. Hoare e publicado
em 1962, talvez o mais utilizado de todos os mtodos de ordenao. Isso
ocorre porque quase sempre o Quicksort significativamente mais rpido
do que todos os demais mtodos de ordenao baseados em comparao.
Alm disso, suas caractersticas fazem com que ele, assim como o Mergesort, possa ser facilmente paralelizado. Ele tambm pode ser adaptado para
realizar ordenao externa (Quicksort Externo).
Um aspecto que torna o Quicksort muito interessante sob o ponto de
visto terico o fato de que, embora em geral ele seja extremamente rpido,
existem casos (muito raros, verdade) em que seu desempenho bem ruim,
chegando a ser pior do que o de mtodos de ordenao considerados inferiores como os mtodos Bolha, Insero e Seleo.
Assim como o Mergesort, o Quicksort tambm baseado na estratgia
de diviso e conquista. Ocorre que, enquanto no Mergesort a fase de diviso
trivial e a fase de conquista trabalhosa, no Quicksort, com veremos a
seguir, acontece o contrrio, a fase de diviso trabalhosa e a fase de conquista trivial.
Nesse mtodo, a lista dividida em parte esquerda e parte direita, sendo que os elementos da parte esquerda so todos menores que os elementos
da parte direita, conforme mostrado na Figura 2.7. Essa fase do mtodo
chamada de partio.
Em seguida, as duas partes so ordenadas recursivamente (usando o
prprio Quicksort). A lista estar ento ordenada.
Uma estratgia para fazer a partio escolher um valor como piv e
ento colocar na parte esquerda os elementos menores ou iguais ao piv e
na parte direita os elementos maiores que o piv.
Embora existam diversas maneiras de escolher o piv, algumas das
quais sero apresentadas nessa seo, adotaremos a princpio uma estratgia extremamente simples, mas que costuma apresentar resultados prticos muito bons. Alm disso, tal estratgia facilita perceber os casos em
que o procedimento de partio no divide a lista de maneira equilibrada.
Dessa forma, torna-se mais fcil caracterizar e analisar o pior caso do Mtodo Quicksort.
Utilizaremos como piv o primeiro elemento da lista. Nesse caso, o
piv deve ser colocado entre as duas partes. O Procedimento Partio, que
implementa tal estratgia, descrito no Algoritmo 2.8.

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 31

31
22/04/13 14:53

...

PIV

INICIO

PIV
j

> PIV

FIM

...

Figura 2.7: Partio

PROCEDIMENTO PARTIO
ENTRADA: UM VETOR L E AS POSIES INICIO E FIM
SADA:j, tal que L[INICIO]..L[j-1] L[j] e
L[j+1]..L[FIM] > L[j]
// j a posio onde ser colocado o piv, como
// ilustrado na figura abaixo

PIVO = L[INICIO], i = INICIO + 1, j = FIM


ENQUANTO i j
ENQUANTO i je L[i] PIVO
i = i + 1
ENQUANTO L[j] > PIVO
j = j - 1
SE i j
TROCA(L[i],L[j])
i = i + 1, j = j - 1
TROCA(L[INICIO], L[j])
DEVOLVA j
FIM {PARTIO}
Algoritmo 2.8: Procedimento Partio

No Procedimento Partio a varivel i avana at encontrar um elemento maior do que o piv e a varivel j recua at encontrar um elemento
menor ou igual ao piv. feita ento a troca do elemento que est na posio i com o elemento que est na posio j. Esse processo repetido at
termos i > j. Para finalizar, o piv colocado entre as duas partes fazendo
troca(L[INICIO], L[j]). A posio j devolvida ao chamador do procedimento.
A regio crtica do Procedimento Partio constituda dos dois laos
mais internos, sendo n o tamanho do intervalo. Observe que inicialmente
j i = n 2. Note ainda que a cada iterao de um dos laos internos ou i
incrementado ou j decrementado. Isso significa que a cada iterao de um
desses laos a expresso j i decrementada de uma unidade. Consequentemente, aps no mximo n 1 iteraes desses laos teremos j i = -1 o que
implica que j ser menor do que i. O lao ser ento finalizado. Conclumos
que o Procedimento Partio requer tempo linear. Claramente, esse procedimento tem complexidade espacial constante.
Na Figura 2.8 ilustrada a partio de uma lista. Observe que nesse
exemplo que a partio ficou equilibrada, pois quatro elementos ficaram
esquerda do piv e trs elementos ficaram direita do piv.

...

10

11

12

13

14

15

16

17

INICIO

...

FIM
1 troca
2 troca
3 troca

32

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 32

22/04/13 14:53

...

10

11

12

13

14

15

16

17

...

Figura 2.8: Exemplo de partio equilibrada

Nesse exemplo, percebemos que o Procedimento Partio pode inverter a ordem existente entre os elementos repetidos. Consequentemente, o
Quicksort no-estvel.
Se o elemento escolhido como piv for o maior elemento do intervalo,
teremos uma partio desequilibrada, como ilustrado na Figura 2.9. Note
que apenas uma troca ser executada.

...

10

11

12

13

14

15

16

17

INICIO

...

...

FIM

10

11

12

13

14

15

16

17

...

Figura 2.9: Exemplo de partio desequilibrada

fcil perceber que se o menor elemento do intervalo for escolhido


como piv nenhuma troca ser efetuada. Teremos outra partio desequilibrada. Em ambos os casos uma das metades produzidas com a partio
ficar vazia e a outra ter todos os elementos do intervalo exceto o piv.
Esse fato ter um impacto importante sobre o desempenho do Quicksort
como veremos mais adiante.
Descrevemos a seguir uma verso recursiva do Quicksort.
ALGORITMO QUICKSORT
ENTRADA: UM VETOR L E AS POSIES INICIO E FIM
SADA: O VETOR L EM ORDEM CRESCENTE DA POSIO INICIO AT
A POSIO FIM
SE INICIO < FIM
j = PARTICAO(L, INICIO, FIM)
SE INICIO < j - 1
QUICKSORT(L, INICIO, j - 1)
SE j + 1 < FIM
QUICKSORT(L, j + 1, FIM)
FIM {QUICKSORT}
Algoritmo 2.9: Quicksort

Para analisar o Algoritmo Quicksort vamos denotar por T(n) o tempo


requerido para ordenar um intervalo de tamanho n e por E(n) o espao extra requerido para ordenar um intervalo de tamanho n. No pior caso, que
ocorre quando todas as escolhas do piv recaem sempre sobre um elemento extremo (o maior ou o menor) do intervalo, a complexidade temporal do
Quicksort dada por:
PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 33

33
22/04/13 14:53

T(n) = T(n 1) + cn
T(1) = c
Essa frmula pode ser facilmente resolvida resultando em T(n) = (n2 - n)/2.
A complexidade espacial do Quicksort no pior caso dada por:
E(n) = E(n 1) + c
E(1) = c

No livro Algoritmos Teoria e Prtica descrito um


mtodo para calcular a
mediana em tempo linear.

Resolvendo essa frmula obtemos E(n) = cn. Conclumos que no pior


caso o Algoritmo Quicksort requer tempo (n2) e espao (n). Para nossa
surpresa, essa complexidade temporal to ruim quanto as dos mtodos
Bolha, Insero e Seleo e essa complexidade espacial to ruim quanto
a do Mergesort. Some-se a isso o fato de que o Quicksort no-estvel e
ento conclumos que no pior caso o Quicksort um dos piores mtodos de
ordenao.
fcil perceber que com o critrio de escolha do piv que adotamos,
se a lista estiver inversamente ordenada, todos os pivs escolhidos sero
elementos extremos de seus intervalos e, portanto, recairemos no pior caso
do Quicksort. Para nossa surpresa, se a lista j estiver ordenada, todos os
pivs escolhidos tambm sero elementos extremos de seus intervalos e novamente recairemos no pior caso do Quicksort. Felizmente, a ocorrncia do
pior caso extremamente rara.
No melhor caso, que ocorre quando as escolhas do piv recaem sempre sobre a mediana do intervalo, a complexidade temporal do Quicksort
dada por:
T(n) = 2T(n/2) + cn
T(1) = c
Resolvemos essa frmula ao discutir o Mergesort e sabemos que T(n)
(nlogn). A complexidade espacial do Quicksort dada por:
E(n) = E(n/2) + c
E(1) = c
Resolvendo essa frmula conclumos que E(n) (logn). Sendo assim,
no melhor caso a complexidade temporal do Quicksort pertence a (nlogn)
e a complexidade espacial pertence a (logn). Essas tambm so as complexidades do Quicksort no caso mdio.
Podemos utilizar estratgias mais elaboradas para escolha do piv,
com o objetivo de produzir parties mais equilibradas. Eis algumas ideias:
Utilizar a mdia aritmtica do intervalo.
Utilizar a mediana do intervalo.
Escolher aleatoriamente um elemento do intervalo.
Nos dois primeiros casos precisaremos de tempo linear para escolher o
piv, mas isso no afetar a complexidade temporal assinttica da partio

34

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 34

22/04/13 14:53

que linear. No entanto, em termos absolutos, o tempo requerido pela partio aumentar. Alm disso, o piv poder no ser um elemento do intervalo e
isso exigir algumas alteraes adicionais do Procedimento Partio.
No ltimo caso temos a verso conhecida como Quicksort probabilstico. A principal vantagem dessa verso o fato de tornar impossvel garantir que o Quicksort vai requerer tempo quadrtico para uma determinada
lista. Como vimos anteriormente, ao escolher deterministicamente o piv,
possvel que algum disposto a degradar a performance Quicksort construa
listas para as quais seu desempenho seja quadrtico. Isso no mais possvel na verso probabilstica do algoritmo.

9. Heaps Binrios
Um heap uma coleo de dados parcialmente ordenados. Num heap
crescente vlida a seguinte propriedade: o pai menor ou igual aos seus
filhos. Num heap decrescente, temos a propriedade anloga: o pai maior
ou igual aos seus filhos. Existem diversos tipos de heaps: binrios, binomiais, de Fibonacci etc. Abordaremos apenas heaps binrios.
Um heap binrio se caracteriza pelo fato de que cada elemento possui
no mximo dois filhos. Podemos implementar heaps binrios usando uma
rvore binria, conforme mostra a Figura 2.10. Tal rvore ter todos os
nveis completos, com exceo do ltimo nvel, que pode estar incompleto.
Alm disso, os nveis so preenchidos da esquerda para a direita.
3

10

Figura 2.10: Exemplo de heap binrio crescente armazenado numa rvore

Um heap binrio tambm pode ser implementado atravs de um vetor.


Nesse caso, os filhos da posio i so as posies 2 * i e 2 * i + 1 (A posio
zero do vetor no utilizada). Discutiremos em detalhes como fazer insero e como remover o menor elemento de um heap binrio crescente implementado num vetor. A Figura 2.11 mostra a implementao de um heap
binrio em um vetor.
1
3

2
5

3
3

4
7

5
10

Figura 2.11: Exemplo de heap binrio crescente armazenado num vetor

Observe que num heap binrio crescente implementado numa rvore,


o menor valor estar sempre na raiz da rvore. Se o heap binrio crescente for implementado num vetor, o menor valor estar sempre na primeira
posio do vetor. Dessa forma, encontrar o menor valor contido num heap
binrio crescente uma operao que pode ser feita em tempo constante.
Analogamente, o maior elemento num heap binrio decrescente estar sempre no seu incio.
Para implementar um heap binrio usando um vetor, podemos usar
uma estrutura com os seguintes campos:

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 35

35
22/04/13 14:53

vetor: armazena os dados


tamanho: indica o tamanho do vetor
ultima: indica a ltima posio usada do vetor

x (l-se cho de x) o
maior inteiro que menor
ou igual a x.

Para inserir um valor x num heap binrio devemos inseri-lo aps o


ltimo elemento e depois comparar com seu pai, trocando-os de posio se
houver necessidade. Tal processo repetido at que x seja maior ou igual ao
seu pai ou at x atingir a posio 1 do vetor. O Algoritmo 2.10 implementa a
ideia descrita nesse pargrafo.
ALGORITMO INSERE_HBC
ENTRADA: UM HEAP BINRIO CRESCENTE H E UM VALOR X
SADA: SE HOUVER ESPAO DISPONIVEL, INSERE X EM H;
CASO CONTRRIO, DEVOLVE UM ERRO.
SE H.ultima = H.tamanho
devolva ERRO
H.ultima = H.ultima + 1
i = H.ultima
ENQUANTO i > 1 e H.vetor[i/2] > x
H.vetor[i] = H.vetor[i/2]
i = i/2
H.vetor[i] = x
FIM {INSERE_HBC}

//HEAP OVERFLOW

// DIVISO INTEIRA

Algoritmo 2.10: Insere_HBC

Claramente, a regio crtica do Algoritmo Insere_HBC o lao. Dessa


forma, o tempo requerido pelo algoritmo determinado pela quantidade de
iteraes do lao. Seja n = H.ultima. Note que inicialmente i = n e, portanto,
i possui log2n + 1 bits significativos. A cada iterao do lao, a varivel i
perde um bit significativo, pois o valor de i atualizado fazendo-se i = i/2.
Aps log2n iteraes, i ter apenas um bit significativo. Sendo assim, teremos i 1 e o lao ser finalizado. Assim, a quantidade mxima de iteraes
do lao log2n. Conclumos que a complexidade temporal do Algoritmo Insere_HBC pertence a O(logn).
A Figura 2.12 ilustra a insero do valor 4 num heap binrio crescente. Observe que o valor 7 e depois o valor 5 precisam ser movidos para que o
valor 4 possa ser colocado na posio 2 do vetor. Note ainda que a insero
pode inverter a ordem entre os elementos repetidos.
1

3
1

5
2

3
3

10

Heap antes da insero


4

10

7
8

10

10

novo valor
2 movimentao

1 movimentao

Figura 2.12: Exemplo de insero num heap binrio crescente

Embora seja possvel remover um elemento qualquer do heap, vamos


discutir apenas a remoo do menor elemento. Como vimos anteriormente,
o menor elemento estar sempre na primeira posio do heap.

36

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 36

22/04/13 14:53

Para remover o menor elemento de um heap binrio crescente implementado num vetor, movemos o ltimo valor contido no heap (piv) para a
posio 1 do vetor. Em seguida, comparamos o piv com seus filhos, trocando-o com o menor de seus filhos se houver necessidade. Esse procedimento
repetido at que o piv seja menor ou igual aos seus filhos ou at o piv
atingir uma posio que no tenha filhos.
ALGORITMO REMOVE_MENOR
ENTRADA: UM HEAP BINRIO CRESCENTE H
SADA: SE H NO ESTIVER VAZIO, REMOVE E DEVOLVE O MENOR
ELEMENTO DE H; CASO CONTRRIO; DEVOLVE UM ERRO
SE H.ultima = 0 //HEAP UNDERFLOW
devolva ERRO e PARE
valor= H.vetor[1]
H.vetor[1] = H.vetor[H.ultima]
H.ultima = H.ultima - 1
i = 1
ENQUANTO (2*i H.ultima e H.vetor[i] > H.vetor[2*i]) ou
(2*i < H.ultima e H.vetor[i] > H.vetor[2*i+1])
menor = 2*i
SE 2*i < H.ultima e H.vetor[2*i+1] H.vetor[2*i]
menor= menor+1
TROCA(H.vetor[i], H.vetor[menor])
i = menor
DEVOLVA valor
FIM {REMOVE_MENOR}

Algoritmo 2.11: Remove_Menor

A Figura 2.13 mostra a remoo do menor elemento de um heap binrio crescente. Observe que aps mover o valor 10 para a primeira posio
do vetor, precisamos troc-lo com o valor 3 e depois com o valor 6 para
restaurar a ordenao parcial do heap. Note ainda que a remoo do menor
elemento pode inverter a ordem entre elementos repetidos.
1

2
1

4
2

4
1 troca

3
3

Heap antes da remoo


4

6
2 troca

10

10

10

10

1 movimentao

Figura 2.13: Remoo do menor elemento num heap binrio crescente

Seja n = h.ultima. Observe que h.ultima / 2 possui log2n bits significativos. Inicialmente, a varivel i possui apenas um bit significativo. A cada
iterao do lao, i ganha um bit significativo. Aps log2n iteraes, i ter
log2n + 1 bits significativos e, portanto, teremos i > h.ultima/2. Consequentemente, o lao ser finalizado. Conclumos que o Algoritmo Remove_Menor
requer tempo O(log n).

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 37

37
22/04/13 14:53

10. Heapsort
Podemos usar heaps binrios para ordenar com bastante eficincia
e elegncia. O Mtodo Heapsort baseado no uso de heap binrio. Inicialmente, inserimos os elementos da lista num heap binrio crescente. Em seguida, fazemos sucessivas remoes do menor elemento do heap, colocando
os elementos removidos do heap de volta na lista. A lista estar ento em
ordem crescente.
ALGORITMO HEAP SORT
ENTRADA: UM VETOR L COM N POSIES
SADA: O VETOR L EM ORDEM CRESCENTE
inicialize um HBC H com n posies
PARA i = 0 at n - 1
INSERE_HBC(H, L[i])
PARA i = 0 at n - 1
L[i] = REMOVE_MENOR(H)
FIM {HEAP SORT}
Algoritmo 2.12: Heapsort

O leitor interessado poder encontrar uma prova


desse fato no livro Algoritmos Teoria e Prtica.
(Comen et al., 2002).

Na seo anterior mostramos que a insero e a remoo do menor


elemento requer tempo logartmico no tamanho do heap. Sendo assim, a
complexidade temporal do Heapsort pertence a (n log n).
Como vimos anteriormente, a insero e a remoo do menor elemento
do heap no preservam a ordem relativa existente entre os elementos repetidos. Como consequncia desse fato, o Heapsort no-estvel.
Finalmente, a complexidade espacial do Algoritmo Heapsort (n). No
entanto, podemos facilmente adaptar o Heapsort para fazer ordenao in
situ. Para isso, devemos usar o prprio espao do vetor como heap. Nesse
caso sua complexidade espacial do Heapsort ser O(1).
O sete mtodos que descrevemos neste captulo at agora utilizam
como operao fundamental a comparao de elementos da lista. possvel
mostrar que todo mtodo de ordenao baseado na operao de comparao
requer tempo (n log n). No entanto existem mtodos de ordenao que, sob
certas condies, ordenam em tempo linear. Naturalmente, tais mtodos no
so baseados em comparao. Discutiremos a seguir trs desses mtodos.

11. Countingsort

denota complexidade no
melhor caso.

38

Esse mtodo foi proposto por Harold H. Seward em 1954 e faz a ordenao usando a ideia de contagem. Uma restrio desse mtodo que ele
somente ordena listas de nmeros naturais.
Essa no uma restrio muito severa, pois podemos converter diversos tipos de listas em listas de nmeros naturais. Por exemplo, uma
lista de nmeros inteiros onde o menor valor -x pode ser convertida numa
lista de nmeros naturais somando x a cada elemento da lista. Uma lista
de nmeros racionais pode ser convertida numa lista de nmeros inteiros
multiplicando-se os elementos da lista por uma constante apropriada.
De fato, sempre que existir uma bijeo entre o tipo dos dados da lista
e um subconjunto dos naturais possvel converter a lista em uma lista de
nmeros naturais. Infelizmente, algumas dessas converses podem ter um
impacto negativo sobre o desempenho do mtodo.

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 38

22/04/13 14:53

Seja n o tamanho da lista e k o maior valor contido na lista. Fazemos


uso de um vetor C com k + 1 posies. No primeiro lao do procedimento
Countingsort, descrito no Algoritmo 2.13, o vetor C inicializado com zeros.
No lao seguinte, contamos quantas vezes cada um dos elementos de
0 a k aparece na lista. Para fazer isso, percorremos a lista e para cada valor
i contido na lista incrementamos de uma unidade a posio i do vetor C.
Dessa forma, ao final desse lao cada posio i de C indica quantas vezes o
valor de i ocorre na lista.
Em seguida, fazemos a soma acumulada do vetor C. Percorremos novamente o vetor C, dessa vez a partir da segunda posio, somando cada
posio i do vetor c com a posio anterior. O resultado da soma guardado na prpria posio i. Aps realizar a soma acumulada, cada posio i
do vetor C indicar quantos elementos da lista so menores ou iguais a i.
Obviamente, se i ocorre na lista e C[i] = j, quando a lista estiver ordenada o
valor i dever ocupar a j-sima posio da lista.
Percorremos mais uma vez a lista, dessa vez, da direita para a esquerda (para garantir que a ordenao seja estvel) e colocamos cada valor
i contido na lista na posio c[i] 1 de um vetor auxiliar. Para evitar que
mltiplas cpias de um valor contido na lista sejam colocadas numa mesma
posio do vetor auxiliar, aps colocar um valor i no vetor auxiliar, decrementamos de uma unidade a posio i de C. No ltimo lao, copiamos o
vetor auxiliar para a lista.
ALGORITMO COUNTING SORT
ENTRADA: UM VETOR L CONTENDO N NMEROS NATURAIS NO
INTERVALO DE 0 A K
SADA: O VETOR L EM ORDEM CRESCENTE
PARA i = 0 at k //
c[i]=0
PARA i = 0 at n - 1 //
c[L[i]]= c[L[i]] +1
PARA i = 1 at k //
c[i]= c[i] + c[i-1]
PARA i= n - 1 at 0 (passo -1) //
c[L[i]] = c[L[i]] - 1
aux[c[L[i]]]= L[i]
PARA i = 0 at n - 1
//
L[i]= aux[i]

INICIALIZACAO DE C
CONTAGEM
SOMA ACUMULADA
ORDENACAO
COPIANDO AUX PARA L

FIM {COUNTING SORT}

Algoritmo 2.13: Countingsort

O Algoritmo Countingsort constitudo de cinco laos independentes.


Trs desses laos gastam tempo (n) e os outros dois gastam tempo (k).
Alm disso, vetor C tem k + 1 posies e o vetor aux tem n posies. Conclumos que a complexidade temporal e a complexidade espacial do Countingsort pertencem a (n + k). Para a classe de listas onde k no muito
maior do que n, mais precisamente, se k (n), ento tais complexidades
pertencem a (n). O cuidado que tivemos ao percorrer a lista do final para
o incio no quarto lao garante a estabilidade de Countingsort .
Na Figura 2.14 exibimos o contedo do vetor C ao final de cada lao do
Algoritmo Countingsort. O contedo do vetor aux corresponde lista original em ordem crescente.

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 39

39
22/04/13 14:53

Lista original
Vetor C
1 lao
2 lao
3 lao
4 lao
5 lao
Vetor aux

0
8

1
4

2
5

3
3

4
8

5
2

0
0
0
0
0
0
0
0
0
0

1
0
1
0
1
0
1
0
1
0

2
0
2
1
2
1
2
0
2
0

3
0
3
1
3
2
3
1
3
1

4
0
4
1
4
3
4
2
4
2

5
0
5
1
5
4
5
3
5
3

0
2

1
3

2
4

3
5

4
8

5
8

6
0
6
0
6
4
6
4
6
4

7
0
7
0
7
4
7
4
7
4

8
0
8
2
8
6
8
4
8
4

Figura 2.14: Ordenao com o Algoritmo Countingsort

12. Bucketsort
Embora esse mtodo permita ordenar listas de nmeros quaisquer,
descreveremos uma verso desse mtodo que ordena listas de nmeros no
negativos.
Se a lista a ser ordenada tem n elementos, ser usado um vetor de
ponteiros (bucket) com n posies. Se o maior elemento da lista k, cada
posio do bucket apontar para uma lista encadeada na qual sero inseridos os elementos da lista que pertencem ao intervalo [ i * (k + 1) / n , (i + 1)
* (k + 1) / n). Observe que o intervalo fechado esquerda e aberto direita.
A ideia do mtodo dividir o intervalo que vai de 0 at k em n subintervalos de mesmo tamanho. Cada subintervalo estar associado a uma
lista ligada que ir conter os elementos da lista que pertencem quele subintervalo. Por exemplo, se a lista tem oito elementos o maior deles 71,
teremos oito intervalos: [0, 9), [9, 18), ..., [63, 72). A posio zero do bucket
apontar para uma lista encadeada que ir conter os elementos da lista que
so maiores ou iguais a zero e menores que 9, e assim por diante.
Chamaremos o bucket de vetor B. Para construir as listas encadeadas
devemos inserir cada valor j contido na lista a ser ordenada na lista encadeada apontada por B[ j * n / (k + 1)]. Em seguida, ordenamos as listas encadeadas com um mtodo de ordenao qualquer (de preferncia estvel). Aps
isso, a concatenao das listas encadeadas produz a lista original ordenada.
ALGORITMO BUCKET SORT
ENTRADA: UM VETOR L CONTENDO N NMEROS NO INTERVALO DE
0 AT K
SADA: O VETOR L EM ORDEM CRESCENTE
PARA i = 0 at n - 1 //INICIALIZACAO
B[i] = NULO
//CONSTRUINDO AS LISTAS ENCADEADAS
PARA i = n - 1 at 0 (PASSO -1)
insira L[i] no inicio da lista ligada apontada por
B[L[i] * n / (K + 1)]
// DIVISO INTEIRA
//ORDENANDO E CONCATENANDO AS LISTAS ENCADEADAS
j = 0
PARA i = 0 at n - 1

40

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 40

22/04/13 14:53

coloque a lista apontada por B[i] em ordem crescente


p = B[i]
ENQUANTOp NULO
L[j] = p.info
p = p.proximo
j = j + 1
remova a lista apontada por B[i]
FIM {BUCKET SORT}
Algoritmo 2.14: Bucketsort

Claramente os primeiros dois laos podem ser executados em tempo


(n). Note que o tamanho mdio de cada lista encadeada ser 1. De fato, se
os elementos de L estiverem uniformemente distribudos no intervalo [0, k),
possvel mostrar que o tamanho esperado de cada lista encadeada ser
constante. Nesse caso, independente do mtodo utilizado, a ordenao de
cada lista encadeada ser feita em tempo esperado constante.
A cpia dos elementos de uma lista encadeada requer tempo amortizado constante. A remoo de uma lista encadeada tambm feita em tempo
amortizado constante. Consequentemente, o terceiro lao ir requerer tempo esperado constante, e a complexidade temporal esperada do Algoritmo
Bucketsort ser (n).
Note que no segundo lao percorremos a lista da direita para a esquerda. Com isso, ao construir as listas encadeadas preservamos a ordem relativa
existente entre os elementos repetidos. Se o mtodo utilizado para ordenar as
listas encadeadas for estvel, o Algoritmo Bucketsort tambm ser estvel.
O bucket ter n posies. A quantidade de ns nas listas encadeadas
ser n. Conclumos que a complexidade espacial do Bucketsort pertence a
(n). Finalmente, observe que Bucketsort no ir requerer comparaes se
o mtodo usado como subrotina no for baseado em comparaes.
A Figura 2.15 a seguir exemplifica as listas encadeadas construdas
pelo Bucketsort aps sua ordenao. Claramente, a concatenao das listas
encadeadas produz a lista original em ordem.
0

53 12

12

12

12

28

40

53

71

Lista original

28

71 40

2
Bucket

6
7

Figura 2.15: Ordenao com o Algoritmo Bucketsort

13. Radixsort
Esse mtodo permite ordenar listas cujos elementos sejam comparveis dois
a dois. Uma verso desse mtodo foi utilizada em 1887 por Herman Hollerith,
fundador da Tabulating Machine Company que mais tarde deu origem IBM.
PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 41

41
22/04/13 14:53

Em cada iterao do Radixsort, ordenamos a lista por uma de suas


posies, comeando pela posio menos significante, at chegar posio
mais significante (os elementos da lista devem que ser representados com a
mesma quantidade de posies). Cada ordenao tem que ser feita com um
mtodo estvel.
ALGORITMO RADIX SORT
ENTRADA: UM VETOR L COM N POSIES CUJOS ELEMENTOS
POSSUEM D SMBOLOS
SADA: O VETOR L EM ORDEM CRESCENTE
PARA i = 1 at d
Coloque L em ordem crescente pelo i-simo smbolo menos
significante usando um mtodode ordenao estvel
FIM {RADIX SORT}

Algoritmo 2.15: Radixsort

Podemos adaptar o Countingsort e utiliz-lo como subrotina no Radixsort. Observe que os elementos da lista so constitudos de smbolos de
algum alfabeto. Por exemplo, se a lista contm nmeros decimais, o alfabeto
formado pelos dgitos do sistema numrico decimal. Note que o maior smbolo encontrado numa posio de um elemento no excede o maior smbolo
do alfabeto. Como o tamanho do alfabeto constante, podemos garantir que
a complexidade temporal e a complexidade espacial dessa verso do Countingsort pertencem a (n).
Outra possibilidade seria adaptar o Bucketsort e utiliz-lo como subrotina. Para isso, o bucket dever ter uma posio para cada elemento do
alfabeto. No haver necessidade de ordenar as listas encadeadas visto que
cada uma delas contm apenas elementos com o mesmo smbolo na posio
que est sendo ordenada. Podemos ento garantir que a complexidade temporal dessa verso do Bucketsort ser (n).
Note que tanto o Countingsort quanto o Bucketsort so estveis. Utilizando qualquer um deles como subrotina, o Radixsort ter complexidade
temporal (dn) e complexidade espacial (n). Se d for constante a complexidade temporal ser (n). Note que o Radixsort necessariamente estvel,
qualquer que seja o mtodo usado como subrotina.
32

500

500

500

431

32

431

32

431

32

248
9

32

32

48

Ordenando
pela
unidade

63

Ordenando
pela
dezena

32

ordenando
pela
centena

63

32

248

248

248

63

48

48

431

48

63

500

Figura 2.16: Ordenao com o Algoritmo Radixsort

42

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 42

22/04/13 14:53

1. Complete a tabela abaixo.


Mtodo
Bolha

Complexidade temporal
Melhor caso

Pior caso

Caso mdio

(n2)

(n2)

(n2)

Complexidade
estvel?
espacial
O(1)

Sim

Bolha com flag


Insero
Seleo
Shellsort
Mergesort
Quicksort
Heapsort

2. Caracterize o pior e o melhor caso, em termos assintticos, de cada um


dos mtodos que aparecem na tabela acima.
3. Mostre como ficaria a lista (18, 23, 37, 22, 25, 16, 3, 31, 5, 28, 6, 34, 9,
45) aps cada iterao do lao mais externo dos algoritmos bolha, insero, seleo, shellsort e radixsort, descritos neste captulo.
4. Mostre como ficaria a lista (18, 23, 37, 22, 25, 16, 3, 31, 5, 28, 6, 34, 9,
45) aps ser particionada pelo Procedimento Partio apresentado neste
captulo.
5. Dentre os mtodos bolha, bolha com flag, insero, seleo, shellsort,
mergesort e quicksort, quais seriam os mais eficientes, em termos de
tempo, para colocar listas da forma (n, 1, 2, 3, ..., n 1) em ordem crescente? Justifique sua resposta.
6. Escreva um algoritmo que implemente o mtodo bolha para ordenar
listas encadeadas contendo nmeros. Considere que cada n da lista
possui os campos info, anterior e proximo.
7. Indique quais tipos de listas podem ser ordenadas pelos mtodos Countingsort, Bucketsort e Radixsort e que condies precisam ser satisfeitas
para que eles tenham complexidade de tempo linear no tamanho da
lista.
8. Voc deseja ordenar em tempo linear listas de n elementos contendo
nmeros inteiros entre 1 e 10n. Qual mtodo voc utilizaria ? Justifique
sua resposta.
9. Mostre como ficaria o vetor C no final de cada um dos cinco laos do
Algoritmo Countingsort ao ordenar a lista (18, 23, 17, 22, 25, 16, 3, 11,
5, 8, 6, 4, 9, 15).

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 43

43
22/04/13 14:53

10. Mostre como ficariam as listas encadeadas geradas no mtodo bucket


sort ao ordenar a lista (18, 23, 17, 22, 25, 16, 3, 41, 5, 8, 6, 34, 9, 15).
11. Aps cada iterao do lao mais externo de um algoritmo de ordenao,
a lista (382, 142, 474, 267) ficou como mostrado abaixo. Qual foi o algoritmo utilizado (bolha, insero, seleo ou radixsort)? Justifique por
que nenhum dos outros algoritmos estudados neste captulo poderia ter
produzido as listas abaixo.
(142, 382, 474, 267)
(142, 267, 474, 382)
(142, 267, 382, 474)
12. Escreva um procedimento que receba um heap binrio crescente (passado por referncia) e uma posio i e ento remova o elemento que estiver na posio i do heap.
13. Escreva um procedimento que transforme um vetor num heap binrio
crescente em tempo linear.
14. Mostre como ficaria um heap binrio crescente no qual foram inseridos
os valores 18, 23, 17, 22, 25, 16, 3, 41, 5, 8, 6, 34, 9, 15, nesta ordem (seu
heap deve ser implementado num vetor de 15 posies). Em seguida, remova o elemento que estiver na posio 3, depois o elemento que estiver
na posio 2 e por fim o elemento que estiver na posio 1 e ento mostre
como ficaria o heap.

44

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 44

22/04/13 14:53

Captulo

Ordenao Externa

Objetivos:




Identificar os mecanismos de ordenao externa


Apresentar os processos de intercalao de arquivos
Comparar a eficincia entre as diversas distribuies equilibradas
Definir intercalao de um ou mais caminhos
Definir intercalao polifsica

Pesq_Ord_de_Dados 45

22/04/13 14:53

Pesq_Ord_de_Dados 46

22/04/13 14:53

Apresentao
No incio deste captulo indicamos que quando os arquivos a serem
classificados no podem ser armazenados integralmente na memria principal, impossvel realizar uma ordenao interna atravs de um dos mtodos definidos no captulo anterior. Mostramos tambm que, para resolver este problema, o arquivo original deve ser dividido em partes menores,
de tamanho tal que a classificao interna seja suportada e que a seguir
estas partes, ordenadas, devem ser intercaladas. Apresentamos ento as
formas eficientes de se processar uma intercalao destacando que os mtodos abordados objetivam minimizar o nmero de leitura e gravao dos
registros de cada parte armazenada em disco magntico, chamada rea de
trabalho. So, por fim, indicados os principais fatores que influem na eficincia de um algoritmo de classificao de forma geral, ou seja, usando a
ordenao interna e se necessrio a externa.

1. Definio e mecanismos
Quando os arquivos a serem classificados contm muitos registros,
de modo que no podem ser contidos integralmente na memria principal,
impossvel realizar uma ordenao interna atravs de um dos mtodos
definidos no captulo anterior.
Para resolver este problema, o arquivo original deve ser dividido em
partes menores de tamanho tal que a classificao interna seja suportada.
Uma vez que as partes ou sries j estejam ordenadas elas so intercaladas
sucessivamente at que todas estejam presentes num arquivo final ordenado.
Neste captulo apresentaremos as formas eficientes de se processar
uma intercalao. Os mtodos abordados objetivam minimizar o nmero de
leitura e gravao dos registros de cada parte armazenada em disco magntico, chamada rea de trabalho. Os registros esto organizados nesta rea
de forma sequencial.
Os fatores que influem na eficincia de um algoritmo de classificao
geral so os seguintes:
Nmero de registros e tamanho de cada um deles;
Uso ou no da memria auxiliar (necessita ou no da ordenao
externa);
Tipos e meios de armazenamento utilizados;
Grau de classificao j existente e
Periodicidade de atualizao do arquivo.

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 47

47
22/04/13 14:53

A eficincia de uma classificao externa medida em termos da


quantidade total do tempo necessrio para que os dados sejam lidos, ordenados e gravados na rea de trabalho; isto corresponde fase inicial do
processo de ordenao.
Na fase seguinte as sries ordenadas so lidas e intercaladas duas
a duas, trs a trs, etc. O nmero de sries intercaladas em cada passo
corresponde ao nmero de caminhos. Quanto maior for o nmero de caminhos, mais complexo ser o algoritmo de intercalao (merge). Como este
processo utilizado vrias vezes para conseguir juntar todas as sries, em
geral opta-se por trabalhar com 2 ou 3 caminhos.
Os fatores que influem na eficincia de um algoritmo de classificao
externa so os seguintes:
Nmero de sries produzidas;
Tamanho de cada srie e se so do mesmo tamanho;
Forma de distribuio das sries pelos arquivos de trabalho e
Caractersticas dos blocos e das memrias intermedirias utilizadas na fase de classificao
A estimativa do nmero de sries utilizadas, bem como seu comprimento, funo do nmero de registros do arquivo; isto determina o nmero de passadas durante a fase de classificao. importante que esteja
bem definida a sequncia na qual as sries devem ser distribudas pelos
arquivos de entrada para a fase de intercalao.
Os tipos bsicos de algoritmos para distribuir as sries so equilibradas, onde so colocadas um nmero igual de sries iniciais em cada arquivo e desequilibradas em que as sries so dispostas nos arquivos de modo
a conseguir um melhor nvel de intercalao.
Nas sees seguintes so apresentados os algoritmos de intercalao
de dois caminhos (Merge2) e de trs caminhos (Merge3).

2. Intercalao de dois caminhos


Para exemplificar como se processa uma intercalao, vamos supor
dois arquivos contendo somente os valores das chaves de cada registro.
Considerando R i como um registro com chave K i e que o primeiro arquivo (Arq1) possui 4 registros (R1 a R4) com as respectivas chaves K1 a K4
iguais a {3, 7, 9, 11} e o segundo arquivo (Arq2) possui 6 registros (R5 a R10)
com chaves K5 a K10 iguais a {1, 5, 8, 9, 12, 13}. Em cada passo a seleo
feita pelo teste das chaves K i < Kj apontadas pelas setas. Arq3 o arquivo
de sada.

Arq1

R1
3

R2
7

Arq3

S1
1

S2

i=1

k=2

R3
9
S3

S4

Arq2

R4
11

R5
1

j=5

S5

S6

S7

R6
5
S8

R7
8
S9

R8
9

R9
12

R10
13

S10

Figura 3.1: Exemplo da intercalao de dois caminhos (Passo-1 do Merge2)

48

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 48

22/04/13 14:53

Arq1

R1
3

R2
7

Arq3

S1
1

S2
3

i=1

k=3

R3
9

S3

Arq2

R4
11
S4

j=6

S5

S6

R5
1
S7

R6
5
S8

R7
8
S9

R8
9

R9
12

R10
13

S10

Figura 3.2: Exemplo da intercalao de dois caminhos (Passo-2 do Merge2)

Arq1

R1
3

R2
7

Arq3

S1
1

S2
3

i=2

k=4

R3
9
S3
5

Arq2

R4
11

S4

j=6

S5

S6

R5
1
S7

R6
5
S8

R7
8
S9

R8
9

R9
12

R10
13

S10

Figura 3.3: Exemplo da intercalao de dois caminhos (Passo-3 do Merge2)

Arq1

R1
3

R2
7

Arq3

S1
1

S2
3

i=2

k=5

R3
9
S3
5

R4
11
S4
7

Arq2

S5

R5
1

j=7

S6

S7

R6
5
S8

R7
8
S9

R8
9

R9
12

R10
13

S10

Figura 3.4: Exemplo da intercalao de dois caminhos (Passo-4 do Merge2)

Arq1

R1
3

R2
7

Arq3

S1
1

S2
3

i=3

k=6

R3
9
S3
5

Arq2

R4
11
S4
7

S5
8

R5
1

j=7

S6

S7

R6
5
S8

R7
8
S9

R8
9

R9
12

R10
13

S10

Figura 3.5: Exemplo da intercalao de dois caminhos (Passo-5 do Merge2)

Arq1

R1
3

R2
7

Arq3

S1
1

S2
3

i=3

k=7

R3
9
S3
5

Arq2

R4
11
S4
7

j=8

S5
8

S6
9

R5
1

S7

R6
5
S8

R7
8
S9

R8
9

R9
12

R10
13

S10

Figura 3.6: Exemplo da intercalao de dois caminhos (Passo-6 do Merge2)

Arq1

R1
3

R2
7

Arq3

S1
1

S2
3

i=4

k=8

R3
9
S3
5

Arq2

R4
11
S4
7

R5
1

j=8

S5
8

S6
9

S7
9

R6
5

S8

R7
8
S9

R8
9

R9
12

R10
13

S10

Figura 3.7: Exemplo da intercalao de dois caminhos (Passo-7 do Merge2)

Arq1

R1
3

R2
7

Arq3

S1
1

S2
3

i=4

k=9

R3
9
S3
5

Arq2

R4
11
S4
7

R5
1

j=9

S5
8

S6
9

S7
9

R6
5
S8
11

S9

R7
8

R8
9

R9
12

R10
13

S10

Figura 3.8: Exemplo da intercalao de dois caminhos (Passo-8 do Merge2)

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 49

49
22/04/13 14:53

Arq1

R1
3

R2
7

Arq3

S1
1

S2
3

i=5

k=10

R3
9

R4
11

S3
5

Arq2

R5
1

j=9

S4
7

S5
8

S6
9

R6
5

S7
9

R7
8

S8
11

S9
12

R8
9

R9
12

R10
13

S10

Figura 3.9: Exemplo da intercalao de dois caminhos (Passo-9 do Merge2)

Arq1

R1
3

R2
7

Arq3

S1
1

S2
3

i=5

k=11

R3
9

R4
11

S3
5

S4
7

Arq2

R5
1

j=10

S5
8

S6
9

R6
5

S7
9

R7
8

S8
11

S9
12

R8
9
S10
13

R9
12

R10
13

Figura 3.10: Exemplo da intercalao de dois caminhos (Passo-10 do Merge2)

Arq1

R1
3

R2
7

Arq3

S1
1

S2
3

i=5

k=11

R3
9
S3
5

R4
11
S4
7

FIM

Arq2

R5
1

j=11

S5
8

S6
9

S7
9

R6
5
S8
11

R7
8
S9
12

R8
9
S10
13

R9
12

R10
13

Figura 3.11: Exemplo da intercalao de dois caminhos (Passo-11 do Merge2 )

Observe que a partir do passo 9 o ponteiro do arquivo Arq1 maior


que o nmero de registros nele contidos, ou seja, significa que foi atingido o
Fim de Arquivo ou end_of_file. Quando h esta ocorrncia em um dos
arquivos, o processo final de intercalao consiste somente em copiar os
demais registros do outro arquivo que ficou aberto para a sada.
No Algoritmo 3.1 que faz a intercalao de dois caminhos, identificado
como o procedimento Merge2, utilizaremos as mesmas variveis usadas no
exemplo anterior. Sem perda de generalidade, consideramos que R i, Rj e Sk
representam as chaves dos seus respectivos registros.
Arq1: K1 < K 2 < K3 < . . . < K m-1 < K m
Arq2: K m+1 < K m+2 < . . . < K n-1 < K n
Arq3: S1 < S2 < S3 < . . . . . .< Sn-1 < Sn

( ponteiro i )
( ponteiro j )
( ponteiro k )

PROCEDIMENTO MERGE2 (R, S, m, n)


ENTRADA: INTEIROS m, n
Registro R com duas sries a intercalar
// R1:m (primeira srie ordenada)
// Rm+1:n (segunda srie ordenada)
SADA: Registro S com uma nica srie ordenada
// S1:n (srie ordenada/intercalada)
// Variveis auxiliares

// K: vetor [1:n] de inteiros
// i, j, k, ini, fim: ponteiros/contadores

50

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 50

22/04/13 14:53

i = 1; k = 1; j = m + 1
ENQUANTO ( i m E j n )

SE ( Ki Kj )

Sk = Ri

i = i + 1
SENO

Sk = Rj

j = j + 1
SE ( i > m )
ini = j
fim = n
SENO
ini = i
fim = m
PARA i = ini AT fim
Sk = R i
k = k + 1
// fim para
// fim enquanto
RETORNA
FIM {MERGE2}
Algoritmo 3.1: Merge2 Intercalao de dois caminhos

3. Intercalao de trs caminhos


O algoritmo que faz a intercalao de trs caminhos, identificado como
o procedimento Merge3, utiliza R i, Rj, R l e Sk respectivamente representantes das chaves dos seus registros, como segue.
Arq1:
Arq2:
Arq3:
Arq4:

K1 < K 2 < K3 < . . . < Kp-1 < Kp


Kp+1 < Kp+2 < . . . < Kq-1 < Kq
Kq+1 < Kq+2 < . . . < K N-1 < K N
S1 < S2 < S3 < . . . . . .< SN-1 < SN

(
(
(
(

ponteiro
ponteiro
ponteiro
ponteiro

i )
j )
l )
k )

Uma vez atingido o fim de um dos arquivos, ser utilizada o procedimento Merge2, definido na seo 3.2, para intercalar os demais registros
dos outros dois arquivos. definida uma funo MENOR que identifica o
menor de trs valores numricos.
PROCEDIMENTO MERGE3 (R, S, p, q, N)
ENTRADA: INTEIROS p, q, N
Registro R com trs sries a intercalar
R1:p (primeira srie ordenada)
Rp+1:q (segunda srie ordenada)
Rq+1:N (terceira srie ordenada)
SADA: Registro S com uma nica srie ordenada
// S1:N (srie ordenada/intercalada)

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 51

51
22/04/13 14:53

// Variveis auxiliares

K: vetor [1:n] de inteiros

i, j, k, l, m, n: ponteiros/contadores
FUNO MENOR ( X, Y, Z ): inteiro

ENTRADA: X, Y, Z inteiros
SADA: MENOR
// retorna 1 se o menor X
// retorna 2 se o menor Y
// retorna 3 se o menor Z

// Variveis auxiliares

v: vetor [1:3] de inteiros
w: inteiro


v[1] = X;
v[2] = Y;
v[3] = Z;

MENOR = 1;
w = v[1];

PARA i = 2 AT 3

SE v[i] < w

w = v[i]

MENOR = i

// fim para

DEVOLVA MENOR

FIM {MENOR}
i = 1;
k = 1;
j = p + 1;
ENQUANTO ( i p E j q E l n )

CASO MENOR( Ki , Kj , Kl )
1: Sk = Ri

i = i + 1
2: Sk = Rj

j = j + 1
3: Sk = Rl

l = l + 1
// fim caso

k = k + 1

l = q + 1

// O trecho seguinte define os parmetros dos dois


// ltimos arquivos para o MERGE2.
SE ( i > p )

m

n
SENO
SE ( i

m

n
SENO
m

n

= q j + 1
= N - l + 1
> p )
= p i + 1
= N - l + 1
= p i + 1
= q j + 1

MERGE2 ( R, S, m, n )
// fim enquanto
RETORNA
FIM {MERGE3}
Algoritmo 3.2: Merge3 Intercalao de trs caminhos

52

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 52

22/04/13 14:53

4. Intercalao de k caminhos
Num caso geral, o algoritmo para fazer a intercalao de k caminhos,
identificado como o procedimento Mergek, pode ser implementado de forma
similar ao algoritmo da seo 3.
Por exemplo, para o Merge4 (k=4), a funo MENOR selecionaria o
menor valor entre quatro nmeros e no momento em que fosse atingido o
fim de um dos arquivos, deveria ser chamado o procedimento Merge3 para
finalizar o processo de intercalao.
Porm, como j foi citado anteriormente, no comum a utilizao de
uma intercalao com mais de trs caminhos, devido a complexidade deste
algoritmo, mesmo sabendo que o nmero de leituras e gravaes poderia
ser reduzido.
Os algoritmos de classificao por intercalao de k caminhos so conhecidos como de distribuio equilibrada. Na seo seguinte faremos uma
comparao entre intercalaes equilibradas para diferentes valores de k.

5. Comparao entre Distribuies Equilibradas


Esta comparao ser feita atravs de um exemplo. Vamos supor que
para classificar 7000 registros, a memria disponvel para a ordenao interna, em funo do tamanho dos registros, suporta processar no mximo
1000 registros por vez, ou seja, a cada 1000 registros lidos, feita sua classificao e a srie correspondente ordenada gravada em um meio auxiliar,
de forma sequencial.
Caso o nmero de registros do arquivo no seja mltiplo de 1000,
somente a ltima srie ficar incompleta, porm, como vimos nas sees
anteriores, isto no ser problema para o procedimento de intercalao do
tipo Mergek.
O nmero de arquivos de trabalho, bem como a distribuio das sries
nestes arquivos, depende do nmero k de caminhos a serem intercalados.
Nas subsees seguintes fazemos uma simulao para k= 2, 3 e 4 caminhos.

5.1 Classificao Equilibrada de dois caminhos


Para k=2 sero necessrios 4 arquivos de trabalho. A fase inicial de
classificao cria sries de comprimento 1000 e as coloca alternadamente
em dois destes arquivos (Arq1 e Arq2), assim:

Arq1
Arq2

R11000
R10012000

R20013000
R30014000

R40015000
R50016000

R60017000

Figura 3.12: Distribuio equilibrada em dois arquivos (Passo-1)

A notao Rp q corresponde srie ordenada a partir dos registros de


entrada da posio p at a posio q.
As sries dispostas em cada coluna da tabela anterior so intercaladas
via Merge2 produzindo outras sries at duas vezes maiores que as sries
iniciais. Essas so gravadas em outros dois arquivos (Arq3 e Arq4), assim:

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 53

53
22/04/13 14:53

Arq3
Arq4

R12000
R20014000

R40016000
R60017000

Figura 3.13: Resultado da intercalao de dois caminhos (Passo-2)

Este processo repetido de forma alternada entre os arquivos Arq1/Arq2


e Arq3/Arq4, at que apenas uma srie (arquivo classificado) seja produzida.

Arq1
Arq2

Arq3
Arq4

R14000
R40017000

R17000

Figura 3.14: Intercalao final de dois caminhos (Passos 3 e 4)

Observe que em todo o processo de classificao foram realizadas 28.000


leituras e 28.000 gravaes, correspondendo a 7.000 delas em cada passo.
Para efeito, vamos considerar um arquivo com 20 registros, considerando somente suas chaves, e um limite de classificao interna de 3
registros.
Ri

10

11

12

13

14

15

16

17

18

19

20

Ki

27

14

29

22

33

18

23

11

17

12

23

Figura 3.15: Exemplo de classificao com 7 sries de at 3 registros cada

Arq1
Arq2

5-14-27

9-18-33

4-11-17

5-23

2-22-29

1-7-23

8-9-12

Figura 3.16: Fase-1 da intercalao de dois caminhos do exemplo da Fig. 3.15

Arq3 2-5-14-22-27-29
Arq4 1-7-9-18-23-33

4-8-9-11-12-17
5-23

Figura 3.17: Fase-2 da intercalao de dois caminhos a partir da Fig. 3.16

Arq1

1-2-5-7-9-14-18-22-23-27-29-33

Arq3

1-2-4-5-5-7-8-9-9-11-12-14-1718-22-23-23-27-29-33

Arq2

4-5-8-9-11-12-17-23

Arq4

Figura 3.18: Fases 3 e 4 da intercalao de dois caminhos a partir da Fig. 3.17

5.2 Classificao Equilibrada de trs caminhos


Para k=3 podem ser usados tambm 4 arquivos de trabalho. A fase
inicial de classificao cria sries de comprimento 1000 e as distribui tambm em dois arquivos, a diferena que em determinado momento da segunda fase, usando o Merge2, pelo menos um dos arquivos fica vazio, de
modo que possvel a partir da utilizar o Merge3.

54

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 54

22/04/13 14:53

Observe a seguir como seria a classificao.


Fase-1 (ordenao interna e gravao inicial)

Arq1
Arq2
Arq3
Arq4

R11000
R10012000

R20013000
R30014000

R40015000
R50016000

R60017000

Figura 3.19: Distribuio equilibrada em trs arquivos

Fase-2 (uso do Merge2 )

Arq1

Arq2

Arq3 R12000
Arq4 R20014000

(ponteiro)

R40016000

R60017000

Figura 3.20: Intercalao de dois caminhos do exemplo da Fig. 3.19

Fase-3 (uso do Merge3 )

Arq1
Arq2
Arq3
Arq4

S15000

Fase-4 (uso do Merge2 )

R40016000

Arq1
Arq2
Arq3
Arq4

S17000

Figura 3.21: Intercalao de trs e dois caminhos a partir da Fig. 3.20

A srie S15000 a sada do Merge3 com entradas obtidas a partir de


R60017000, R12000 e R 20014000 , nesta ordem. A fase final corresponde ao Merge2
entre os registros com ponteiros em Arq2 e Arq3 com sada em Arq1.
Observe que para todas as fases deste tipo de classificao pode ser
usado o Merge3, dado que, de acordo com sua descrio na seo 3, quando um dos arquivos est com o ponteiro no final (end_of_ file) o Merge2
acionado.
O nmero de leituras e gravaes reduzido de 28.000 para 25.000,
visto que para cada fase teramos:

Fase-1

Fase-2

Fase-3

Fase-4

Total (L/G)

7.000

6.000

5.000

7.000

25.000

Figura 3.22: Nmero de Leituras e Gravaes para o exemplo da Fig. 3.19

5.3 Classificao Equilibrada de mltiplos caminhos


Para k > 4 sero necessrios (k+1) arquivos de trabalho. A fase inicial
de classificao cria sries de comprimentos fixos e as coloca alternadamente em k arquivos (Arq1 a Arqk), deixando o de ordem (k+1) livre. As fases
seguintes utilizam o procedimento de intercalao de k caminhos (Mergek).

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 55

55
22/04/13 14:53

Para o exemplo da subseo anterior, teramos para k=4:


Fase-1 (classificao interna e distribuio alternada das sries)

Arq1
Arq2
Arq3
Arq4
Arq5

R11000
R10012000
R20013000
R30014000

R40015000
R50016000
R60017000

Figura 3.23: Distribuio equilibrada em quatro arquivos

Fase-2 (Merge4 )

Arq1
Arq2
Arq3
Arq4
Arq5

R14000

R40015000
R50016000
R60017000

Figura 3.24: Intercalao de quatro caminhos do exemplo da Fig. 3.23

Fase-3 (Merge4 )

Arq4

R17000

Figura 3.25: Intercalao de quatro caminhos a partir da Fig. 3.24

O nmero de leituras e gravaes reduzido mais ainda, no caso, de


25.000 para 18.000, assim:
Fase-1
7.000

Fase-2
4.000

Fase-3
7.000

Total (L/G)
18.000

Figura 3.26: Nmero de Leituras e Gravaes para o exemplo da Fig. 3.23

6. Intercalao Polifsica
O objetivo deste tipo de intercalao distribuir as sries iniciais de
forma desequilibrada, de modo que menos passos sejam necessrios para
a classificao total.
Em funo do nmero de arquivos T a serem utilizados gerada uma
tabela de distribuio com base na Srie de Fibonacci. necessrio ento
que o algoritmo de classificao externa contenha uma tabela desta distribuio em funo do valor de T. Sabemos que, de modo similar intercalao
de mltiplos caminhos, para T arquivos devemos ter k = (T 1) caminhos.
A seguir mostramos as tabelas para alguns casos. Caso o nmero
de sries no esteja contido na tabela, considerar a distribuio imediatamente superior; isso acarreta que durante a fase de intercalao as sries
complementares sejam vazias, ou seja, j foi atingido seu final de arquivo.

56

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 56

22/04/13 14:53

Por exemplo, na Tabela 3.1, caso o nmero de sries seja igual a 10, a distribuio usada seria a de nvel 5, ou 13 sries, sendo que nesse caso, 3 delas
seriam vazias.
Tabela 3.1: Distribuio polifsica para k=2 ( T=3 arquivos, usar o Merge2 )

Nvel
N
n+1
0
1
2
3
4
5
6
7
8
9
10
11
...

T1
a
a+b
1
1
2
3
5
8
13
21
34
55
89
144
...

T2
b
a
0
1
1
2
3
5
8
13
21
34
55
89
...

Sries
T
t+a
1
2
3
5
8
13
21
34
55
89
144
233
...

Tabela 3.2: Distribuio polifsica para k=3 ( T=4 arquivos, usar o Merge3 )

Nvel
N
n+1
0
1
2
3
4
5
6
7
8
...

T1
a
a+b
1
1
2
4
7
13
24
42
79
...

T2
b
a+c
0
1
2
3
6
11
18
37
66
...

T3
c
a
0
1
1
2
4
7
13
24
42

Sries
t
t+2a
1
3
5
9
17
31
55
103
187
...

Tabela 3.3: Distribuio polifsica para k=4 ( T=5 arquivos, usar o Merge4 )

Nvel
n
n+1
0
1
2
3
4
5
6
7
8
...

T1

a
a+b
1
1
2
4
8
15
29
56
108
...

T2

b
a+c
0
1
2
4
7
14
27
52
100
...

T3

C
a+d
0
1
2
3
6
12
23
44
85

T4

d
a
0
1
1
2
4
8
15
29
56

Sries
t
t+3a
1
4
7
13
25
49
94
181
349
...

Exemplo 3.1: Classificao por interpolao polifsica para 25 sries


utilizando T=5 arquivos. Consultando a tabela acima observe que a distribuio inicial deve ser feita de acordo com a linha indicada pelo nvel 5. Na
Tabela 3.4 o arquivo de sada em cada fase est indicado pela smbolo .

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 57

57
22/04/13 14:53

Tabela 3.4: Distribuio para k=4 caminhos e T=5 arquivos do Exemplo 3.1

Fase
1
2
3
4
5

8
4
2
1

T1
x1
x1
x1
x1

T2
7x1
3x1
1x1

1 x 25

T3
6x1
2x1

1 x 13

T4
4x1

2x7
1x7

T5

4x4
2x4
1x4

A notao s x t indica s sries de tamanho t. Note que de uma fase


para a seguinte o menor valor de s (nmero de sries) da fase i corresponde quantidade a ser retirada de cada arquivo para que possa ser feita a
intercalao Merge4 e gravadas no arquivo de sada da fase i+1.
Exemplo 3.2: Classificao por interpolao polifsica para 25 sries
utilizando T=4 arquivos. Consultando a Tabela 3.2 observamos que o nmero 31 constante aquele que mais se aproxima de 25; no caso seriam
distribudas entre os arquivos 6 sries fictcias vazias.
Utilizando o Merge3, a sequncia de intercalaes seria esta:
Tabela 3.5: Distribuio para k=3 caminhos e T=4 arquivos do Exemplo 3.2

Fase

1
2
3
4
5
6

T1

13 x 1
6x1
2x1

1 x 17

T2

11 x 1
4x1

2x9
1x9

T3

7x

4x
2x
1x

1
5
5
5

T4

7x3
3x3
1x3

1 x 31

1. O algoritmo Merge2 da seo 2 no leva em considerao se os dois blocos a serem intercalados so tais que todas as chaves de um bloco sejam
maiores que o outro. Faa ento uma alterao neste procedimento para
prever este caso especfico. Indique qual o benefcio desta ao.
2. Para a intercalao de 4 caminhos (Merge4) poderia ser usada uma das
tcnicas citadas a seguir. Indique qual a melhor delas e justifique.
a) De forma semelhante ao Merge3 da seo 3, modificando a funo
MENOR para comparar quatro nmeros e ampliando as comparaes.
b) Merge4 ( A, B, C, D ) = Merge2 ( Merge3 (A,B,C), D)
c) Merge4 ( A, B, C, D ) = Merge2 ( Merge2 (A,B) , Merge2 (C,D))
3. Utilize algum procedimento apresentado neste captulo para classif icar um arquivo contendo 4.500 registros, sabendo que possvel
classif icar no m ximo 750 destes registros na memria interna.
Indique o nmero de leituras e gravaes ocorridas.
4. Defina uma estratgia diferente da utilizada no item anterior de modo a
reduzir o nmero de leituras e gravaes.

58

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 58

22/04/13 14:53

5. Considere as seguintes chaves de um arquivo que pode ser dividido em


exatamente dois blocos para uso numa classificao externa:
i
Ki

10

11

12

13

14

15

16

17

18

19

20

15

24

19

12

13

28

53

21

17

42

19

18

13

Suponha a existncia de uma funo MEDIANA(V,N), que calcula a mediana de um vetor V[1:N] e dos procedimentos QSORT(A,N) que ordena
o vetor A[1:N] totalmente na memria principal e Merge2 (X, m,Y, n, S)
que faz a intercalao de 2 caminhos, onde S[1:(m+n)] o vetor ordenado
resultante da intercalao dos vetores X[1:m] e Y[1:n].
Apresente os resultados aps executar cada um dos seguintes passos:
a) W = MEDIANA (K, 20)
b) X = Ki, se Ki < W e Y = Ki, se Ki > W, i = 1:20

c) QSORT (X, 10); QSORT (Y, 10);

d) Merge2 (X, m,Y, n, S); apresente S.


6. Escreva um algoritmo para resolver de forma geral o mtodo descrito no
exerccio 5.
7. Generalize o mtodo descrito no exerccio 5 para proceder a classificao
interna considerando qualquer nmero de sries.
8. Como foi apresentado, a ordenao de um arquivo atravs da classificao externa se faz necessrio quando seus registros no cabem totalmente na memria principal, em funo do tamanho de cada um deles,
e no por causa do grande nmero de chaves. Indique uma alternativa
para ordenar arquivos desta magnitude sem utilizar os procedimentos
de intercalao.
9. Fazer uma comparao, em relao ao nmero de leitura e gravaes
necessrias para realizar uma classificao externa com 25 sries de
tamanho 1000 cada, considerando as seguintes tcnicas de intercalao
equilibrada de:
a) dois caminhos
b) trs caminhos
c) quatro caminhos
10. Repetir o exerccio 9 considerando agora a intercalao polifsica de:
a) dois caminhos (T=3)
b) quatro caminhos (T=5)

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 59

59
22/04/13 14:53

Pesq_Ord_de_Dados 60

22/04/13 14:53

Captulo

Tcnicas de pesquisa

Objetivos:




Definir as tcnicas de pesquisa sequencial e binria


Apresentar as tabelas de disperso
Apresentar as rvores de busca balanceadas
Mostrar as tcnicas de manuteno das rvores de pesquisa
Analisar a complexidade dos algoritmos de pesquisa

Pesq_Ord_de_Dados 61

22/04/13 14:53

Pesq_Ord_de_Dados 62

22/04/13 14:53

Apresentao
Neste captulo apresentamos diversas tcnicas e estruturas de dados
que permitem fazer pesquisa com bastante eficincia. Inicialmente, apresentamos o procedimento de busca sequencial que, apesar de ser ineficiente,
serve para efeito de comparao com os demais mtodos. A seguir abordamos
a busca binria, que permite encontrar um valor contido num vetor ordenado
com extrema eficincia. No entanto, as operaes de insero e remoo tm
custo computacional elevado, por isso comum utilizar outras estruturas
de pesquisa em que os dados estejam implicitamente ordenados, como as
tabelas de disperso onde, sob certas hipteses, essas operaes podem ser
feitas em tempo esperado constante. No final do captulo abordamos trs tipos de rvores de busca balanceadas: rvores AVL, rvores B e rvores B+.
Descrevemos as operaes de insero, busca e remoo nessas estruturas e
mostramos que tais operaes so feitas em tempo logartmico, no pior caso.

1. Tcnicas de Pesquisa
Uma das tarefas de maior importncia na computao a pesquisa
de informaes contidas em colees de dados. Em geral, desejamos que
essa tarefa seja executada sem que haja a necessidade de inspecionar toda
a coleo de dados.
Neste captulo apresentamos diversas tcnicas e estruturas de dados
que permitem fazer pesquisa com bastante eficincia. Discutimos as operaes de insero, busca e remoo nessas estruturas, analisando sua
complexidade temporal e espacial.
Inicialmente, nas sees 2 e 3, descrevemos respectivamente os procedimentos de busca sequencial que trivial e ineficiente, e de busca binria,
que permite encontrar um valor contido num vetor ordenado com extrema
eficincia. Sabe-se, no entanto, que as operaes de insero e remoo
num vetor ordenado tm custo computacional elevado.
Em seguida, na seo, apresentamos as tabelas de disperso, discutindo as tcnicas de hashing fechado e hashing aberto. Tais tcnicas podem
ser usadas para resolver o problema da coliso de chaves que inerente ao
uso dessas estruturas. Mostramos que, sob certas hipteses, as operaes
de insero, busca e remoo em tabelas de disperso so feitas em tempo
esperado constante.
Finalmente, na seo 5 abordamos trs tipos de rvores de busca
balanceadas: rvores AVL, rvores B e rvores B+. Nessas estruturas as
operaes de insero, busca e remoo so feitas em tempo logartmico.

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 63

63
22/04/13 14:53

2. Busca Sequencial
Podemos procurar, ou buscar, um valor x num vetor L inspecionando
em sequncia as posies de L a partir da primeira posio. Se encontrarmos x, a busca tem sucesso. Se alcanarmos a ltima posio de L sem
encontrar x, conclumos que x no ocorre no vetor L. Esse tipo de busca
chamado de busca sequencial.
Considerando que o vetor L contm n elementos, ordenados ou no,
fcil verificar que a busca sequencial requer tempo linearmente proporcional ao tamanho do vetor, ou seja, O(n); por isso, comum dizer que a
busca sequencial uma busca linear. Observa-se que, no melhor caso, o
elemento x encontrado logo na primeira tentativa da busca, atravs de
uma comparao; no pior caso, x encontra-se na ltima posio e so feitas
n comparaes, logo, no caso mdio, o elemento encontrado aps (n+1)/2
comparaes. Para vetores de mdio ou grande porte, esse tempo considerado inaceitvel, dado que existem tcnicas mais eficientes descritas nas
sees seguintes.
Antes apresentamos dois algoritmos para a busca sequencial.
PROCEDIMENTO BUSCA_SEQUENCIAL ( L , X , POS )
ENTRADA: UM VETOR L e UM VALOR X
SADA: POS = i, SE X OCORRE NA POSIO i DE L // SUCESSO
POS = 0, CASO CONTRRIO.
POS = 0
PARA i = 1 at N

SE L[i] = X

POS = i

ESCAPE
// fim para
DEVOLVA POS
FIM {BUSCA_SEQUENCIAL}
Algoritmo 4.1: Busca Sequencial Simples

PROCEDIMENTO BUSCA_SEQUENCIAL_REC ( L , N, X )
ENTRADA: UM VETOR L DE TAMANHO N e UM VALOR X
SADA: i, SE X OCORRE NA POSIO i DE L
// SUCESSO
0, CASO CONTRRIO.
SE N = 1
SE L[1] = X

DEVOLVA 1
SENO

DEVOLVA 0
SENO
SE L[N] = X
DEVOLVA N
SENO
BUSCA_SEQUENCIAL_REC ( L , N-1, X )
FIM {BUSCA_SEQUENCIAL_REC}
Algoritmo 4.2: Busca Sequencial Recursiva

64

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 64

22/04/13 14:53

3. Busca Binria
Quando o vetor L estiver em ordem crescente, podemos determinar se
x ocorre em L de forma mais rpida da seguinte maneira: inspecionamos a
posio central de L; se ela contm x a busca para, tendo sido bem sucedida,
caso contrrio, se x for menor do que o elemento central passamos a procurar x, recursivamente, no intervalo de L que est esquerda da posio
central. Se x for maior do que o elemento central continuamos a procurar x,
recursivamente, no intervalo de L que est direita da posio central. Se o
intervalo se tornar vazio, a busca para, tendo sido mal sucedida.
O procedimento que acabamos de descrever chamado de busca binria. Facilmente, podemos adaptar a busca binria para procurar valores
em vetores que estejam em ordem decrescente. O Algoritmo 4.3 fornecemos
uma descrio recursiva em pseudocdigo desse procedimento.
PROCEDIMENTO BUSCA_BINARIA
ENTRADA: UM VETOR L EM ORDEM CRESCENTE, UM VALOR X, E AS
POSIES INICIO E FIM.
SADA: SIM, SE X OCORRE ENTRE AS POSIES INICIO E FIM DE
L; NO, CASO CONTRRIO.
SE INICIO > FIM
DEVOLVA NO E PARE
MEIO = (INICIO+FIM)/2
// DIVISO INTEIRA
SE X = L[MEIO]
DEVOLVA SIM E PARE
SE X < L[MEIO]
DEVOLVA BUSCA_BINARIA(L, X, INICIO, MEIO - 1)
SENAO
DEVOLVA BUSCA_BINARIA(L, X, MEIO + 1, FIM)

FIM {BUSCA_BINARIA}

Algoritmo 4.3: Busca Binria

A Figura 4.1 ilustra o funcionamento do Algoritmo Busca Binria ao


procurar o valor 34 num vetor ordenado. Observe que apenas as posies
8, 13 e 10 do vetor (nessa ordem) so inspecionadas. A tabela que aparece
aps o vetor mostra os valores dos parmetros de entrada (exceto o vetor L,
que passado por referncia e compartilhado por todas as chamadas), o
contedo da varivel MEIO e o valor devolvido por cada chamada.

0
2

1
5

2
5

Chamada
1
2
3

3
8

4
10

x
34
34
34

5
13

6
16

7
17

INICIO
0
9
9

8
29

9
31

FIM
17
17
12

10
34

11
36

12
43

MEIO
8
13
10

Figura 4.1: Exemplo de busca binria

13
49

14
51

15
56

16
65

17
69

Valor
devolvido
Sim
Sim
Sim

Se estivssemos procurando o valor 7 no vetor da Figura 4.1, iramos


inspecionar apenas as posies 8, 3, 1 e 2 do vetor (nessa ordem). A Tabela
4.1 mostra os valores dos parmetros de entrada, o contedo da varivel
PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 65

65
22/04/13 14:53

MEIO e o valor devolvido por cada chamada. Naturalmente, como 7 no


ocorre no vetor, o valor devolvido No.
Tabela 4.1: Exemplo de busca binria

Chamada
1
2
3
4
5

Na verdade, como o Algoritmo Busca Binria utiliza recurso de cauda, o


compilador/interpretador
pode gerar uma verso
desse algoritmo em linguagem de mquina que
tenha complexidade espacial constante.

O operador mod denota a


operao de resto da diviso, inteira.

x
7
7
7
7
7

INICIO
0
0
0
2
3

FIM
17
7
3
2
2

MEIO
8
3
1
2
-

Valor
devolvido
No
No
No
No
No

Vamos denotar por T(n) o tempo requerido pelo Algoritmo Busca Binria para procurar um valor num intervalo com n posies. Note que se x
no estiver na posio central do intervalo ser feita uma chamada recursiva para procurar x num intervalo que ter aproximadamente n/2 posies.
Dessa forma, correto afirmar que:
T(n) T(n/2) + c
T(0) = c
Resolvendo essa frmula de recorrncia conclumos que T(n) O(log
n). Sendo assim, a complexidade temporal do Algoritmo Busca Binria pertence a O(log n).
fcil perceber que a complexidade espacial desse algoritmo tambm
dada pela mesma frmula de recorrncia. Conclumos que tal complexidade tambm pertence a O(log n). Vale salientar que se implementarmos
o procedimento de busca binria ser usar recursividade, a complexidade
espacial passa a ser constante.
possvel adaptar o procedimento de busca binria para encontrar
um valor mais prximo de x num vetor ordenado. Por exemplo, no vetor da
Figura 4.1, o valor mais prximo do 40 43. Esse tipo de busca conhecida
como busca binria aproximada. Tal adaptao deixada como exerccio
para o leitor no final deste captulo.
Apesar da busca binria ser extremamente eficiente, as operaes de
insero e remoo so feitas em tempo linearmente proporcional ao tamanho do vetor e isso, em geral, considerado inaceitvel. Por esse motivo,
nas situaes em que as operaes de insero e remoo so frequentes,
prefervel utilizar uma estrutura de dados onde os dados estejam implicitamente ordenados e que tambm permitam fazer inseres e remoes com
bastante eficincia. Na Seo 4 descrevemos alguns tipos de rvores que
possuem tais caractersticas.

4. Tabelas de Disperso
As tabelas de disperso, tambm conhecidas como tabelas de espalhamento ou tabelas de hashing, armazenam uma coleo de valores, sendo
que cada valor est associado a uma chave. Tais chaves tm que ser todas
distintas e so usadas para mapear os valores na tabela. Esse mapeamento
feito por uma funo de hashing, que chamaremos de h.
Por exemplo, podemos implementar uma tabela de disperso usando
um vetor com oito posies e utilizar h(x) = x mod 8 como funo de hashing.
Dizemos que h(k) a posio original da chave k e nessa posio da tabe-

66

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 66

22/04/13 14:53

la que a chave k deve ser inserida. A Figura 4.2 ilustra a insero de uma
coleo de valores com suas respectivas chaves numa tabela de disperso.
Chave

Valor

25

Lia

Funo de hashing:

18

Ana

h(x) = x mod 8

Rui

31

Gil

4
5
6
7

Figura 4.2: Tabela de disperso

Observe que o valor Gil foi colocado na posio 7 da tabela, pois a chave associada a Gil 31 e h(31) = 7. O que aconteceria se tentssemos inserir
nessa tabela o valor Ivo com chave 33 ? Observe que h(33) = 1, mas a posio 1 da tabela j est ocupada. Dizemos que as chaves 25 e 33 colidiram.
Mais precisamente, duas chaves x e y colidem se h(x) = h(y).
Note que o problema da coliso de chaves ocorre porque, na maioria
dos casos, o domnio das chaves maior que a quantidade de posies da
tabela. Sendo assim, pelo princpio da casa de pombos, qualquer funo do
conjunto das chaves para o conjunto das posies da tabela no injetora.
No aceitvel recusar a insero de uma chave que colida com outra
j existente na tabela se ela ainda tiver posies livres. Precisamos, portanto, de alguma estratgia para lidar com as colises de chaves. Existem
diversas tcnicas para lidar com as colises. Nas prximas duas subsees
apresentaremos duas dessas tcnicas.

4.1 Hashing Fechado


Na tcnica conhecida como hashing fechado, quando tentamos inserir
uma chave y e ela colide com uma chave x j existente na tabela, colocamos
y na primeira posio livre aps a posio h(y). Uma tabela de disperso
que utilize essa estratgia para resolver as colises de chaves costuma ser
chamada de tabela de hashing fechado.
Na tabela da Figura 4.2, a chave 33 deve ser inserida na posio 3 visto que ela a primeira posio livre aps a posio h(33). Consideramos que
aps a ltima posio da tabela vem a posio 0. Sendo assim, na tabela da
Figura 4.2, a chave 23 deve ser inserida na posio 0. A Figura 4.3 mostra
a tabela da Figura 4.2 aps a insero das chaves 33 e 23. Dizemos que as
chaves 23 e 33 esto deslocadas de suas posies originais e denotamos tal
fato na figura usando o asterisco.

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 67

67
22/04/13 14:53

Chave

Valor

23*

Edu

25

Lia

Funo de hashing:

18

Ana

h(x) = x mod 8

33*

Ivo

Rui

31

Gil

4
5
6
7

Figura 4.3: Inseres em hashing fechado

Obviamente, se a tabela estiver cheia e tentarmos inserir mais uma


chave, tal insero no ser possvel. Nesse caso, dizemos que ocorreu um
evento conhecido como estouro da tabela de disperso (hash overflow).
Ao usarmos essa estratgia para resolver as colises, a seguinte propriedade mantida pelas operaes de insero: se uma chave k foi inserida numa posio j, ento as posies da tabela desde h(k) at j tm que
estar ocupadas. Como decorrncia dessa propriedade, para buscar uma
chave k numa tabela de hashing fechado devemos inspecionar em sequncia as posies da tabela a partir da posio h(k). A busca termina quando
ocorrer um dos seguintes eventos:
A posio inspecionada contm k. Nesse caso, a busca foi bem sucedida.
A posio inspecionada est livre. Nesse caso, podemos concluir que
k no ocorre na tabela.
Todas as posies foram inspecionadas. Se esse evento ocorrer antes dos dois anteriores significa a tabela no tem posies livres e
que a chave k no ocorre na tabela.
Por exemplo, se procurarmos a chave 33 na tabela da Figura 4.3, teremos que inspecionar as posies 1, 2 e 3 e a busca ser bem sucedida. Por
outro lado, se procurarmos a chave 15, inspecionaremos as posies 7, 0, 1,
2 e 3 e a busca ser mal sucedida.
A remoo numa tabela de hashing fechado um pouco mais complicada que a insero e a busca. Precisamos garantir que a propriedade
decorrente das inseres, que enunciamos anteriormente, tambm seja preservada pelas remoes.
Para remover uma chave k, primeiramente precisamos encontr-la.
Obviamente, se k no ocorre na tabela a remoo mal sucedida. Suponha
que a chave k foi encontrada numa posio j. Tal posio deve ser liberada.
Em seguida, inspecionamos as posies subsequentes em busca de uma
chave que esteja deslocada. Se encontrarmos uma chave deslocada cuja
posio original seja a posio que foi liberada ou uma posio anterior a
ela, devemos mov-la para a posio que est livre. Note que a posio onde
estava a chave deslocada agora est livre. O processo ento repetido at
que uma posio livre seja alcanada.
Por exemplo, para remover a chave 18 da tabela da Figura 4.3 devemos
liberar a posio 2 e em seguida mover a chave 33 para a posio 2. A remoo

68

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 68

22/04/13 14:53

para quando a posio 4 atingida. Se aps essa remoo quisermos remover


a chave 31, teremos que mover a chave 23 para a posio 7. Com isso, a posio 0 fica livre. Observe que chave 33, apesar de estar deslocada, no deve ser
movida para a posio 0, pois sua posio original a posio 1. A Figura 4.4
mostra como ficaria a tabela da Figura 4.3 aps essas duas remoes.
Chave

Valor

25

Lia

Funo de hashing:

33*

Ivo

h(x) = x mod 8

Rui

23

Edu

Naturalmente existe um
limite para a quantidade
de chaves que podem ser
armazenadas numa tabela de hashing aberto. No
entanto, esse limite determinado pela memria
fsica do computador e no
pelo tamanho da tabela.

4
5
6
7

Figura 4.4: Remoes em hashing fechado

4.2 Hashing Aberto


A tcnica de hashing aberto bem mais simples que hashing fechado.
Numa tabela de hashing aberto cada posio da tabela contm um ponteiro
para uma lista encadeada que contm todas as chaves mapeadas pela funo de hashing naquela posio. Note que usando essa tcnica o espao de
armazenamento das chaves no fica restrito tabela, da o nome hashing
aberto, e no h limitao quanto quantidade de chaves que podem ser
armazenadas na tabela. Dessa forma, ao utilizar essa estratgia para resolver as colises, no precisamos nos preocupar com hash overflow.
Para inserir uma chave k numa tabela de hashing aberto, calculamos
h(k) e ento inserimos tal chave (e o valor associado a ela) no final da lista
encadeada apontada pela posio h(k) da tabela, caso essa chave no ocorra nessa lista (lembre-se de que numa tabela de disperso as chaves tm
que ser todas distintas).
Ilustramos na Figura 4.5 a insero das chaves 25, 18, 31, 5, 23 e 33,
nessa ordem, numa tabela de hashing aberto com 5 posies e que utiliza a
funo de hashing h(x) = x mod 5.
0

25

Lia

31

Gil

18

Ana 23 Edu 33

Funo de hashing:

h(x) = x mod 5

Rui

Ivo

Figura 4.5: Inseres em Hashing aberto

Para encontrar uma chave k numa tabela de hashing aberto basta


procurar tal chave na lista encadeada apontada pela posio h(k) da tabela.
PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 69

69
22/04/13 14:53

A remoo em hashing aberto tambm bastante simples. Aps encontrar a


chave que se deseja remover, basta remover o n que a contm. A Figura 4.6
mostra a tabela da Figura 4.5 aps a remoo das chaves 18 e 31.

25

Lia

Rui

23

Edu 33

Ivo

Funo de hashing:

h(x) = x mod 5

3
4

Figura 4.6: Remoes em Hashing aberto

Vamos agora discutir a eficincia das operaes de insero, busca e


remoo em tabelas de disperso. Antes, precisamos definir alguns termos.
Dizemos que uma funo de hashing boa se ela pode ser computada em tempo constante e se ela espalha as chaves na tabela de maneira
uniforme. Por exemplo, dada uma tabela de disperso com 37 posies, a
funo h(x) = 2x mod 37 no boa, pois ela espalha as chaves somente nas
posies mpares da tabela. A funo h(x) = x! mod 37 tambm no boa,
pois no pode ser computada em tempo constante. J a funo h(x) = x mod
37 boa, se o domnio das chaves o conjunto dos nmeros naturais. Caso
o domnio das chaves seja o conjunto dos naturais pares, h(x) = x mod 37
deixaria de ser uma boa funo de hashing, pois mapearia as chaves somente nas posies mpares da tabela. Nesse caso, a funo h(x) = x/2 mod
37 seria considerada boa.
A carga de uma tabela de disperso a razo entre a quantidade de
chaves e a quantidade de posies da tabela. Por exemplo, a carga da tabela
da Figura 4.6 0,8. A carga de uma tabela de hashing fechado considerada baixa se ela menor ou igual a 0,5. No caso de uma tabela de hashing
aberto, a carga considerada baixa se ela limitada por uma constante.
possvel mostrar que se a funo de hashing boa e a carga
baixa, as operaes de insero, busca e remoo so feitas em tempo esperado constante.
Observe que no caso de hashing fechado, as operaes de insero,
busca e remoo sempre terminam quando uma posio livre atingida. Se
a carga baixa, pelo menos a metade das posies da tabela estaro livres.
Sendo assim, se a funo de hashing espalha as chaves de maneira uniforme, a cada duas posies consecutivas esperado que pelo menos uma esteja livre e consequentemente a quantidade esperada de posies que devem
ser inspecionadas constante.
No caso de um hashing aberto, se a carga baixa e a funo de hashing
espalha as chaves de maneira uniforme, o tamanho esperado de cada lista
encadeada ser constante. Note que as operaes de insero, busca e remoo gastam tempo limitado pelo tamanho da maior lista encadeada. Isso
implica que tais operaes iro requerer tempo esperado constante.
Nas situaes prticas nas quais a quantidade mxima de chaves que
sero armazenadas na tabela pode ser estimada a priori, possvel determinar o tamanho que a tabela deve ter de modo a garantir que sua carga

70

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 70

22/04/13 14:53

seja sempre baixa. Em tais situaes, o uso de tabelas de disperso pode


ser bastante adequado.

5. rvores de Busca Balanceadas


Nessa seo abordaremos as rvores de busca balanceadas. Nessas
rvores, as chaves armazenadas so mantidas implicitamente ordenadas.
Isso permite que a operao de busca seja feita percorrendo-se um ramo
da rvore, desde a raiz at, no mximo, chegar a uma folha. Alm disso,
tais rvores possuem propriedades que garantem que sua altura seja muito
pequena se comparada quantidade de chaves contidas na rvore. Como
veremos mais adiante, isso garante que as operaes de insero, busca e
remoo sejam feitas com muita eficincia.
Discutiremos trs tipos de rvores de busca balanceadas: rvores
AVL, rvores B e rvores B+.

5.1 rvores AVL


As rvores AVL so rvores binrias propostas por Adelson-Velski e
Landis em 1962 que se caracterizam por duas propriedades:
Se um n da rvore contm uma chave x, as chaves contidas na
subrvore esquerda desse n so todas menores do que x e as
chaves contidas na subrvore direita desse n so todas maiores
do que x.
Para cada n da rvore, a diferena de altura entre a subrvore
esquerda desse n e a subrvore direita desse n de no mximo 1.
A primeira propriedade garante que as chaves contidas na rvore estejam implicitamente ordenadas. A segunda propriedade garante o balanceamento da rvore.
A estrutura de um n de uma rvore AVL pode ser constituda dos
seguintes campos:
chave: armazena uma chave.
filhoesq: ponteiro para o filho esquerdo.
filhodir: ponteiro para o filho direito.
bal: a altura da subrvore esquerda menos a altura da subrvore
direita do n.
O campo bal indica como est o balanceamento das subrvores apontadas pelo n e auxilia a manter o balanceamento da rvore nas operaes
de insero e remoo. Observe que os nicos valores aceitveis para o
campo bal so 1, 0 e 1. A Figura 4.7 exibe um exemplo de rvore AVL. O
valor do campo bal aparece acima de cada n.

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 71

71
22/04/13 14:53

31
-1

15

39

7
0

19

34
9

17
Figura 4.7: Exemplo de rvore AVL

Se permitirmos a ocorrncia de chaves repetidas


numa rvore AVL podemos chegar numa situao onde impossvel
preservar a propriedade
do balanceamento. Por
exemplo, imagine como
seria uma rvore AVL com
as chaves 15, 15 e 15.

72

A operao de busca numa rvore AVL similar busca numa rvore


binria de busca qualquer. Para procurar uma chave k, primeiramente verificamos se a rvore vazia. Em caso afirmativo, a busca para, tendo sido
mal sucedida. Caso contrrio, verificamos se a chave contida na raiz k.
Nesse caso, a busca tem sucesso. Caso contrrio, se k for menor do que a
chave contida na raiz, repetimos o processo recursivamente na subrvore
esquerda da raiz. Se k for maior do que a chave contida na raiz, repetimos
o processo recursivamente na subrvore direita da raiz. Na rvore da Figura 4.7, para chegar na chave 17 teremos que passar antes pelos ns que
contm as chaves 31, 15 e 19. Se buscarmos a chave 42, passaremos pelos
ns que contm as chaves 31 e 39 at atingir a subrvore direita do 39,
que vazia. A busca ser ento mal sucedida.
J a operao de insero mais complicada. Para inserir uma chave
k numa rvore AVL devemos percorr-la, a partir da raiz, como se estivssemos procurando k. Se a chave k for encontrada, a insero deve ser
abortada pois rvores AVL no podem ter chaves repetidas. Caso contrrio, atingiremos um ponteiro nulo. Devemos ento criar uma nova folha
contendo a chave k e fazer o ponteiro que era nulo apontar para tal folha.
Naturalmente, os campos filhoesq e filhodir dessa nova folha devem ser nulos e o campo bal deve receber o valor 0.
Precisamos ainda atualizar o bal dos ancestrais dessa nova folha. Isso
deve ser feito da seguinte maneira. Se a folha foi inserida esquerda de seu
pai, o bal do pai deve ser incrementado. Se ela foi inserida direita de seu
pai, o bal do pai deve ser decrementado.
Durante uma insero, se o bal de um n tornar-se -1 ou 1 ser preciso propagar a atualizao do bal para o seu n pai. Se esse n estiver
esquerda de seu pai, o bal do pai deve ser incrementado, caso contrrio, o
bal do pai deve ser decrementado. Se o bal de um n tornar-se 0, a insero
finalizada.
Por exemplo, ao inserir a chave 3 na rvore da Figura 4.7 teremos que
incrementar o bal do n que contm a chave 7. Como o bal desse n passar
a ser 1, teremos que atualizar o bal do seu n pai, que contm a chave 15.
O bal do n pai passar a ser 0 e a insero ser finalizada.

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 72

22/04/13 14:53

31
0

15

39

7
0

17

19

34
9

Figura 4.8: rvore da Figura 4.7 aps a insero da chave 3

Existe ainda mais uma possibilidade a tratar. Se o bal de um n tornar-se 2 ou 2, o que inaceitvel, ser necessrio realizar um procedimento nesse n de modo a restaurar o balanceamento da rvore. Tal procedimento chamado de rotao.
Em rvores AVL, existem essencialmente dois tipos de rotao: simples e dupla. Essas rotaes podem ser esquerda ou direita. A figura 4.9
ilustra graficamente a rotao simples esquerda, tambm chamada de
rotao left-left ou simplesmente rotao LL. Nessa figura, B e C so subrvores de altura H e A uma subrvore de altura H + 1. Observe que o n
n1 toma o lugar do n n que ento movido para a direita. A subrvore B
posicionada esquerda do n n.
2

n1
0

C
A

LL

n1

Figura 4.9: Rotao simples esquerda (LL)

A rotao simples direita (right-right ou RR) anloga rotao LL,


conforme mostrado na Figura 4.10.
-2

n1
-1

n1

RR

C
B

Figura 4.10: Rotao simples direita (RR)

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 73

73
22/04/13 14:53

Temos ainda a rotao dupla esquerda, tambm conhecida como


rotao left-right ou LR. Na Figura 4.11 as subrvores A, B e D tm altura
H + 1 e a subrvore C tem altura H. O n n2 toma o lugar do n n que ento
movido para a direita. A subrvore B colocada direita do n n1 e a subrvore C colocada esquerda do n n. O nome dessa rotao deve-se ao
fato de que ela equivale a fazer uma rotao simples direita em torno de n2
e depois fazer uma rotao simples esquerda em torno de n.
0

n2

n
-1

n1

n1
1

-1

D
LR

n2
A

A
B

Figura 4.11: Rotao dupla esquerda (LR)

Na rotao LR a subrvore B poderia ter altura H e a subrvore C


poderia ter altura H + 1. A rotao seria feita da mesma forma que foi explicada no pargrafo anterior. Uma nica diferena que ao final da rotao
o bal de n1 seria 1 e o bal de n seria 0. Temos ainda o caso especial em que
as subrvores B e C so vazias (e portanto H igual a 1). Mais uma vez,
nada muda no procedimento de rotao, exceto pelo fato de que ao final da
rotao os ns n1 e n tero bal 0.
A Figura 4.12 ilustra a rotao dupla direita (right-left ou RL) que
anloga rotao LR.
0

-2

n2

n
1

n1

n1

RL

n2
D
B

Figura 4.12: Rotao dupla direita (RL)

Todas essas rotaes podem ser feitas em tempo constante, pois exigem apenas o redirecionamento de uma quantidade limitada de ponteiros

74

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 74

22/04/13 14:53

e a atualizao do bal de no mximo trs ns. Uma anlise cuidadosa das


rotaes nos permite concluir que alm de restaurar o balanceamento, as
rotaes mantm a ordenao existente na rvore.
Note que em todas as rotaes a raiz da subrvore na qual foi feita a
rotao passa a ter bal zero. Isso significa que numa operao de insero
ser feita no mximo uma rotao.
Na Figura 4.13 mostramos como ficaria a rvore da Figura 4.8 aps
a insero da chave 16. Note que o bal do n que contm a chave 17 seria
atualizado para 1 e o bal do n que contm o 19 passaria a ser 2. Para restaurar o balanceamento foi necessria uma rotao LL em torno desse n.
1

31
0

15

39

17

34
9

16

19

Figura 4.13: rvore da Figura 4.8 aps a insero da chave 16

Resta-nos discutir a operao de remoo. Infelizmente essa operao


ainda mais complicada que a insero, razo pela qual vamos trat-la
fazendo distino entre dois casos.
Abordaremos primeiro a remoo de uma chave k contida numa folha.
Naturalmente, tal folha deve ser removida. Em seguida, devemos atualizar
o bal dos ancestrais dessa folha. Se a folha estava esquerda de seu pai, o
bal do pai deve ser decrementado. Se ela estava direita, o bal do pai deve
ser incrementado.
Durante uma remoo, se o bal de um n tornar-se 0 ser preciso propagar a atualizao do bal para o seu n pai. Se esse n estiver esquerda
de seu pai, o bal do pai deve ser decrementado, caso contrrio, o bal do pai
deve ser incrementado. Se o bal de um n tornar-se -1 ou 1, a remoo finalizada. Se o bal de um n tornar-se 2 ou 2, ser necessrio realizar uma
das quatro rotaes explicadas anteriormente.
Convm salientar que possvel que o bal de um n seja atualizado
para 2 e o bal de seu filho esquerdo seja 0. Nesse caso, podemos fazer uma
rotao simples ou dupla esquerda. Analogamente, possvel que o bal
de um n torne-se -2 e o bal de seu filho direito seja 0. Teremos a opo de
fazer uma rotao simples ou dupla direita. Em geral escolhemos fazer a
rotao simples.
Note que em todas as rotaes a raiz da subrvore na qual foi feita a
rotao passa a ter bal zero. Isso significa que na remoo, aps uma rotao ser preciso propagar a atualizao do bal para os seus ancestrais. Isso
pode levar necessidade de mltiplas rotaes.
A Figura 4.14 mostra como ficaria a rvore da Figura 4.13 aps a remoo da chave 34. Como essa chave estava esquerda de seu pai, teremos
que decrementar o bal de seu pai passar a ser 0. Em seguida, teremos que
atualizar o bal da raiz, que passa a ser 2. Teremos ento que fazer uma roPESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 75

75
22/04/13 14:53

tao esquerda, que pode ser simples ou dupla, visto que o filho esquerdo
da raiz tem bal 0. Optamos por fazer uma rotao LR para que possamos
fazer uma remoo mais interessante em seguida.
0

17
1

15

31

16

19

39

Figura 4.14: rvore da Figura 4.13 aps a remoo da chave 34


Se o n que contm k
no tiver filho esquerdo,
devido propriedade do
balanceamento, seu filho
direito ser folha. Ele deve
ento tomar o lugar do n
que contm k.

Vamos agora analisar a remoo de uma chave k contida em um n


interno. Nesse caso, devemos substituir k por sua chave antecessora, que
a maior chave da subrvore esquerda de k. Encontramos tal chave percorrendo a subrvore esquerda de k sempre para a direita at atingir um
n que no tenho filho direito.
Se o n que contm a chave antecessora for uma folha, recamos no
caso que tratamos anteriormente, pois teremos que remover a chave antecessora. Se a chave antecessora no estiver numa folha, devemos substitu-la por seu filho esquerdo, que necessariamente ser folha, visto que a chave antecessora no pode ter filho direita. Como o filho esquerdo da chave
antecessora uma folha, recamos novamente no caso de remover uma
folha e devemos proceder como explicado anteriormente.
Na Figura 4.15 mostramos como ficaria a rvore da Figura 4.14 aps a
remoo da chave 17. Observe que essa chave deve ser substituda por sua
chave antecessora, que o 16. Ao remover a folha que contm o 16, precisamos incrementar o bal de seu pai, que passar a ser 2. Precisaremos de
uma rotao LL em torno do n que contm o 15. Aps essa rotao, teremos que decrementar o bal da raiz.
0

16
0

31

15

19

39

Figura 4.15: rvore da Figura 4.14 aps a remoo da chave 17

Vamos agora analisar a complexidade das operaes de busca, insero e remoo em rvores AVL. No pior caso da operao de busca, preciso
percorrer a rvore a partir da raiz at atingir uma folha que esteja no ltimo
nvel. Na insero e na remoo pode ser necessrio percorrer a rvore desde a raiz at atingir o ltimo nvel e ento subir na rvore atualizando o bal
dos ancestrais do n que foi inserido ou removido e, eventualmente, fazendo
rotaes. Torna-se claro, portanto, que essas operaes gastam tempo limi-

76

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 76

22/04/13 14:53

tado pela altura da rvore. O seguinte teorema relaciona a altura de uma


rvore AVL com a quantidade de chaves contidas na rvore.
Teorema AVL: Seja H a altura de uma rvore AVL que contm n chaves. Ento:
log2(n + 1) H 1,44 log2(n + 2) 0,328.
Esse teorema implica que a complexidade das operaes de busca,
insero e remoo em rvores AVL O(logn). So, portanto, estruturas de
pesquisa bastante eficientes.

5.2 rvores B
Nessa e na prxima seo estudaremos as rvores B e as rvores B+.
Tais estruturas so muito utilizadas na prtica devido extrema eficincia
com que so feitas as operaes de busca, insero e remoo. A maioria
dos sistemas gerenciadores de bancos de dados utiliza essas estruturas,
especialmente as rvores B+, para criar arquivos de ndices. Elas tambm
so utilizadas por diversos sistemas de arquivos.
As rvores B foram propostas em 1972 por Rudolf Bayer e Edward
McCreight, pesquisadores da Boeing Research Labs, e constituem uma generalizao das rvores 2-3.
Ao contrrio das rvores AVL, cada n de uma rvore B pode armazenar diversas chaves. Uma caracterstica importante de uma rvore B a
sua ordem. A ordem da rvore determina a quantidade de chaves que um n
pode armazenar e tambm a quantidade de filhos que um n pode ter. Uma
rvore B de ordem m possui as seguintes propriedades:
Cada n da rvore armazena de m a 2m chaves, exceto a raiz, que
armazena de 1 a 2m chaves.
Se um n interno armazena k chaves ento ele tem que ter k + 1 filhos.
Todas as folhas esto contidas no ltimo nvel da rvore.
A subrvore esquerda de uma chave x contm apenas chaves menores do que x e a subrvore direita de x contm apenas chaves
maiores do que x.
Em cada n da rvore as chaves so mantidas em ordem estritamente crescente.
As trs primeiras propriedades garantem o balanceamento da rvore.
De fato, as rvores B so extremamente bem balanceadas. Surpreendentemente, no h necessidade de rotaes para manter o balanceamento. Isso
decorre do fato de que tais rvores crescem para cima, na direo da raiz,
fato incomum entre as rvores.
As outras duas propriedades garantem que as chaves contidas na rvore estejam implicitamente ordenadas. Elas tambm implicam que rvores
B no podem armazenar chaves repetidas.
A estrutura de um n de uma rvore B de ordem m pode ser constituda dos seguintes campos:
c: um vetor de chaves com 2m posies.
p: um vetor de ponteiros com 2m + 1 posies.
numchaves: indica a quantidade de chaves contidas no n.
pai: ponteiro para o n pai.

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 77

77
22/04/13 14:53

Os campos numchaves e pai, embora no sejam imprescindveis, facilitam sobremaneira a implementao de diversas operaes em rvores B.
Em um n da rvore, o ponteiro armazenado em p[i] aponta para a subrvore esquerda da chave armazenada em c[i] e p[i + 1] aponta para a subrvore direita de c[i]. A figura 4.16 mostra como poderia ser a estrutura de
um n de uma rvore B de ordem 2.

pai

numchaves
0

c
p

12
0

19
1

25
2

Figura 4.16: Estrutura de um n de uma rvore B

A Figura 4.17 mostra um exemplo de rvore B de ordem 1.


51
25 33
4 12

29

69 84
37 42

55

78

89 96

Figura 4.17: Exemplo de rvore B

A busca de uma chave em rvores B simples. Para procurar uma


chave k, primeiramente verificamos se a rvore vazia. Em caso afirmativo, a busca para, tendo sido mal sucedida. Caso contrrio, verificamos se k
ocorre na raiz da rvore. Nesse caso, a busca tem sucesso. Caso contrrio,
determinamos a menor chave contida na raiz que maior do que k. Se essa
chave existir, repetimos o procedimento, recursivamente, na subrvore
esquerda dessa chave. Se k for maior do que todas as chaves contidas na
raiz, repetimos o procedimento, recursivamente, na subrvore direita da
maior chave contida na raiz.
Na rvore da Figura 4.17, para buscar a chave 37 teremos que inspecionar a raiz. Como a chave 37 menor do que 51, devemos seguir o
ponteiro para a subrvore esquerda do 51, chegando ao n que contm
as chaves 25 e 33. Como 37 maior do que essas chaves, devemos seguir o
ponteiro para a subrvore esquerda do 33, chegando ao n que contm o
37. Se quisermos procurar a chave 30, comearemos inspecionando a raiz.
Como a chave 30 menor do que 51, seguiremos para o n que contm as
chaves 25 e 33. Como 33 a menor chave desse n que maior do que 30,
devemos seguir o ponteiro para a subrvore esquerda do 33, chegando ao
n que contm o 29. Visto que 30 maior do que 29, devemos seguir o ponteiro para a subrvore direita do 29. Observe que tal subrvore vazia e,
portanto, a busca ser mal sucedida.
Vamos agora explicar como fazer a insero de chaves em rvores B.
Para inserir uma chave k numa rvore B de ordem m devemos percorr-la,

78

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 78

22/04/13 14:53

a partir da raiz, como se estivssemos procurando k. Se a chave k for encontrada, a insero deve ser abortada, pois rvores B no podem ter chaves
repetidas. Caso contrrio, atingiremos uma folha. Se essa folha tiver menos
do que 2m chaves, basta inserir k de modo que as chaves contidas nessa
folha continuem em ordem crescente.
Suponha agora que a folha contenha 2m chaves. Nesse caso, a folha precisar ser subdividida, criando-se uma nova folha. Distribuiremos a
chave k e as chaves contidas nessa folha da seguinte maneira. As m menores chaves continuaro na folha, as m maiores chaves sero movidas para
a nova folha e a chave central (aquela que no est entre as m menores nem
entre as m maiores chaves) deve subir para o n pai. Note que se o n pai
tiver 2m chaves, ele tambm precisar ser subdividido.
Esse processo de subdiviso pode propagar-se at a raiz da rvore. Se
a raiz for subdividida, a chave central ser armazenada numa nova raiz e a
altura da rvore aumentar. A Figura 4.18 mostra como seria a subdiviso
da folha esquerda ao inserir a chave 12.
33

12 33

36

4 25

25

36

Figura 4.18: Subdiviso de uma folha numa rvore B

Na Figura 4.19 exibimos a rvore da Figura 4.17 aps a insero das


chaves 73 e 45, nessa ordem. Note que a chave 73 deve ser inserida na folha que contm o 78. J a chave 45 deve ser inserida na folha que contm
as chaves 37 e 42. Como essa folha est cheia (armazena 2m chaves) ela
precisar ser subdividida. A chave 42 (chave central) dever ser movida
para o n pai. Como o n pai tambm est cheio, ele tambm precisar ser
subdividido. A chave 33 ser movida para a raiz da rvore e a insero ser
finalizada.
33 51
25
4 12

29

42
37

45

69 84
55

73 78
89 96
8
73 78
Figura 4.19: rvore B da Figura 4.17 aps a insero das chaves
73 e 45

Observe que se inserirmos a chave 80 na rvore da Figura 4.19, teremos que subdividir a folha que contm o 73 e o 78, seu n pai, que contm
o 69 e o 84, e a raiz da rvore. Com isso, a rvore passar a ter altura 4.
Vamos agora a discutir operao de remoo. Para remover uma chave
k de uma rvore B de ordem m precisamos encontrar o n da rvore que
contm k. Vamos tratar primeiramente o caso em que tal n uma folha. Se
essa folha tiver mais do que m chaves ou for a raiz da rvore, basta remover
k apropriadamente dessa folha.
Suponha agora que a folha que contm k no a raiz da rvore e armazena exatamente m chaves. Aps remover k dessa folha, devemos tentar
obter mais uma chave para essa folha de modo que ele continue armazenando m chaves. Para isso, a folha irm esquerda (preferencialmente) ou

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 79

79
22/04/13 14:53

a folha irm direita deve doar uma chave. Essa chave movida para o n
pai e a chave do n pai que est entre as folhas envolvidas na doao deve
ser movida para a folha que continha k. A Figura 4.20 ilustra a doao de
uma chave da folha irm esquerda.
25

12

4 12

25

Figura 4.20: Doao de uma chave numa remoo em rvore B

Se nem a folha irm esquerda nem a folha irm direita tiver mais
do que m chaves, ser necessrio fundir a folha que contm k com a folha
irm sua esquerda (preferencialmente) ou com a folha irm sua direita.
A chave do n pai que est entre as folhas que esto se fundindo deve ser
movida para a nova folha que ser obtida com a fuso. A Figura 4.21 ilustra
a fuso de duas folhas.
25 33

33

36

36

4 25

Figura 4.21: Fuso de duas folhas de uma rvore B

Observe que ao fundir duas folhas o n pai dessas folhas perde uma
chave. Se ele no for a raiz e tiver exatamente m chaves ser necessrio obter a doao de uma chave do seu n irmo esquerda (preferencialmente)
ou do seu n irmo direita. Se nenhum desses dois ns irmos puder doar
uma chave, devemos fundir o n pai com o seu n irmo esquerda (preferencialmente) ou com o seu n irmo direita.
Esse processo de subdiviso pode propagar-se at os filhos da raiz da
rvore. Se for necessrio fundir os nicos dois filhos da raiz, a raiz antiga
deixar de existir, o n obtido com a fuso passar a ser a nova raiz e a altura da rvore diminuir.
Na Figura 4.22 exibimos a rvore da Figura 4.19 aps a remoo das
chaves 4 e 55, nessa ordem. Note que a folha que contm a chave 4 tem
mais do que m chaves e, portanto, basta remover tal chave dessa folha. J
a remoo da chave 55 leva necessidade de obter a doao de uma chave
da folha irm sua direita.
33 51
25
4

29

42
37

73 84
69

69
78
89 96
55
38
Figura 4.22: rvore B da Figura 4.19 aps a remoo das chaves 4 e 5573 78
45

Ao removermos a chave 45 da rvore da Figura 4.22 teremos que fundir a folha que contm tal chave com folha irm esquerda. O n pai das
folhas que sero fundidas precisar obter uma doao do n irmo direita. A rvore resultante mostrada na Figura 4.23.

80

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 80

22/04/13 14:53

33 73
25
4

51

29

37 42

84
69

78
89 96
55 da chave38
Figura 4.23: rvore B da Figura 4.22 aps a remoo
45
69

Vamos agora tratar o caso em que a chave k, a ser removida, est em


um n interno. Nesse caso, devemos substituir k por sua chave antecessora,
que a maior chave da subrvore esquerda de k. Observe que tal chave
necessariamente estar numa folha e, portanto, recamos no caso de remoo de uma chave. Devemos ento proceder como explicado nos pargrafos
anteriores.
Por exemplo, se quisermos remover a chave 33 da rvore mostrada na
Figura 4.23, teremos que substitu-la pela chave 29, que sua chave antecessora. A folha que continha o 29 ficar vazia e ter que ser fundida com
sua folha irm esquerda e a chave 25 descer para a folha obtida com a
fuso. Precisaremos fazer mais uma fuso envolvendo o n onde estava a
chave 25 e o n que contm o 51. Com isso, a chave 29 que foi para a raiz
dever descer para o n obtido nessa ltima fuso.
73
29 51
33
4 25

37 42

84
69

78

89 96

Figura 4.24: rvore B da Figura 4.23 aps a remoo da chave 33

Deve ter ficado claro que a operao de busca requer que a rvore seja
percorrida a partir da raiz at, no mximo, atingir uma folha. Dessa forma,
tal operao gasta tempo linearmente proporcional altura da rvore, no
pior caso. Na insero e na remoo necessrio percorrer a rvore da raiz
at atingir o ltimo nvel e, eventualmente, subir na rvore realizando subdivises ou fuses. Fica claro, portanto, que essas operaes gastam tempo
limitado pela altura da rvore. O teorema a seguir relaciona a altura de
uma rvore B com a quantidade de chaves contidas na rvore.
Teorema de Bayer-McCreight: Seja H a altura de uma rvore B de
ordem m que contm n chaves. Ento:
log2m(n + 1) H logm+1(n + 1).
Esse teorema implica que a complexidade temporal das operaes de
busca, insero e remoo em rvores B O(logn). Vemos ainda que quanto
maior a ordem da rvore, menor ser sua altura. Na prtica, em comum utilizar ordens bem maiores do que 1, fazendo com que a altura da rvore seja
muito pequena. Por exemplo, se a ordem da rvore B for 50 e ela armazenar
1 bilho de chaves, sua altura ser no mximo 5. So, portanto, estruturas
de pesquisa extremamente eficientes.

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 81

81
22/04/13 14:53

5.3 rvores B+
As rvores B+, tambm propostas por Bayer e McCreight, so bem parecidas com as rvores B, tendo apenas duas diferenas mais significativas:
Todas as chaves vlidas contidas na rvore tm que aparecer em
alguma folha da rvore.
Cada folha possui um ponteiro que aponta para a folha imediatamente sua direita.
Convm salientar que as chaves contidas nos ns internos servem
apenas para orientar o caminhamento na rvore. A primeira diferena
mais importante e requer o relaxamento de uma das propriedades das rvores B, descrita no incio da Subseo 5.2:
A subrvore esquerda de uma chave x contm apenas chaves menores ou iguais a x e a subrvore direita de x contm apenas chaves maiores do que x.
A Figura 4.25 mostra uma rvore B+ de ordem 1 com as mesmas chaves contidas na rvore B da Figura 4.24.
37 73
25
4 25

29 37

42 51

51

84
69

69 73

89 96
73 78

78 84
Figura 4.25: Exemplo de rvore B+ 38

Como numa rvore B+ uma chave s vlida se aparece em alguma


folha, em toda operao de busca devemos percorrer a rvore a partir da
raiz at atingir uma folha. Para procurar uma chave k, primeiramente verificamos se a rvore vazia. Em caso afirmativo, a busca para, tendo sido
mal sucedida. Caso contrrio, verificamos se a raiz da rvore folha. Se
esse for o caso, verificamos se x ocorre na raiz. Se for este o caso, a busca
tem sucesso; caso contrrio, a busca mal sucedida. Se a raiz no for uma
folha, determinamos a menor chave contida na raiz que maior ou igual
a k. Se essa chave existir, repetimos o procedimento, recursivamente, na
subrvore esquerda dessa chave. Se k for maior do que todas as chaves
contidas na raiz, repetimos o procedimento, recursivamente, na subrvore
direita da maior chave contida na raiz.
Para buscar a chave 29 na rvore da Figura 4.25 teremos que inspecionar inicialmente a raiz. Como 29 menor do que 37, devemos seguir o
ponteiro para a subrvore esquerda do 37, chegando ao n que contm a
chave 25. Visto que 29 maior do que 25, devemos seguir o ponteiro para
a subrvore direita do 25, chegando folha contm o 29. Se quisermos
procurar a chave 75, comearemos inspecionando a raiz. Como 75 maior
do que 73, seguiremos para o n que contm a chave 84. Visto que 75 menor do que 84, devemos seguir o ponteiro para a subrvore esquerda do
84, chegando folha que contm o 78 e o 84. Tal folha no contm o 75 e,
portanto, a busca mal sucedida.
A insero em rvores B+ similar insero em rvores B, com apenas uma diferena significativa: ao subdividir uma folha, a chave central
deve ser copiada para o n pai. Dessa maneira, a chave central continua a
ser uma chave vlida, pois ela permanece numa folha. Por exemplo, ao in-

82

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 82

22/04/13 14:53

serir a chave 75 na rvore da Figura 4.25, a folha que contm as chaves 78


e 84 precisar ser subdividida. A chave 78 ser ento copiada para o n pai.
A rvore resultante obtida com essa insero mostrada na Figura 4.26.
37 73
25

51

75 78
84
89 96
55
38
Figura 4.26: rvore B+ da Figura 4.25 aps a insero da chave 7573 78

4 25

29 37

42 51

78 84
69

69 73

A remoo em rvores B+ tambm similar remoo em rvores B,


com apenas duas diferenas mais significativas. Uma delas est na forma
com feita a doao de uma chave contida numa folha.
Por exemplo, ao fazer a doao de uma chave da folha irm esquerda, a segunda maior chave da folha que est doando copiada para o n pai
e ocupa o lugar da chave que estava entre as folhas envolvidas na doao. A
maior chave da folha que est doando ento movida para a folha que est
recebendo a doao. A Figura 4.27 ilustra essa diferena. Note que a chave
75 foi copiada para o n pai e o 78 foi movido para a folha que antes continha o 84. Observe que o 84 ainda aparece na rvore, mas no numa folha.
Dessa forma, o 84 no mais uma chave vlida da rvore.
37 73
25

51

75 84
69

29 37
42 51
75
4 25
69 73
78
89 96
33
55
9 Figura 4.27: rvore B+ da Figura 4.26 aps a remoo da
38chave 8473 78

A outra diferena ocorre na fuso de duas folhas. Nesse caso, a chave


do n pai que est entre elas simplesmente eliminada. Observe na Figura
4.28 como fica a rvore da Figura 4.27 aps a remoo da chave 75.
37 73
25
4 25

29 37

51
42 51

84
69

69 73

78
89 96
38
73 75
78
Figura 4.28: rvore B+ da Figura 4.27 aps a remoo da chave

possvel mostrar que uma rvore B+ que contenha as mesmas chaves vlidas que uma rvore B ter no mximo um nvel a mais do que a
rvore B. Sendo assim, pelo Teorema de Bayer-McCreight, conclumos que
a altura de uma rvore B+ logartmica na quantidade de chaves contidas
na rvore.
Claramente, as operaes de busca, insero e remoo em rvores
B+ gastam tempo linearmente proporcional altura da rvore. Sendo assim, tais operaes so feitas em tempo (logn). Assim como as rvores B,
as rvores B+ tambm so estruturas de pesquisa extremamente eficientes.
PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 83

83
22/04/13 14:53

1. Escreva uma verso no recursiva do algoritmo de busca binria.


2. Escreva uma funo que receba um vetor em ordem crescente e um valor
x e devolva o ndice da posio do vetor cujo contedo mais prximo de
x. Sua funo dever requerer tempo logartmico no tamanho do vetor
(sugesto: adapte o algoritmo de busca binria).
3. Mostre como ficaria uma tabela de hashing fechado com 13 posies,
aps a insero das chaves 46, 8, 74, 15, 23, 51, 83, 69, 9, 24, 33 e 12,
nesta ordem (nessa e na prxima questo, os valores associados s chaves devem ser ignorados). Utilize a seguinte funo de hashing: h(x) = x
mod 13. Em seguida, remova as chaves 46, 8 e 74, nesta ordem, e mostre
como ficaria a tabela.
4. Mostre como ficaria uma tabela de hashing aberto com 7 posies, aps
a insero das chaves 46, 8, 74, 15, 23, 51, 83, 69, 9, 24, 33 e 12, nesta
ordem. Utilize a seguinte funo de hashing: h(x) = x mod 7. Em seguida, remova as chaves 15, 23 e 51, nesta ordem, e mostre como ficaria a
tabela.
5. Explique o que a carga de uma tabela de hashing e diga quando ela
considerada baixa. Explique tambm o que uma boa funo de
hashing.
6. Escreva um algoritmo que receba uma tabela de hashing fechado (passada por referncia) e uma chave k e ento insira essa chave na tabela,
se ela ainda no existir na tabela.
7. Insira as chaves 46, 8, 74, 15, 23, 51, 83, 69, 9, 24, 33 e 12, nessa ordem, numa rvore AVL. Em seguida, remova as chaves 83, 69 e 9, nessa
ordem. Aps cada insero ou remoo desenhe como ficou a rvore,
incluindo o bal de cada n. Mencione tambm as rotaes utilizadas nas
inseres e remoes.
8. Escreva um algoritmo que receba um ponteiro para a raiz de uma rvore
AVL e imprima o contedo dos ns da rvore em ordem decrescente.
9. Escreva uma funo que receba um ponteiro para a raiz de uma rvore
AVL e devolva a altura da rvore. Sua funo dever requerer tempo logartmico no tamanho da rvore.
10. Escreva um algoritmo que receba um ponteiro para a um n de uma
rvore AVL e realize uma rotao simples direita em torno desse n.
11. Mostre como ficaria uma rvore B de ordem 1 aps a insero das chaves 46, 8, 74, 15, 23, 51, 83, 69, 9, 24, 33 e 12, nesta ordem. Em seguida, remova as chaves 24, 33, e 12, nessa ordem, e mostre como ficaria
a rvore.
12. Mostre como ficaria uma rvore B+ de ordem 1 aps a insero das
chaves 46, 8, 74, 15, 23, 51, 83, 69, 9, 24, 33 e 12, nesta ordem. Em seguida, remova as chaves 46, 8 e 74, nessa ordem, e mostre como ficaria
a rvore.

84

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 84

22/04/13 14:53

13. Escreva uma funo que receba um ponteiro para a raiz de uma rvore
B+ e devolva a quantidade de chaves contidas na rvore.
14. Discorra sobre a eficincia das operaes de insero, remoo, busca,
busca aproximada e listagem em ordem em rvores B e B+.

Sites
http://pt.wikipedia.org/wiki/Bubble_sort
http://pt.wikipedia.org/wiki/Insertion_sort
http://pt.wikipedia.org/wiki/Selection_sort
http://pt.wikipedia.org/wiki/Shell_sort
http://pt.wikipedia.org/wiki/Merge_sort
http://pt.wikipedia.org/wiki/Quick_sort
http://pt.wikipedia.org/wiki/Heapsort
http://pt.wikipedia.org/wiki/Count_sort
http://pt.wikipedia.org/wiki/Bucket_sort
http://pt.wikipedia.org/wiki/Radix_sort
http://pt.wikipedia.org/wiki/Busca_binria
http://pt.wikipedia.org/wiki/Tabela_de_disperso
http://pt.wikipedia.org/wiki/rvore_AVL
http://pt.wikipedia.org/wiki/rvore_B
http://pt.wikipedia.org/wiki/rvore_B+
http://pt.wikipedia.prg/wiki/Sort-merge_utility
http://www.cs.pitt.edu/~kirk/cs1501/animations/Sort1.html
http://slady.net/java/bt/view.php?w=750&h=500

Ascencio A.F.G., Aplicaes de Estrutura de Dados em Delphi. So Paulo:


Pearson Prentice Hall, 2005.
Cormen. T.H., C.E. Leiserson, R.L. Rivest, and C. Stein, Algoritmos: Teoria e Prtica. Rio de Janeiro: Editora Campus, 2002.
Feofiloff, P. Algoritmos em Linguagem C. Elsevier, 2008.
Horowitz. E. and S. Sahni. Fundamentos de Estrutura de Dados. Rio de
Janeiro: Editora Campus, 1987.
Tenenbaum, A.M., Y. Langsam and M.J. Augenstein. Estrutura de Dados
usando C. So Paulo: Pearson Makron Books, 1996.
Ziviani, N. Projeto de Algoritmos. 2.ed., So Paulo: Thomson, 2004.
________. Projeto de Algoritmos com Implementaes em Java e C++.
Cengage Learning, 2006.
PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 85

85
22/04/13 14:53

Gerardo Valdisio Rodrigues Viana


Possui Graduao em Engenharia Mecnica pela UFC - Universidade
Federal do Cear, Licenciatura em Matemtica pela UECE - Universidade
Estadual do Cear, Especializao, Mestrado e Doutorado em Cincia da
Computao pela UFC com perodo no IME/USP - Instituto de Matemtica
e Estatstica da Universidade de So Paulo. Aposentou-se como Professor
Associado da UFC em Agosto de 2010. Atualmente Professor Adjunto da
UECE. Nos ltimos anos publicou 11 artigos em peridicos especializados
e 6 trabalhos completos e 7 simples em anais de congressos. Possui 2 livros publicados e participou da elaborao de 1 captulo de livro. Orienta
trabalhos de concluso de curso (monografias de graduao) e dissertaes
de mestrado na rea de computao. Atua nas reas de Matemtica Computacional, Otimizao Combinatria, Anlise de Algoritmos e Bioinformtica. Em suas atividades profissionais interagiu com diversos colaboradores
em co-autorias de trabalhos cientficos. Em seu currculo Lattes os termos
mais freqentes na contextualizao da produo cientfica, tecnolgica e
artstico-cultural so: Otimizao Combinatria, Programao Matemtica, Metaheuristicas, Computao Paralela e Biologia Computacional.

Glauber Ferreira Cintra


Possui graduao em Cincia da Computao pela Universidade Estadual do Cear, mestrado em Matemtica Aplicada pela Universidade de
So Paulo e doutorado em Cincia da Computao pela Universidade de
So Paulo. Atualmente professor do Instituto Federal de Educao, Cincia e Tecnolgia do Cear e professor da Faculdade 7 de Setembro. Tem
experincia na rea de cincia da computao, com nfase em otimizao
combinatria, atuando principalmente nos seguintes temas: problemas de
corte e empacotamento, gerao de colunas, algoritmos de aproximao e
programao matemtica.

Ricardo Holanda Nobre


Possui Graduao em Cincias da Computao pela Universidade Estadual do Cear e em Direito pela Universidade Federal do Cear. Especialista em Direito Empresarial, Mestre em Computao pela Universidade
Estadual do Cear e Doutorando do curso de Engenharia de Teleinformtica da Universidade Federal do Cear. Atua nas reas de Otimizao Combinatria, Anlise de Algoritmos, Computao Paralela e Anlise de Imagens.
Foi Gerente de TIC da Caixa de Assistncia dos Funcionrios do Banco do
Nordeste (CAMED) e Gerente de Desenvolvimento em TIC da Secretaria da
Justia e Cidadania do Estado do Cear, desenvolvendo trabalhos de identificao biomtrica, Business Intelligence, Data Warehouse dentre outros.
Atualmente Professor da Faculdade de Tecnologia do Nordeste, Professor
Colaborador e Pesquisador da Universidade Estadual do Cear e Analista
de Sistemas do SERPRO, no qual desenvolve atividades ligadas a Banco de
Dados e a Data Warehouse.

86

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 86

22/04/13 14:53

Anexo

Relao de Algoritmos









1 - Algoritmo da Bolha - bubble_sort.c


2 - Algoritimo da Insero - insertion_sort.c
3 - Algortmo da Seleo - selection_sort.c
4 - Algoritmo Shellsort - shell_sort.c
5 - Algoritmo Mergesort - merge_sort.c
6 - Algoritmo Quicksort - quick_sort.c
7 - Algoritmo Heapsort - heap_sort.c
8 - Algoritmo Counting - counting_sort.c
9 - Algoritmo Bucketsort - bucket_sort.c
10 - Algoritmo Radixsort - radix_sort.c

Pesq_Ord_de_Dados 87

22/04/13 14:53

Pesq_Ord_de_Dados 88

22/04/13 14:53

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <stdbool.h>
int main() {
int vetor[5], i, aux;
bool parar = false;
for(i=0;i<5;++i)
{
printf("Digite o valor: ");
scanf("%d",&vetor[i]);
}
while(parar == false)
{
parar = true;
for(i=0;i<4;++i)
{
if(vetor[i]>vetor[i+1])
{
parar = false;
aux = vetor[i];
vetor[i] = vetor[i+1];
vetor[i+1] = aux;
}
}
}
for(i=0;i<5;++i)
{
printf("%d\n",vetor[i]);
}
getch();
return 0;
}

1 - Algoritmo da Bolha - bubble_sort.c

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 89

89
22/04/13 14:53

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
void insertionSort(int *V, int tam)
{
int i, j, aux;
for(i = 1; i < tam; i++){
j = i;
while((V[j] < V[j - 1])&&(j!=0)) {
aux = V[j];
V[j] = V[j - 1];
V[j - 1] = aux;
j--;
}
}
}
int main() {
int vet[5], i, aux;
for(i=0;i<5;++i)
{
printf("Digite o valor: ");
scanf("%d",&vet[i]);
}
insertionSort(vet, 5);
for(i=0;i<5;++i)
{
printf("%d\n",vet[i]);
}
getch();
}

2 - Algoritimo da Insero - insertion_sort.c

90

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 90

22/04/13 14:53

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
void selectionsort(int * vet, int tam)
{
int i, j, min;
for (i = 0; i < (tam-1); i++)
{
min = i;
for (j = (i+1); j < tam; j++) {
if(vet[j] < vet[min]) {
min = j;
}
}
if (i != min) {
int swap = vet[i];
vet[i] = vet[min];
vet[min] = swap;
}
}
}
int main() {
int vetor[5], i, aux;
for(i=0;i<5;++i)
{
printf("Digite o valor: ");
scanf("%d",&vetor[i]);
}
selectionsort(vetor, 5);
for(i=0;i<5;++i)
{
printf("%d\n",vetor[i]);
}
getch();
}

3 - Algoritmo da Seleo - selection_sort.c

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 91

91
22/04/13 14:53

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
void shellsort(int * vet, int size) {
int i , j , value;
int gap = 1;

do {
gap = 3*gap+1;
} while(gap < size);

do {

gap /= 3;

for(i = gap; i < size; i++) {

value =vet[i];

j = i - gap;

while (j >= 0 && value < vet[j]) {

vet [j + gap] =vet[j];

j -= gap;

vet [j + gap] = value;

} while ( gap > 1);


}

int main() {
int vetor[5], i, aux;
for(i=0;i<5;++i)
{
printf("Digite o valor: ");
scanf("%d",&vetor[i]);
}
shellsort(vetor, 5);
for(i=0;i<5;++i)
{
printf("%d\n",vetor[i]);
}
getch();
}

4 - Algoritmo Shellsort - shell_sort.c

92

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 92

22/04/13 14:53

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
void merge(int vec[], int vecSize) {
int mid;
int i, j, k;
int* tmp;
tmp = (int*) malloc(vecSize * sizeof(int));
if (tmp == NULL) {
exit(1);
}
mid = vecSize / 2;
i = 0;
j = mid;
k = 0;
while (i < mid && j < vecSize) {
if (vec[i] < vec[j]) {
tmp[k] = vec[i];
++i;
}
else {
tmp[k] = vec[j];
++j;
}
++k;
}
if (i == mid) {
while (j < vecSize) {
tmp[k] = vec[j];
++j;
++k;
}
}
else {
while (i < mid) {
tmp[k] = vec[i];
++i;
++k;
}
}

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 93

93
22/04/13 14:53

for (i = 0; i < vecSize; ++i) {


vec[i] = tmp[i];
}
free(tmp);
}
void mergeSort(int vec[], int vecSize) {
int mid;
if (vecSize > 1) {
mid = vecSize / 2;
mergeSort(vec, mid);
mergeSort(vec + mid, vecSize - mid);
merge(vec, vecSize);
}
}
int main() {
int vec[5], i, aux;
for(i=0;i<5;++i)
{
printf("Digite o valor: ");
scanf("%d",&vec[i]);
}
mergeSort(vec, 5);
for(i=0;i<5;++i)
{
printf("%d\n",vec[i]);
}
getch();
}

5 - Algoritmo Mergesort - merge_sort.c

94

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 94

22/04/13 14:53

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
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;
}
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);
}
}
int main() {
int vec[5], i, aux;
for(i=0;i<5;++i)
{
printf("Digite o valor: ");
scanf("%d",&vec[i]);
}
quickSort(vec, 0, 5);
for(i=0;i<5;++i)
{
printf("%d\n",vec[i]);
}
getch();
}

6 - Algoritmo Quicksort - quick_sort.c

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 95

95
22/04/13 14:53

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>

void heapsort(int vec[], int n)


{
int i = n/2, pai, filho;
int t;

for (;;)
{
if (i > 0)
{
i--;
t = vec[i];
}
else
{
n--;
if (n == 0)
return;
t = vec[n];
vec[n] = vec[0];
}

pai = i;
filho = i*2 + 1;

while (filho < n)


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

96

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 96

22/04/13 14:53

}
}

int main() {
int vec[5], i, aux;

for(i=0;i<5;++i)
{
printf("Digite o valor: ");
scanf("%d",&vec[i]);
}

heapsort(vec, 5);

for(i=0;i<5;++i)
{
printf("%d\n",vec[i]);
}
getch();
}

7 - Algoritmo Heapsort - heap_sort.c

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 97

97
22/04/13 14:53

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
void countingsort(int *vet, int n, int min, int max)
{
int i, j, z;
int range = max - min + 1;
int *count = malloc(range * sizeof(*vet));

for(i = 0; i < range; i++)

count[i] = 0;


for(i = 0; i < n; i++)

count[ vet[i] - min ]++;


for(i = min, z = 0; i <= max; i++)
{

for(j = 0; j < count[i - min]; j++)

vet[z++] = i;

}
free(count);
}

int main() {
int vet[5], i, maior;
for(i=0;i<5;++i)
{
printf("Digite o valor: ");
scanf("%d",&vet[i]);
}
printf("Qual o maior elemento: ");
scanf("%d",&maior);
countingsort(vet, 5, 0, maior );
for(i=0;i<5;++i)
{
printf("%d\n",vet[i]);
}
getch();
}

8 - Algoritmo Counting - counting_sort.c

98

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 98

22/04/13 14:53

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#define n 5
#define num_bucket 3

typedef struct {
int topo;
int balde[n];
} bucket;

void bubble(int *vet,int tam){


int i,j,temp,flag;
if(tam){
for(j=0;j<tam-1;j++){
flag=0;
for(i=0;i<tam-1;i++){
if(vet[i+1]<vet[i]){
temp=vet[i];
vet[i]=vet[i+1];
vet[i+1]=temp;
flag=1;
}
}
if(!flag)
break;
}
}
}

void bucketsort(int *vet, int tam){


bucket b[num_bucket];
int i,j,k;
for(i=0;i<num_bucket;i++)
b[i].topo=0;

for(i=0;i<tam;i++){
j=(num_bucket)-1;
while(1){
if(j<0)
break;
if(vet[i]>=j*10){

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 99

99
22/04/13 14:53

b[j].balde[b[j].topo]=vet[i];
(b[j].topo)++;
break;
}
j--;
}
}

for(i=0;i<num_bucket;i++)
if(b[i].topo)
bubble(b[i].balde,b[i].topo);

i=0;
for(j=0;j<num_bucket;j++){
for(k=0;k<b[j].topo;k++){
vet[i]=b[j].balde[k];
i++;
}
}
}

int main() {
int vet[n], i, maior;

for(i=0;i<n;++i)
{

printf("Digite o valor: ");

scanf("%d",&vet[i]);

bucketsort(vet, n);

for(i=0;i<n;++i)
{

printf("%d\n",vet[i]);
}

getch();
}

9 - Algoritmo Bucketsort - bucket_sort.c

100

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 100

22/04/13 14:53

#include <limits.h>
#include <stdlib.h>
#include <conio.h>

typedef unsigned uint;


#define swap(a, b) { tmp = a; a = b; b = tmp; }

/* sort unsigned ints */


static void rad_sort_u(uint *from, uint *to, uint bit)
{
if (!bit || to < from + 1) return;

uint *ll = from, *rr = to - 1, tmp;


while (1) {

/* find left most with bit, and right most without bit, swap */

while (ll < rr && !(*ll & bit)) ll++;

while (ll < rr &&

if (ll >= rr) break;

swap(*ll, *rr);

(*rr & bit)) rr--;

if (!(bit & *ll) && ll < to) ll++;


bit >>= 1;

rad_sort_u(from, ll, bit);


rad_sort_u(ll, to, bit);
}

/* sort signed ints: flip highest bit, sort as unsigned, flip back */
static void radix_sort(int *a, const size_t len)
{
size_t i;
uint *x = (uint*) a;

for(i=0;i<len;++i)

x[i] ^= INT_MIN;


rad_sort_u(x, x + len, INT_MIN);

for(i=0;i<5;++i)
x[i] ^= INT_MIN;
}

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 101

101
22/04/13 14:53

static inline void radix_sort_unsigned(uint *a, const size_t len)


{
rad_sort_u(a, a + len, (uint)INT_MIN);
}

int main(void)
{
int vet[5], i;
for(i=0;i<5;++i)
{
printf("Digite o valor: ");
scanf("%d",&vet[i]);
}

radix_sort(vet, 5);

for(i=0;i<5;++i)
{

printf("%d\n", vet[i]);
}

getch();

return 0;
}

10 - Algoritmo Radixsort - radix_sort.c

102

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 102

22/04/13 14:53

Lista de Algoritmos
Captulo 1
Algoritmo 1.1: Calcula o fatorial de N de forma direta...................... 13
Algoritmo 1.2: Calcula o fatorial de N de forma recursiva................. 14
Algoritmo 1.3: Calcula o Binmio de Newton.................................... 16
Captulo 2
Algoritmo 2.1: Bolha.......................................................................... 21
Algoritmo 2.2: Bolha com Flag........................................................... 23
Algoritmo 2.3: Insero...................................................................... 24
Algoritmo 2.4: Seleo....................................................................... 25
Algoritmo 2.5: Shellsort..................................................................... 27
Algoritmo 2.6: Mergesort.................................................................. 28
Algoritmo 2.7: Procedimento Merge................................................. 30
Algoritmo 2.8: Procedimento Partio............................................... 32
Algoritmo 2.9: Quicksort.................................................................... 34
Algoritmo 2.10: Insere_HBC............................................................... 36
Algoritmo 2.11: Remove_Menor....................................................... 37
Algoritmo 2.12: Heapsort................................................................... 38
Algoritmo 2.13: Countingsort............................................................ 39
Algoritmo 2.14: Bucketsort................................................................ 41
Algoritmo 2.15: Radixsort.................................................................. 42
Captulo 3
Algoritmo 3.1: Merge2 Intercalao de dois caminhos................... 51
Algoritmo 3.2: Merge3 Intercalao de trs caminhos................... 52
Captulo 4
Algoritmo 4.1: Busca Sequencial Simples ......................................... 64
Algoritmo 4.2: Busca Sequencial Recursiva........................................ 64
Algoritmo 4.3: Busca Binria.............................................................. 65

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 103

103
22/04/13 14:53

104

PESQUISA E ORDENAO DE DADOS

Pesq_Ord_de_Dados 104

22/04/13 14:53