You are on page 1of 10

Notas de Aula de o de Computadores Algoritmos e Programac a

F L AVIO K EIDI M IYAZAWA com a colaborac a o de T OMASZ KOWALTOWSKI

Instituto de Computac a o - UNICAMP

Vers ao 2000.1

Estas notas de aula n ao devem ser usadas como u nica fonte de estudo. O aluno deve ler outros livros dispon veis na literatura. Nenhuma parte destas notas pode ser reproduzida, qualquer que seja a forma ou o meio, sem a permiss ao dos autores. Os autores concedem a permiss ao expl cita para a utilizac a o e reproduc a o deste material no contexto do ensino de disciplinas regulares dos cursos de graduac a o sob a responsabilidade do Instituto de Computac a o da UNICAMP.

Copyright 2000

Instituto de Computac a o UNICAMP Caixa Postal 6176 13083970 CampinasSP fkm,tomasz @ic.unicamp.br

ii

o 11 Algoritmos de Ordenac a
Nesta sec a o vamos considerar outros algoritmos para ordenac a o: InsertionSort, MergeSort e QuickSort. Apresentaremos os algoritmos MergeSort e QuickSort implementados recursivamente e utilizando uma importante t ecnica chamada Divis ao e Conquista. Estes dois algoritmos est ao entre os algoritmos mais r apidos para ordenac a o usando apenas comparac a o entre elementos. Neste tipo de ordenac a o, o algoritmo QuickSort e o que tem o melhor tempo m edio para se ordenar seq ue ncias em geral.

11.1

Algoritmo InsertionSort

O algoritmo InsertionSort tamb em usa a t ecnica de projeto de algoritmo por induc a o para resolver o problema, i.e., supondo saber resolver um problema pequeno, resolve se um maior.

Considere um vetor . Vamos supor que j a sabemos ordenar o vetor (com elementos, e portanto menor que ). A id eia e ordenar o vetor e depois inserir o elemento na posic a o correta (da o nome InsertionSort). Primeiramente apresentamos um algoritmo recursivo que implementa esta id eia. procedure InsertionSortRecursivo(var v : TipoVetorReal;n:integer); var i : integer; aux : real; begin if n 1 then begin InsertionSortRecursivo(v,n 1); Ordena os n 1 primeiros elementos aux: v[n]; i: n; while (i 1) and (v[i 1] aux) do begin v[i] : v[i 1]; i: i 1; end; v[i] : aux; end; end; InsertionSortRecursivo

13254

"!#%$ 1

&

"&'()"!#0$ 

2 6

O algoritmo tem uma estrat egia indutiva e ca bem simples implement a-lo de maneira recursiva. Note que a base da recurs ao e para o vetor com no m aximo 1 elemento (nestes caso o vetor j a est a ordenado e portanto o problema para este vetor j a est a resolvido). Uma vez que desenvolvemos a estrat egia, podemos observar que podemos descrev e-lo melhor de forma interativa, uma vez que o algoritmo acima faz uma chamada recursiva no in cio da rotina (veja sec a o 10.4). Assim, uma estrat egia mais eciente, usando duas estruturas de repetic a o, e apresentada a seguir. procedure InsertionSort(var v : TipoVetorReal;n:integer); var i,j : integer; aux : real; begin for i: 2 to n do begin aux: v[i]; j: i; while (j 1) and (v[j 1] aux) do begin v[j] : v[j 1]; j: j 1; end; v[j] : aux; end; end; InsertionSort

2 6

No caso m edio este algoritmo tamb em gasta um tempo computacional quadr atico em relac a o a quantidade de elementos. Por outro lado, se a inst ancia estiver quase ordenada, este algoritmo e bastante r apido.

107

11.2

Algoritmo MergeSort e Projeto por Divis ao e Conquista

O algoritmo MergeSort tamb em usa a estrat egia por induc a o. Al em disso, o algoritmo usa de outra t ecnica bastante importante chamada Divis ao e Conquista. Neste tipo de projeto, temos as seguintes etapas:

7 7

Problema sucientemente pequeno: Resolvido de forma direta. Problema n ao e sucientemente pequeno: Divis ao: O problema e dividido em problemas menores. Conquista: Cada problema menor e resolvido (recursivamente). Combinar: A soluc a o dos problemas menores e combinada de forma a construir a soluc a o do problema.

No algoritmo MergeSort, a etapa de divis ao consiste em dividir o vetor, com elementos, em dois vetores (sube dividido vetores) de mesmo tamanho ou diferindo de no m aximo um elemento. No caso, um vetor em vetores e .

& @BA )CDFE $ & & BG CDFH @ $

389$

Para facilitar, em vez de realmente dividir o vetor em dois outros vetores, usaremos ndices para indicar o in cio e o m de um subvetor no vetor original. Assim, estaremos sempre trabalhando com o mesmo vetor, mas o subvetor a ser ordenado em cada chamada recursiva ser a denido atrav es destes ndices. Caso o vetor tenha no m aximo 1 elemento, o vetor j a est a ordenado e n ao precisamos subdividir em partes menores (base da recurs ao). Uma vez que o vetor (problema) foi dividido em dois subvetores (problemas menores), vamos ordenar (conquistar) cada subvetor (subproblema) recursivamente. o es dos subproblemas e feita intercalando os dois subvetores ordenados em apenas um A combinac a o das soluc vetor. Para isso, usaremos dois ndices para percorrer os dois subvetores e um terceiro para percorrer o vetor que receber a os dois vetores intercalados, vetor resultante. A id eia e comec ar os ndices no in cio dos dois vetores e comparar os dois elementos localizados por estes ndices e atribuir no vetor resultante o menor valor. Em seguida, incrementamos o ndice que tinha o menor valor. Este processo se repete at e que tenhamos intercalado os dois vetores no vetor resultante.

4`deXa

No quadro seguinte apresentamos o procedimento para intercalar os vetores e na gura 36 ilustramos seu comportamento.

IQPSRT9RVURVW9@X3Y(R`Wba e Q I PSX3Y(R`W3c

procedure IntercalaMergeSort(var v : TipoVetorReal; Inicio,Meio,Fim:integer); var i,j,k : integer; v1 [Inicio..Meio], v2 [Meio 1..Fim] begin supondo a declarac a o de Vaux no procedimento principal i: Inicio; j: Meio 1; k: Inicio; while (i Meio) and (j Fim) do begin if (v[i] v[j]) then begin Sempre inserindo o menor em Vaux vaux[k]: v[j]; j: j 1; end else begin vaux[k]: v[i]; i: i 1; end; k: k 1; end; while (i Meio) do begin vaux[k]: v[i]; Inserindo os elementos do primeiro vetor i: i 1; k: k 1; end; while (j Fim) do begin vaux[k]: v[j]; Inserindo os elementos do segundo vetor j: j 1; k: k 1; end; for k: Inicio to Fim do v[k] : vaux[k]; Copiando para o vetor original end; IntercalaMergeSort

fg 6

fh c c

fg fg

c c

c c

A seguir, descrevemos o algoritmo MergeSort.

108

inicio

m+1

fim

V Vaux

1
i k

0
j

6
Configurao Inicial

1
i

2
j

Vaux 0
k

3
i

2
j

Vaux 0

1
k

Preenchimento de Vaux at que um dos vetores tenha sido transferido

3 1 3 1 1 1

7
i

8 3 8 3 3 3

9 4 9 4 4 4

0 5 0
i

2 6

6
j

Vaux 0 V 1

2 7 2 2 2

2 6 6 6

4 7 7 7

5 8 8 8

6
j Transferncia do segundo vetor.

Vaux 0 V 0

5 5
i

9
k

9 9

Vaux 0

Copia do vetor j Vaux[inicio,...,fim] para o vetor V[inicio,...,fim] k

Figura 36: Intercalac a o de dois sub-vetores. procedure MergeSort(var V : TipoVetorReal; n:integer); var Vaux : TipoVetorReal; vetor auxiliar para fazer intercalacoes

2i2i6

Inserir rotina Intercala IntercalaMergeSort

fi2i2p

procedure MergeSortRecursivo(var V : TipoVetorReal; inicio,m:integer); var meio : integer; begin if (m inicio) then begin Se tiver quantidade suciente de elementos meio: (m inicio) div 2; Dividindo o problema MergeSortRecursivo(V,inicio,meio); Conquistando subproblema 1 MergeSortRecursivo(V,meio 1,m); Conquistando subproblema 2 IntercalaMergeSort(V,inicio,meio,m); Combinando subproblemas 1 e 2 end; end; MergeSortRecursivo

begin MergeSortRecursivo(V,1,n); end; MergeSort

Na gura 37 apresentamos uma simulac a o do algoritmo MergeSort para o vetor 7,3,8,1,4,2,6,5 . Denotamos a chamado da rotina MergeSort(V) por M(V), e a rotina IntercalaMergeSort por I( ). Se uma chamada da rotina exige chamadas recursivas, esta e substitu da pelas chamadas , onde e s ao as duas partes de .

q rIs$

)  tu q rI & $v q r I & & $w$

I & I &&

109

M( 7 I( M( 7 I( I( M( 7 I( I( I(M(7) I( I( I( 7 I( I( I( 7 I( I( (3 I( I( (3 I( I( (3 I( I( (3 I( I( (3 I( (1 I( (

, 3 , 3 , 3) ,M(3)) ,M(3) ) , 3) , 7) , 7) , 7) , 7) , 7) , 3 3 2

, 8 , 8 ,M( 8 ,M( 8 ,M( 8 ,M( 8 ,M( 8 ,I(M(8) ,I( 8 ,I( 8 , (1 , 7 , , 7 3

, 1 , 4 , , 1) ,M(4 , , 1)) ,M(4 , , 1)) ,M(4 , , 1)) ,M(4 , , 1) ) ,M(4 , , 1) ) ,M(4 , , M(1))) ,M(4 , , M(1))) ,M(4 , , 1)) ,M(4 , , 8)) ,M(4 , , 8) ,M(4 , , , 8) , (2 4 , 5 , ,

2 , 6 2 , 6 2 , 6 2 , 6 2 , 6 2 , 6 2 , 6 2 , 6 2 , 6 2 , 6 2 , 6 2 , 6 4 6 , , 5 7

, 5) , 5) ) , 5) ) , 5) ) , 5) ) , 5) ) , 5) ) , 5) ) , 5) ) , 5) ) , 5) ) , 5) ) , , 6) ) 8)

(1 , 1 ,

Figura 37: Simulac a o das chamadas recursivas do procedimento MergeSort para o vetor 7,3,8,1,4,2,6,5 .

11.3

Algoritmo QuickSort

O algoritmo QuickSort tamb em usa a t ecnica de divis ao e conquista, dividindo cada problema inicial em duas partes. Neste caso, a etapa de divis ao em dois subproblemas e mais sosticada mas por outro lado a etapa de combinac a o e simples (lembrando que no algoritmo MergeSort, dividir e simples enquanto combinar e mais sosticado). Para dividir um vetor de um pivo tal que

@%$ em dois subvetores x&'x& xy & $ e "& &'"& & x& & $ , o algoritmo usa & , w4V e f & & , 4@ . ao ordenados recursivamente (conquistados). Uma vez que o vetor foi dividido nos subvetores & e & & , estes s Por m, os vetores s ao combinados, que nada mais e que a concatenac a o dos vetores ordenados x& e "& & .

"%$ . Primeiro escolhemos um pivo . Uma das vantagens de se escolher este pivo do pr oprio vetor a ser ordenado e que podemos implementar a estrat egia garantindo sempre que cada subvetor e estritamente menor que o vetor original. O que faremos e tomar o pivo e dividir o vetor em subvetores x& e "& & de tal maneira que a ordenac a o nal se torne o vetor &ed $ d & & , onde o operador d e a concatenac a o de vetores.
Antes de apresentar o algoritmo de particionamento em um vetor, vamos apresent a-lo usando um vetor auxiliar. A implementac a o e mais simples e ca mais f acil de se entender a id eia do programa. Primeiro a rotina escolhe um pivo ). Troca com o primeiro elemento ( ). Em seguida percorre-se todos (posic a o os demais elementos e insere os elementos menores ou iguais ao pivo, lado a lado, no in cio do vetor auxiliar. Os elementos maiores que o pivo s ao inseridos lado a lado a partir do m do vetor auxiliar. Por m, o pivo e inserido na posic a o intermedi aria e o vetor auxiliar e copiado para o vetor auxiliar.

A etapa mais complicada neste algoritmo e a etapa de divis ao, que pode ser feita ecientemente no mesmo vetor

rfgTihjkRlWsm o n RpT'RVURVWqcrdeXs$tuv IQPSRpT9R`UR`Wgcxwyz dvXa

IsPSRpT9R`UR`Wa

110

function ParticionaQuickSort(var v : TipoVetorReal;inicio,m:integer):integer; var esq,dir,IndicePivo:integer; Pivo:real; Supondo a declarac a a o de Vaux (vetor auxiliar p/ partic o) no procedimento principal begin troca(v[inicio],v[(inicio m) div 2]); escolha de um pivo Pivo : v[Inicio]; Pivo ca na posic a o Inicio esq: Inicio; dir: Fim; for i: Inicio 1 to m do begin if (V[i] Pivo) then begin Vaux[dir] : V[i]; dec(dir); end else begin inc(esq); Vaux[esq] : V[i]; end; end; V[esq] : Pivo; esq dir for i: Inicio to m do V[i] : Vaux[i]; Copia Vaux[inicio..m] para V[inicio..m] ParticionaQuickSort : esq; end; No quadro seguinte mostramos comportamento deste algoritmo.

inicio

Pivo

fim

V Vaux

8 12 7 13 9 10 2 15 9 17 7
Configurao Inicial esq Pivo i dir

V 10 12 7 13 9 Vaux
esq Pivo

2 15 9 17 7

Colocando o pivo na primeira posio

dir i

V 10 12 7 13 9 Vaux
esq Pivo

2 15 9 17 7 12
dir

(12>pivo) copia. 12 no fim do vetor auxiliar.

V 10 12 7 13 9 Vaux 7
esq Pivo i

2 15 9 17 7 12
dir

(7<pivo) copia 7 no inicio do vetor auxiliar

V 10 12 7 13 9 Vaux 7
esq Pivo

2 15 9 17 7 13 12
dir

(13>pivo) copia 13 no fim do vetor auxiliar.

V 10 12 7 13 9 Vaux 7
Pivo

8 7

2 15 9 17 7 17 15 13 12
esq=dir i

V 10 12 7 13 9 Vaux 7 9 8 2 9

2 15 9 17 7

7 10 17 15 13 12
esq=dir Pivo

Copia pivo na posio intermediria. i Copia vetor auxiliar para o vetor original.

9 9

8 8

2 2

9 9

7 10 17 15 13 12 7 10 17 15 13 12
esq=dir

Vaux 7

111

Agora vamos descrever o procedimento para particionar um vetor, atrav es de um pivo e sem uso de vetor auxiliar. Primeiramente colocaremos o pivo na primeira posic a o do vetor. Para obter os subvetores e , usaremos de dois ndices no vetor original, esq e dir. Inicialmente esq comec a no segundo elemento do vetor (logo depois do pivo) e dir comec a no u ltimo elemento do vetor. Em seguida, fazemos o ndice esq andar para a direita enquanto o ndice apontar para um elemento menor ou igual ao pivo. Fazemos o mesmo com o ndice dir, andando-o para a esquerda enquanto o elemento apontado por ele for maior que o pivo. Isto far a com que o ndice esq v a pulando todos os elendice dir pula todos os elementos que v ao pertencer ao vetor . Quando os mentos que v ao pertencer ao vetor e o dois ndices pararem, estes v ao estar parados em elementos que n ao s ao os pertencentes aos correspondentes vetores e neste caso, trocamos os dois elementos e continuamos o processo. Para manter a separac a o entre e vi avel, vamos fazer este processo sempre enquanto . Quando todo este processo terminar (i.e., quando ), iremos inserir o Pivo (que estava na primeira posic a o) separando os dois vetores. O algoritmo QuickSort est a descrito na p agina 112. Existem outras implementac o es do algoritmo QuickSort que s ao mais ecientes que a vers ao que apresentamos, embora s ao tamb em um pouco mais complicadas. function ParticionaQuickSort(var v : TipoVetorReal;inicio,m:integer):integer; var esq,dir,IndicePivo : integer; Pivo : real; begin troca(v[inicio],v[(inicio m) div 2]); escolha de um pivo Pivo : v[Inicio]; Pivo ca na posic a o Inicio esq: Inicio 1; primeiro elemento mais a esquerda, pulando o pivo dir: Fim; primeiro elemento mais a direita while (esq dir) do begin Pivo) do inc(esq); while (esq dir) and (v[esq] v[dir]) do dec(dir); while (esq dir) and (pivo if esq dir then begin troca(V[esq],V[dir]); inc(esq); dec(dir); end; esq, e esq dir 1 end; dir if v[dir] Pivo then IndicePivo : dir dir esq 1 ou dir esq else IndicePivo : dir 1; esq dir troca(v[IndicePivo],v[Inicio]); Coloca o pivo separando os dois subvetores ParticionaQuickSort : IndicePivo; end;

& &&

&

Y0|}fhRp~

&& & && Y(|(}3hR~

c f f

fh

fh

fh

2 2

Sfh

A seguir, apresentamos a descric a o do algoritmo QuickSort. procedure QuickSort(var V : TipoVetorReal; n:integer); Declarar Vaux e inserir rotina Intercala ParticionaQuickSort procedure QuickSortRecursivo(var V :TipoVetorReal; inicio,m:integer); var IndicePivo : integer; begin if (m inicio) then begin se tem pelo menos 2 elementos IndicePivo : ParticionaQuickSort(v,Inicio,Fim); Dividindo o problema QuickSortRecursivo(V,Inicio,IndicePivo 1); Conquistando subproblema 1 QuickSortRecursivo(V,IndicePivo 1,Fim); Conquistando subproblema 2 end; N ao e preciso fazer nada para combinar os dois subproblemas end; begin QuickSortRecursivo(V,1,n); end;

2i2i6

fi2i2p

112

11.4

Exerc cios

1. Fac a uma rotina recursiva para ordenar um vetor usando a estrat egia do algoritmo SelectionSort. 2. Fac a um algoritmo para ordenar um vetor usando uma estrat egia parecida com a usada pelo algoritmo MergeSort s o que em vez de dividir em duas partes, divide em tr es partes. (I.e., se o vetor for sucientemente pequeno, ordena-se de forma direta. Caso contr ario este algoritmo divide o vetor em 3 partes iguais (ou diferindo de no m aximo um elemento). Ordena recursivamente cada um dos tr es subvetores e por m o algoritmo intercala os tr es vetores, obtendo o vetor ordenado.) elementos consecutivos de um vetor do ndice ao ndice . Projete um procedimento recur3. Seja sivo com o cabec alho procedure minmax(var v: TipoVetorReal; i,f: integer; var minimo, maximo: real); que retorna em minimo e maximo o menor e o maior valor que aparecem no vetor dos ndices ao ndice , respectivamente. O procedimento deve dividir o vetor em dois subvetores de tamanhos quase iguais (diferindo de no m aximo 1 elemento). 4. (K- esimo) O problema do - esimo consiste em, dado um vetor com elementos, encontrar o - esimo menor elemento do vetor. Note que se o vetor j a estiver ordenado, podemos resolver este problema obtendo o elemento a um algoritmo que usa a ordenac a o para resolver o problema do que est a na posic a o do vetor. Isto nos d - esimo. Entretanto, e poss vel se resolver este problema de maneira mais eciente, no caso m edio. A id eia e combinar duas estrat egias:

@bx$

(a) Estrat egia da busca bin aria, de descartar uma parte do vetor. (b) Estrat egia do algoritmo ParticionaQuickSort, que divide o vetor em tr es partes, onde cont em os elementos menores ou iguais a e cont em os elementos maiores que

I &

I &&

Use estas duas estrat egias para desenvolver uma func a o que dado , e , devolve o - esimo menor elemento do vetor. 5. Fac a um programa contendo procedimentos com os seguintes cabec alhos:

I 1

IrI& d $ d I& &$ , .

7 7 7 7 7

procedure MergeSort(var v:TipoVetor; :integer); procedure QuickSort(var v:TipoVetor; :integer); procedure SelectionSort(var v:TipoVetor; :integer); procedure InsertionSort(var v:TipoVetor; :integer); procedure aleatorio(var v:TipoVetor; :integer);

onde TipoVetor e um vetor de n umeros: type TipoVetor=array [1..30000] of integer; As rotinas MergeSort, QuickSort, InsertionSort e SelectionSort s ao rotinas para ordenar usando os algoritmos do mesmo nome. A rotina aleatorio coloca no vetor a quantidade de elementos gerados (pseudo) aleatoriamente pela func a o random(MAXINT).

O programa deve ter rotinas auxiliares para leitura e impress ao de vetores. O programa deve ter um menu com opcoes: (a) (b) (c) (d) (e) (f) (g) (h) Ler um vetor com inteiros ( tamb em e lido). Inicialmente Gerar vetor aleat orio com elementos ( e lido). Ordenar por MergeSort. Ordenar por QuickSort. Ordenar por InsertionSort. Ordenar por SelectionSort. Imprimir o vetor. Sair do programa.

1 .

O aluno deve cronometrar os tempos gastos pelas rotinas de ordenac a o para ordenar inteiros (pseudo) aleat orios, onde pode ser (ou o quanto o computador suportar). Caso algum m etodo seja muito lento, ignore sua execuc a o. N ao e necess ario entregar estes tempos.

14))%))%4)))4))b%0ub)b%ubb)9b)b

113

Exerc cios mais elaborados, usando recurs ao


6. (Passeio do Cavalo) Considere um tabuleiro retangular com casas. O cavalo e uma pec a que anda neste tabuleiro, inicialmente em uma posic a o espec ca. O cavalo pode andar duas casas em um dos sentidos, , e uma horizontalmente (verticalmente), e uma casa verticalmente (horizontalmente). Dado um tabuleiro posic a o inicial do cavalo , e , fac a um programa que resolve os seguintes itens:

1p

e"$ 4 1 4

1Q

casas do tabuleiro. (a) Diga se o cavalo consegue fazer um passeio passando por todas as (b) Dado uma posic a o , e , diga se existe um passeio da casa de origem at ea . Em caso positivo, imprima uma seq ue ncia de movimentos que o cavalo precisa fazer para ir de casa para .

e"$

Vi$

Vi$ 4 1 4

1

e$

Vi$

7. (Problema das 8 Rainhas) O problema das 8 rainhas consiste em encontrar uma disposic a o de 8 rainhas em um tabuleiro de xadrez. Uma rainha pode atacar qualquer outra que esteja na mesma linha, coluna ou diagonal do tabuleiro. Portanto o objetivo e dispor as 8 rainhas de maneira que qualquer duas delas n ao se ataquem. Fac a um programa que encontra a soluc a o para este problema, com rainhas em um tabuleiro . 8. (Pentominos) Um Pentomino e uma gura formada juntando 5 quadrados iguais pelos lados. As 12 guras poss veis, exceto por rotac o es, s ao as seguintes:

11

Dado um ret angulo , o objetivo e preencher este ret angulo com os pentominos, sem sobreposic a o entre pentominos e sem que um pentomino ultrapasse a borda do ret angulo. Por exemplo, a gura seguinte mostra um preenchida com pentominos. Al em disso, um pentomino pode ser girado antes de ser encaixado ret angulo no ret angulo.

k34

Fac a um programa recursivo para resolver este problemas, dado um ret angulo

114

You might also like