exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de...

39
Exterm´ ınio de mariposas * assio Naia dos Santos 15 de dezembro de 2011 Sum´ ario 1. Enunciado ...................................................... 1 2. Que tristeza! Querem matar as mariposas! .................................... 3 19. Encontrando o fecho ................................................ 7 21. Comparando com pontos do fecho ........................................ 9 26. M´ ınimo e m´ aximo elemento com a propriedade P ................................ 12 27. A ´ arvore bin´ aria de busca balanceada ...................................... 13 35. ´ Arvore rubro-negra ................................................. 17 37.Inser¸c˜ ao ....................................................... 18 50.Remo¸c˜ ao ...................................................... 22 68.Inicializa¸c˜ ao e incremento do fecho ........................................ 27 77. Algumas coisas que vou deixar aqui por enquanto ................................ 30 81. Gerando a sa´ ıda .................................................. 31 1. Enunciado Entomologistas colocaram armadilhas para determinar o influxo de mariposas de julho em uma dada regi˜ ao do planeta. A inten¸c˜ ao ´ e estudar programas de exterm´ ınio que tenham algum potencial de controlar o aumento na popula¸ ao de mariposas. O estudo requer uma organiza¸ ao das armadilhas em regi˜ os compactas, que ser˜ ao ent˜ ao usadas para testar cada ecnica de exterm´ ınio. Uma regi˜ ao ´ e definida como o pol´ ıgono com o per´ ımetro de menor comprimento que pode circundar todas as armadilhas em uma regi˜ ao. A figura 1 ilustra as armadilhas (representadas por pontos) de uma regi˜ ao, e o pol´ ıgono a elas associado. x y Figura 1: Exemplo correspondente ` a Regi~ ao #3 da entrada de exemplo. . Entrada O arquivo de entrada cont´ em registros de dados para diversas regi˜ oes. A primeira linha de cada registro cont´ em o n´ umero (inteiro) de armadilhas na regi˜ ao. Linhas seguintes cont´ em cada dois n´ umeros reais que s˜ ao as coordenadas x e y de uma armadilha. N˜ ao h´ aduplica¸c˜ ao de dados em um registro (cada armadilha aparece apenas uma vez em um registro). O fim da entrada ´ e indicado por uma regi˜ ao com zero armadilhas. Sa´ ıda A sa´ ıda, para uma regi˜ ao, ´ e representada por ao menos trˆ es linhas. * Problema para UVA Online Judge 1

Upload: others

Post on 25-Mar-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

Extermınio de mariposas∗

Tassio Naia dos Santos

15 de dezembro de 2011

Sumario

1. Enunciado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12. Que tristeza! Querem matar as mariposas! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319. Encontrando o fecho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 721. Comparando com pontos do fecho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 926. Mınimo e maximo elemento com a propriedade P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1227. A arvore binaria de busca balanceada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1335. Arvore rubro-negra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1737. Insercao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1850. Remocao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2268. Inicializacao e incremento do fecho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2777. Algumas coisas que vou deixar aqui por enquanto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3081. Gerando a saıda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

1. Enunciado

Entomologistas colocaram armadilhas para determinar o influxo de mariposas de julho em uma dada regiao doplaneta. A intencao e estudar programas de extermınio que tenham algum potencial de controlar o aumento napopulacao de mariposas.

O estudo requer uma organizacao das armadilhas em regios compactas, que serao entao usadas para testar cadatecnica de extermınio. Uma regiao e definida como o polıgono com o perımetro de menor comprimento que podecircundar todas as armadilhas em uma regiao. A figura 1 ilustra as armadilhas (representadas por pontos) de umaregiao, e o polıgono a elas associado.

x

y

Figura 1: Exemplo correspondente a Regi~ao #3 da entrada de exemplo..

Entrada O arquivo de entrada contem registros de dados para diversas regioes. A primeira linha de cada registrocontem o numero (inteiro) de armadilhas na regiao. Linhas seguintes contem cada dois numeros reais que sao ascoordenadas x e y de uma armadilha. Nao ha duplicacao de dados em um registro (cada armadilha aparece apenasuma vez em um registro). O fim da entrada e indicado por uma regiao com zero armadilhas.Saıda A saıda, para uma regiao, e representada por ao menos tres linhas.

∗Problema para UVA Online Judge

1

Page 2: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

Primeira linha O numero da regiao. O primeiro registro corresponde a Regi~ao #1, o segundo a Regi~ao #2, etc.

Proxima(s) linhas Uma lista dos pontos que aparecem no perımetro de uma regiao. Os pontos devem ser identi-ficados na forma (x, y), arredondados para uma unica casa decimal. O ponto inicial da listagem e irrelevante,mas a lista deve estar orientada em sentido horario, alem de iniciar e terminar com o mesmo ponto. No casode pontos colineares, qualquer ordem que descreva o perımetro de menor comprimento e aceitavel.

Ultima linha O perımetro da regiao, arredondado para duas casas decimais.

Uma linha em branco deve separar a saıda de dois registros consecutivos.

ENTRADA

3

1 2

4 10

5 12.3

6

0 0

1 1

3.1 1.3

3 4.5

6 2.1

2 -3.2

7

1 0.5

5 0

4 1.5

3 -0.2

2.5 -1.5

0 0

2 2

0

SAIDA

Region #1:

(1.0,2.0)-(4.0,10.0)-(5.0,12.3)-(1.0,2.0)

Perimeter length = 22.10

Region #2:

(0.0,0.0)-(3.0,4.5)-(6.0,2.1)-(2.0,-3.2)-(0.0,0.0)

Perimeter length = 19.66

Region #3:

(0.0,0.0)-(2.0,2.0)-(4.0,1.5)-(5.0,0.0)-(2.5,-1.5)-(0.0,0.0)

Perimeter length = 12.52

2

Page 3: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

2. Que tristeza! Querem matar as mariposas!

E usando cientistas da computacao. Onde e que vamos parar?! Ja sei, ja sei. Voce nao esta lendo este documentopara este tipo de coisa. Talvez esteja mesmo avaliando se nao e bom pular alguns paragrafos ate que o autor volteao normal, e discuta as coisas como se deve fazer. Pronto, pronto, o proximo paragrafo e seguro. Parei.

O desafio e encontrar o fecho convexo (doravante simplesmente fecho) de um conjunto de pontos, e fornecer oseu perımetro. Vamos usar hoje um algoritmo incremental para fazer esse servico. Incremental no sentido de que,apos algum pre-processamento, vamos analisar os pontos um a um, guardando o fecho dos pontos ja observados.Naturalmente, ao fim desse processo teremos o fecho convexo do conjunto de pontos todo. Depois e so percorreresse conjunto em sentido horario — vamos precisar fazer isso para imprimir os pontos do fecho, de qualquer modo— calculando o seu perımetro.

Comecamos com uma breve discussao dos predicados geometricos que vamos usar, seguida das estruturas dedados que serao uteis. Por fim, alguns detalhes mais tecnicos do algoritmo, para garantir consumo de tempoesperado O(n lg n).

3. Os pontos do fecho sao pontos extremos, da colecao, em um certo sentido. Ademais, o fecho e um polıgonoconvexo (mora?). Ora, seguindo o esquema geral do algoritmo que esbocamos, e preciso descobrir se cada pontopnovo que analisamos esta dentro ou fora do fecho intermediario que temos em maos. Chamaremos de H o conjuntode pontos ja analisados que pertencem a fronteira do polıgono, por razoes anglofonas1.

Se o ponto pnovo esta dentro do polıgono do fecho, entao podemos passar ao proximo ponto, nao temos nadaa fazer. Caso contrario, ele passa a fazer parte de H, e, com sua insercao, alguns dos pontos que estavam em Hdevem sair dele (lembre-se que H contem apenas os pontos na “fronteira” do fecho).

pbaixo

v2

vuv1

pnovo

Figura 2: Analisando o ponto pnovo — deve ser acrescentado ao fecho?

Na figura 2, H contem, em sentido horario os pontos pbaixo, . . . , v1, . . . , u, v, v2 . . . (reticencias indicam pontos aque nao demos nomes). Ali, o ponto pnovo esta do lado de fora da fronteira, e entao ele deve ser acrescentado aofecho. Os pontos u, v, assim como varios pontos da fronteira que sao vistos por pnovo devem ser removidos. Noteque os pontos que vao sair estao entre v1 e v2. Isso e importante: os pontos que saem sao sempre um conjuntode pontos consecutivos na fronteira de H (se o conjunto de pontos tivesse um “furo”, o fecho nao seria convexo).Alem disso, esses extremos (v1 e v2), sao exatamente os pontos “vizinhos” de pnovo na fronteira do polıgono, depoisque ele e acrescentado ao fecho. Depois da remocao da regiao visıvel, H passa a conter, em sentido horario, ospontos pbaixo, . . . , v1, pnovo, v2 . . . Pode tambem acontecer de pnovo pertencer a uma aresta do fecho. Nesse caso,consideramos (de acordo com o enunciado) que ele deve ser acrescentado a H.

4. Certo, testar se o pnovo esta dentro do polıgono nos diz se ele entra ou nao em no fecho H. Mas como encontrar(caso existam) os pontos do fecho que precisam sair com a chegada do ponto?

Ja observamos que a parte do fecho que deve sair com a entrada de pnovo e “um pedaco so” da fronteira.Trocando em miudos, isso significa que so precisamos encontrar os extremos do pedaco que deve ser removido. Naverdade, os extremos so nao bastam, ja que dois pontos no fecho determinam dois pedacos, e precisamos saberqual deles queremos remover. A ambiguidade some se orientamos o fecho em um sentido — por exemplo, o sentidohorario — e chamamos um dos extremos de primeiro e o outro de ultimo.

Bom, e isso. Agora que compreendemos melhor o problema, vamos ataca-lo!

1Fecho convexo, em ingles, e convex hull, e. . . bem, ingles e uma lıngua tao comum quando se fala de algoritmos!

3

Page 4: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

5. Estrutura de nosso programa.

〈Arquivos de cabecalho 8 〉〈Constantes e variaveis globais 6 〉〈Pre-declaracao de funcoes 34 〉〈Funcoes 33 〉〈Rotina principal 7 〉

6. O s dados da regiao analisada ficam guardados em variaveis globais. O numero de pontos N e o numero daregiao numero regiao .

〈Constantes e variaveis globais 6 〉 ≡int N = 0;int numero regiao = 1;

Veja tambem os trechoss 15, 28, 29 e 31.

Codigo utilizado no trecho 5.

7. A rotina principal opera em lacos leitura, processamento, saıda, que em cada iteracao encontra o fecho convexopara cada uma das regioes descrita na entrada.

Como o numero de pontos no fecho pode ser “arbitrariamente” grande2, vamos fazer alguma alocacao dememoria, que precisaremos desfazer depois de processadas as regioes. Essa e a ultima tarefa de nosso programa.

〈Rotina principal 7 〉 ≡int main (int argc , char ∗∗argv ){〈Variaveis locais de main 12 〉printf ("prompt $ ");fflush (stdin );scanf ("%d",&N);while (N > 0) {〈Leitura e processamento do registro da regiao 9 〉〈 Imprime a resposta para a regiao 81 〉++numero regiao ; /∗ Avanca contador de regiao. ∗/printf ("prompt $ ");fflush (stdin );scanf ("%d",&N);

}〈Libera memoria alocada 18 〉return 0;}

Codigo utilizado no trecho 5.

8. Nossas necessidades de entrada, saıda e alocacao dinamica de memoria deixam claro que algumas bibliotecassao necessarias.

〈Arquivos de cabecalho 8 〉 ≡#include <stdio.h>

#include <stdlib.h>

Veja tambem os trechoss 22 e 32.

Codigo utilizado no trecho 5.

9. Guardamos as coordenadas dos pontos nos vetores X[0..N − 1] e Y [0..N − 1]. O fecho convexo e armazenadousando dois vetores: H[ ] e antecessor em H [ ], que nao vamos manipular diretamente. Como precisamos exibir ospontos do fecho em sentido horario, armazenamos essa informacao em H[]: se o ponto i = (x, y) = (X[i],Y [i]) estano fecho, entao sucessor (i) e o proximo ponto (da fronteira) do fecho, percorrido em sentido horario. Por sua vez,antecessor (sucessor (i)) ≡ i se i e um ponto do fecho. Certo, mas como saber se um ponto esta no fecho? Bom,tomando alguns cuidados na hora de escrever nosso algoritmo, podemos garantir que o ponto zero sempre faz parte

2Desde que nao excedidas as limitacoes do computador que se esta usando.

4

Page 5: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

do fecho. Um jeito de fazer isso e colocar nessa posicao algum dos pontos extremos da regiao, digamos, o de menory-coordenada. Em caso de empate entre pontos, tomamos o que tem a menor x-coordenada entre eles. Essa e nossaescolha aqui. Doravante, esse ponto sera chamado de pbaixo. Para economizar um pouco de tempo, encontramospbaixo a medida que lemos a entrada do problema. Vamos aproveitar tambem para encontrar palto, o ponto de maiorx-coordenada entre os pontos que empatam na maior y-coordenada da colecao. Quando N > 1, a condicao de quenao ha pontos da colecao com ambas as coordenadas iguais, garante que esse ponto existe e e diferente de pbaixo.Em todo caso, se N ≡ 1, o fecho e trivial.

〈Leitura e processamento do registro da regiao 9 〉 ≡〈Aloca espaco para X e Y ; para o programa em caso de erro 13 〉scanf ("%lf %lf",&X[0],&Y [0]); /∗ Le o primeiro ponto. ∗/if (N > 1) {〈Le o segundo ponto e inicializa ındices pbaixo e palto 10 〉〈Le os demais pontos, mantendo pbaixo e palto apontando para os pontos certos 11 〉〈Troca pbaixo e 0 de posicao e tambem palto e 1 em X[ ] e Y [ ] 16 〉for (i = 0; i < N ; ++i) printf ("%d -> %.1f %.1f\n", i,X[i], Y [i]);〈Encontra o fecho convexo da regiao 19 〉;

}Codigo utilizado no trecho 7.

10. 〈Le o segundo ponto e inicializa ındices pbaixo e palto 10 〉 ≡scanf ("%lf %lf",&X[1],&Y [1]);if (〈O ponto 0 tem y-coordenada menor do que a do ponto 1, ou ambos tem mesma y-coordenada mas 0 tem

x-coordenada menor 25 〉) {p baixo = 0;p alto = 1;}else {

p baixo = 1;p alto = 0;}

Codigo utilizado no trecho 9.

11. 〈Le os demais pontos, mantendo pbaixo e palto apontando para os pontos certos 11 〉 ≡for (p novo = 2; p novo < N ; ++p novo) {

scanf ("%lf %lf",&X[p novo ],&Y [p novo ]);if (〈Ponto pnovo deve entrar no lugar de pbaixo 23 〉) p baixo = p novo ;else /∗ Nenhum ponto poderia ser atribuıdo a ambos pbaixo e palto ao mesmo tempo. ∗/if (〈Ponto pnovo deve entrar no lugar de palto 24 〉) p alto = p novo ;}

Codigo utilizado no trecho 9.

12. 〈Variaveis locais de main 12 〉 ≡int p novo ;

Veja tambem os trechoss 17, 76 e 86.

Codigo utilizado no trecho 7.

13. Usamos uma abordagem hıbrida para gerenciamento da memoria no programa. Se o tamanho dos vetores,tamanho pontos , nao excede o limite tamanho inicial pontos , usamos vetores estaticamente alocados. Quando Nultrapassa o valor de tamanho pontos , alocamos memoria. A cada nova regiao processada, verificamos se N excedeutamanho pontos , alocando mais memoria se necessario.

Como o tamanho do fecho nao e necessariamente o tamanho do vetor de pontos, e como usamos dois vetores(H e antecessor ) para armazenar o fecho, o tamanho inicial fecho e menor do que tamanho inicial pontos .

Alem disso, ainda nao sabemos como vamos fazer a parte do programa que trata do aumento ou diminuicaodo fecho, entao deixamos a alocacao de H e antecessor em H para depois. De todo modo, e importante que cadaum dos vetores tenha inicialmente ao menos uma posicao, para que o programa trate os casos N ≡ 1 e N ≡ 2graciosamente.

5

Page 6: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

#define tamanho inicial pontos 2000 /∗ Sera que e melhor usar uma potencia de 2? ∗/#define tamanho inicial fecho 1000

〈Aloca espaco para X e Y ; para o programa em caso de erro 13 〉 ≡if (N > tamanho pontos ) {

libera pontos ( );X = malloc(sizeof (double) ∗N);Y = malloc(sizeof (double) ∗N);tamanho pontos = N ;}

Codigo utilizado no trecho 9.

14. A macro libera pontos ( ) so faz lguma coisa se o conjunto de pontos foi alocado alguma vez. Como isso soacontece se tamanho pontos > tamanho inicial pontos . . .

#define libera pontos () do{

if (tamanho pontos > tamanho inicial pontos ) {free (X);free (Y );X = X estatico ;Y = Y estatico ;tamanho pontos = tamanho inicial pontos ;

}}while (0)

15. Como dissemos, inicialmente X e Y apontam para vetores estaticamente alocados.

〈Constantes e variaveis globais 6 〉 +≡double X estatico [tamanho inicial pontos ], Y estatico [tamanho inicial pontos ];double ∗X = X estatico , ∗Y = Y estatico ;int tamanho pontos = tamanho inicial pontos ;

16. 〈Troca pbaixo e 0 de posicao e tambem palto e 1 em X[ ] e Y [ ] 16 〉 ≡x aux = X[0]; X[0] = X[p baixo ]; X[p baixo ] = x aux ;y aux = Y [0]; Y [0] = Y [p baixo ]; Y [p baixo ] = y aux ;x aux = X[1]; X[1] = X[p alto ]; X[p alto ] = x aux ;y aux = Y [1]; Y [1] = Y [p alto ]; Y [p alto ] = y aux ;

Codigo utilizado no trecho 9.

17. 〈Variaveis locais de main 12 〉 +≡int p baixo , p alto ;double x aux , y aux ;

18. 〈Libera memoria alocada 18 〉 ≡libera pontos ( );libera arvore ( );

Codigo utilizado no trecho 7.

6

Page 7: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

19. Encontrando o fecho

Nosso algoritmo opera “aumentando” o fecho pouco a pouco. Ele comeca com algum fecho pequeno (tres dospontos da colecao), e percorre a seguir os pontos que ainda nao foram analisados, alterando-o quando necessario.A estrutura do algoritmo e bastante simples. Inicializamos o fecho e depois processamos os pontos um a um.

Em um estagio intermediario, temos um fecho H, que podemos percorrer no sentido horario usando sucessor ( ).Queremos saber se o ponto pnovo deve entrar nessa lista, e, alem disso, que pontos devem sair do fecho com a suaentrada — se e que algum sai. Como fazer? Ja vimos que o ponto entra no fecho somente se esta fora, ou nafronteira, de seu polıgono. E como decidir se esse e o caso? Um jeito de decidir e percorrer as arestas do fecho emum sentido (horario ou anti-horario), observando de que lado esta o ponto. Como o polıgono definido pelos pontosdo fecho e convexo, o ponto estara sempre do mesmo lado somente quando ele esta dentro do polıgono. Um exemplopode ser visto na figura 3.

p

q

p

q

Figura 3: Esquerda: pontos fora (p) e dentro (q) do fecho. Se percorremos o fecho em sentido horario, q permanecea nossa direita, enquanto p fica ora a esquerda, ora a direita. Direita: Fecho apos a inclusao de p. Os pontos em H(vertices na fronteira do fecho) estao conectados por arestas — sao os vertices do polıgono definido pelo fecho.

Fixando que vamos percorrer o polıgono em sentido horario, se o ponto novo se mantiver a direita, ele estadentro do polıgono, e nao precisamos alterar o fecho. Se em algum caso o ponto fica a esquerda de uma aresta,sabemos que ele esta fora do polıgono, mas isso nao e tudo! Sabemos ainda que ele ve os extremos dessa aresta. Nafigura 3, os pontos vistos por p estao conectados a ele por uma linha tracejada. Ja vimos que os pontos vistos porp sao uma porcao conexa do fecho — uma curva poligonal. E facil decidir quem fica ou sai de H se sabemos quaispontos veem (ou, se preferir, sao vistos por) p: mantemos os extremos da regiao visıvel, e eliminamos seu interior.

Uma primeira estrategia entao e: observar, para cada aresta do fecho, se pnovo esta a esquerda, guardando aprimeira e a ultima aresta da regiao visıvel. Colocamos pnovo no fecho, entre os extremos dessa regiao, eliminandodo fecho os pontos internos.

O problema com essa estrategia e que sempre requer que analisemos todos os pontos que estao no nosso fechointermediario. Vamos fazer algo um pouco diferente, que as vezes nos leva mais rapido a resposta. . .

Queremos uma estrutura de dados que nos permita fazer uma especie de busca binaria pelos extremos da regiaovista por pnovo, de modo a encontrar uma aresta decisora da situacao de pnovo. Se pnovoesta a esquerda da arestadecisora, entao ele esta fora do polıgono; se esta a direita, entao esta dentro do polıgono. Essa aresta, claro, podeser diferente para cada pnovo.

Existe uma aresta assim? Considere um fecho — que e um polıgono convexo — com ao menos doise um ponto pnovo diferente de qualquer de seus vertices.

Se pnovo esta estritamente dentro do polıgono (isto e, esta dentro mas nao pertence a nenhumaaresta), entao o ponto esta a direita de todas as arestas, subendendendo como antes que percorremosas arestas em sentido horario. Nesse caso, todas as arestas sao decisoras.

Se pnovo esta em alguma aresta, entao ele esta a direita nao estrita de todas as arestas. Em particular,esta a direita estrita de todas as arestas exceto uma, e nesse caso pertence a aresta. A princıpio, usandoum teste de esquerda estrita, ainda aqui todas as arestas sao decisoras.

Se, por fim, esta fora do polıgono, esta a esquerda de algumas arestas e a direita de outras. Tomeum vertice qualquer do fecho, e trace um segmento de reta dele ate pnovo. Esse segmento tem umainterseccao nao nula com o fecho, que e pelo menos o vertice tomado, e no maximo um segmento de retaque “corta” o fecho. Seja pref o ponto da intersecao desse segmento que esta mais proximo de pnovo. Sepref e um vertice do fecho, entao

1. pnovo esta a ersquerda estrita de algum das arestas partindo de pref , ou

2. as arestas do fecho que tem pref como extremidade sao ambas paralelas ao segmento de reta queune pref e pnovo.

7

Page 8: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

Enquanto, se pref nao e vertice do fecho, entao as propriedades acima valem para a aresta em que esta.Isso sugere que a(s) arestas que incidem em pref sao arestas decisoras, desde que tomemos o cuidado deverificar quanto a colinearidade.

Em todo caso, existe uma aresta decisora. Com ela podemos decidir o destino de pnovo. Nossoobjetivo entao e encontrar essa aresta com uma busca binaria.

Mas uma busca binaria requer que se disponha de elementos em ordem, e a ordenacao de coisas, por sua vez,requer algum meio de compara-las. Essa comparacao e o assunto das proximas secoes.

Voltando a construcao do fecho, ela tem duas etapas: construımos um fecho inicial, com poucos pontos, e depoisvemos quais pontos devem ser acrescentados a ele.

〈Encontra o fecho convexo da regiao 19 〉 ≡〈 Inicializa fecho e p novo , de modo que pontos < pnovo nao precisem mais ser analisados 68 〉while (p novo < N) {〈Coloca pnovo no fecho se necessario, removendo pontos que devem sair 69 〉;lis ( );++p novo ; /∗ Proximo ponto nao analisado. ∗/

}Codigo utilizado no trecho 9.

20. Vamos falar de bastante coisa agora, antes de voltarmos a inicializacao do fecho e ao seu incremento. E bomsegurar o chapeu. Em algumas paginas estaremos de volta, quica mais experientes.

8

Page 9: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

21. Comparando com pontos do fecho

Para comparar pnovo com os pontos do fecho, vamos usar uma ordenacao angular (figura 4), inspirada no algoritmode Graham. Queremos uma ordenacao que coincida com a orientacao em sentido horario do fecho. Diremos quep precede o ponto q, denotado p ≺ q, se o angulo α = ppbaixoq, medido em sentido horario satisfaz 0 < α < 2π.A definicao e analoga para sucessao. Note que, quando comparamos pontos da colecao, sempre vale < 2π. Issopois pbaixo e o ponto de menor x-coordenadas entre os pontos de menor y-coordenada. Isso tambem quase sempreequivale a dizer que, partindo de p, e passando por pontos do fecho em sentido horario, encontramos q antes dechegar a pbaixo. (Voce consegue identificar quando essa analogia pode furar?)

pbaixo

pq

α

aumento

Figura 4: Ordenacao angular. Na figura p ≺ q ⇐⇒ α > 0.

Que fazer quando α e 0? Como p e q se comparam nesse caso? Queremos preservar a analogia com a ordenacaohoraria do fecho, de modo que p ≺ q quando p precede q numa volta em sentido horario, partindo de pbaixo.

Vamos associar a cada vertice do fecho uma de suas arestas. A aresta associada e a o conecta ao ponto seguinte,no sentido horario, no fecho. Assim a aresta do ponto i e (i, sucessor (i)). E essa aresta que usaremos para decidircomo comparar p e q quando α e 0. A partir de agora vamos assumir que p esta no fecho, e que estamos comparandop e q. Primeiro, note que se o α e zero, entao p, q e pbaixo sao colineares. Ha dois casos a considerar:

• O proximo ponto do fecho, sucessor (p) = j, e colinear aos outros tres pontos (pbaixo, p e q). Nesse caso,consideramos os vetores

−→pj e −→pq.

– Se os vetores apontam para sentidos opostos, entao q ≺ p;– caso contrario, p ≺ q.

• Se os vetores−→pj e −→pq nao sao paralelos (ou seja, j nao e colinear aos outros tres pontos), dizemos p ≺ q.

Segure as pontas, vamos tentar intuir melhor o que essa definicao significa. Por agora, o importante e perceberque, dois pontos satisfazem sempre uma das duas afirmacoes: p ≺ q ou p � q.

Intuicao do significado — adicionar!Figura com os quadro casos: α 6= 0; sucessor (p) nao-colinear; H[p] colinear e vetores com mesmo sentido;

sucessor (p) colinear e vetores com sentido oposto. Caso que nao ocorre: sucessor (p) nao-colinear e a esquerdaestrita de −−−−→pbaixop.

Uma observacao interessante: se p e q pertencem ao fecho (p, q 6= pbaixo), entao a unica situacao em que saocolineares a pbaixo e se eles estao no inıcio ou no fim da sequencia ordenada de pontos do fecho (podem estar noinıcio e no fim, se a sequencia consiste de pontos colineares). Isso porque o fecho e convexo, e se se p, q e pbaixosaocolineares, e existem pontos a ≺ p, q ≺ b do fecho, entao necessariamente a ou b e colinear a p e q. Trocando emmiudos, se existem pontos no fecho colineares a pbaixo, entao ocorre ao menos uma das duas coisas: todos os pontosque sucedem qualquer desses dois sao tambem colineares a pbaixo, ou todos os pontos que precedem qualquer dessesdois pontos sao tambem colineares a pbaixo.

A vantagem mais significativa desta ordenacao logo ficara clara. Perceba que, como pbaixo e um extremo dacolecao, sabemos que em nenhum passo do algoritmo incremental ele sera removido do fecho. Uma consequenciadesse fato e que, se v1 ≺ v2 sao os extremos da parte do fecho que e vista pnovo (vide figura2), entao pbaixo nao enenhum dos vertices no interior do trecho. Ele pode ser um dos extremos, mas podemos cuidar desse caso a parte.Ora, sabemos que a porcao da fronteira do fecho que e vista por pnovo forma um unico pedaco3, de extremos v1 e v2.Logo, os vertices w que saem do fecho com a entrada de pnovo satisfazem v1 6= w, v2 6= w, e sobretudov1 ≺ w ≺ v2!

3Ou seja, se u e v sao vertices que devem ser removidos, entao todos os vertices no fecho entre eles tambem devem ser removidostambem.

9

Page 10: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

Ha ainda outra vantagem nessa ordenacao. E que podemos comparar dois elementos sem grandes dores decabeca. Se os pontos sao co-lineares, um pouco de geometria analıtica nos ajudara a derivar o teste adequado. Seα > 0, podemos comparar os pontos usando o sinal do produto interno (euclideano) dos vetores −−−−→pbaixop e −−−−→pbaixoq(tomados no plano z = 0)

−−−−→pbaixop×−−−−→pbaixoq =(0, 0, (xp − xpbaixo

) · (yq − ypbaixo)− (xq − xpbaixo

) · (yp − ypbaixo)).

Essa formula resulta um valor negativo se q esta a direita de −−−−→pbaixop; zero se os pontos sao colineares, e um valorpositivo se esta a esquerda.

Podemos (e vamos) usar essa expressao tambem para testar se pnovo esta a esquerda ou direita de uma arestado polıgono.

Notacao. Em breve vamos falar um pouco das arestas do fecho, que sao as arestas entre dois pontos consecutivosdo fecho, e uma notacao sera util: quando falarmos de uma aresta (i, j), em que i e j sao pontos da colecao, deixamosimplıcito que nos nos referimos a aresta percorrida a partir de i na direcao de j. Isso sera importante quando nosfalarmos de pontos a esquerda ou a direita de uma aresta: sao os pontos que ficam a esquerda ou direita quando aaresta e percorrida segundo essa orientacao.

Voltamos a falar da comparacao. Queremos construir uma primitiva menor (i, j) que diga se o ponto i e menordo que o ponto j. Assumimos que j esta no fecho. Entao i ≺ j quando

1. α 6= 0 e temos que i esta estritamente a esquerda do vetor−−−−→pbaixoj;

2. α = 0 e valem

(a) i, j e sucessor (j) sao colineares, e

(b) os vetores−→ji e

−−−−−−−−→jsucessor (j) tem sentidos opostos.

No ultimo item da lista esta a comparacao que falta detalhar. Simplificamos computacionalmente o teste (quepoderia ser feito com o produto escalar dos vetores) se notamos que ele so e relevante quando os pontos sao colineares(algo que ja sabemos se testamos antes que α 6= 0). Bom, nesse caso, podemos inferir de que lado do ponto j estaoi e sucessor (j) comparando suas x-coordenadas com as de j. Se os pontos estao verticalmente alinhados, entaousamos a y-coordenada.

Paremos um pouco e vejamos o que temos. Criamos uma ordenacao dos pontos do fecho que esta de acordo coma orientacao de seus vertices em sentido sentido horario. Nao so isso, essa ordem e estrita, no sentido de que doispontos distintos sao sempre comparaaveis e um e menor do que o outro — igualdade nao acontece.

Em termos praticos, o sucessor de um ponto i, e exatamente sucessor (i)! De modo analogo, antecessor (sucessor (i))e i. Um tipo de magica, isso.

Quer saber se um pnovo esta dentro do polıgono do fecho? Fazemos uma busca binaria pelos vertices do fecho.O ultimo vertice p que virmos na busca e ou o menor dos vertices do fecho maior que pnovo, ou o maior dos verticesdo fecho menor que pnovo. O resultado da comparacao de pnovo e p nos diz qual dos casos vale. E daı?

Bom, digamos que p ≺ pnovo. Entao, podemos decidir se pnovo esta dentro, fora, ou na fronteira do polıgono dofecho observando sua posicao relativa a aresta (p, sucessor (p)), ja que p ≺ pnovo ≺ sucessor (p). A ideia e analogase p � pnovo, so que usamos a aresta (antecessor (p), p). Seja e a aresta em questao.

Se o ponto esta a sua esquerda (estrita), entao ele esta fora do polıgono. Se e colinear a aresta, entao temos(de graca) que ele e um ponto interior da aresta — ou seja, pertence ao segmento de reta da aresta. E esses saojustamente os dois casos em que o ponto deve ser inserido no fecho.

Resumindo: nossa ordenacao permite fazer uma busca binaria no conjunto dos vertices que estao no fecho. Aotermino da busca, tomando o sucessor ou o antecessor do ponto em questao, conseguimos determinar (em tempoconstante) se o ponto deve ou nao ser acrescentado ao fecho.

Definimos agora as operacoes que permitem comparar pontos, e testar colinearidade. As operacoes sao imple-mentadas usando macros por uma questao de eficiencia. Como a maior parte das vezes estamos usando pbaixo (quenunca muda) como referencia, algumas dessas macros tem duas versoes, uma das quais e geral , equanto a outra usaas coordenadas de pbaixo como referencia.

Como estaremos lidando com numeros em ponto flutuante, definimos uma constante eps que e a nossa precisao:dois numeros que diferem por menos do que isso sao iguais para nos.

10

Page 11: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

#define eps 10 · 10−7 /∗ Nao precisa ser grande, vamos arredondar bastante. ∗/#define produto interno(i, j) ((X[i]−X[0]) ∗ (Y [j]− Y [0])− (X[j]−X[0]) ∗ (Y [i]− Y [0]))

/∗ O produto interno que mais vamos calcular usa pbaixo como referencia. ∗/#define produto interno geral (ref , i, j) /∗ ref e o ponto comum aos vetores. ∗/

((X[i]−X[ref ]) ∗ (Y [j]− Y [ref ])− (X[j]−X[ref ]) ∗ (Y [i]− Y [ref ]))#define colineares (i, j) (fabs (produto interno(i, j) < eps )) /∗ α = 0 ∗/#define colineares geral (ref , i, j) /∗ pontos ref , i e j colineares? ∗/

(fabs (produto interno geral (ref , i, j) < eps ))#define direita estrita (i, j) (produto interno(i, j) < −eps ) /∗ =⇒ α 6= 0 ∧ i ≺ j ∗/#define direita estrita geral (ref , i, j) /∗ ponto j a direita do segmento (ref , i), orientado de ref para i ∗/

(produto interno geral (ref , i, j) < −eps )#define esquerda estrita (i, j) (produto interno(i, j) > eps ) /∗ =⇒ α 6= 0 ∧ i � j ∗/#define esquerda estrita geral (ref , i, j) /∗ ponto j a esquerda do segmento (ref , i), orientado de ref para i ∗/

(produto interno geral (ref , i, j) > eps )#define sentidos opostos (ref , p1 , p2 )

/∗ Assume que−−−→ref p1 e

−−−→ref p2 sao colineares. Tem sentidos opostos? ∗/

((X[p1 ] > X[ref ] + eps ∧X[p2 ] + eps < X[ref ])∨ ((fabs (X[p1 ]−X[p2 ]) < eps ) ∧ (Y [p1 ] > Y [ref ] + eps ∧ Y [p2 ] + eps < Y [ref ])))

#define menor (pto ,no) /∗ ponto [no ] esta no fecho. ∗/((esquerda estrita (pto , ponto [no ])) ∨ (((colineares (pto , ponto [no ])) ∧ (colineares (pto ,

ponto [H[no ]])) ∧ sentidos opostos (ponto [no ], pto , ponto [H[no ]]))))

22. A funcao fabs ( ) esta definida em math .h.

〈Arquivos de cabecalho 8 〉 +≡#include <math.h>

23. Agora que estamos mais entendidos em comparacoes usando double, podemos terminar algo que deixamospara tras.

〈Ponto pnovo deve entrar no lugar de pbaixo 23 〉 ≡(Y [p baixo ] > Y [p novo ] + eps ∨ (fabs (Y [p baixo ]− Y [p novo ]) < eps ∧X[p baixo ] > X[p novo ] + eps ))

Codigo utilizado no trecho 11.

24. 〈Ponto pnovo deve entrar no lugar de palto 24 〉 ≡(Y [p alto ] + eps < Y [p novo ] ∨ (fabs (Y [p alto ]− Y [p novo ]) < eps ∧X[p alto ] + eps < X[p novo ]))

Codigo utilizado no trecho 11.

25. 〈O ponto 0 tem y-coordenada menor do que a do ponto 1, ou ambos tem mesma y-coordenada mas 0 temx-coordenada menor 25 〉 ≡

(Y [0] + eps < Y [1] ∨ (fabs (Y [0]− Y [1]) < eps ∧X[0] + eps < X[1]))

Codigo utilizado no trecho 10.

11

Page 12: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

26. Mınimo e maximo elemento com a propriedade P

A discussao que acabamos de fazer sugere que estaremos buscando “intervalos” de elementos em uma sequenciaordenada. E queremos fazer isso com um mınimo de eficiencia (ja viu um entomologo aborrecido?).

Importante aqui e para que queremos os intervalos: buscamos o intervalo de pontos que serao substituıdos porpnovo no fecho. Vamos digredir um pouco e abstrair o que queremos fazer.

Temos uma sequencia ordenada, um elemento pnovo que queremos colocar nela, e uma dada propriedade P.Queremos encontrar o menor elemento pmin e o maior elemento pmax na sequencia (min ≺ pmax) tais que

• ambos satisfazem P,

• se trocamos os elementos entre eles por pnovo, a sequencia continua ordenada.

Note que nem toda ordenacao nos ajuda a fazer essa busca. Isso depende de como a propriedade “aparece” nasequencia ordenada. Felizmente, a propriedade que nos interessa — ser visto por pnovo — e bem-comportada: elasempre vale para um unico intervalo (possivelmente vazio) de elementos na sequencia.

Voltando agora para nossos requisitos, o ponto crucial para a eficiencia de nosso algoritmo e que a remocao einsercao de elementos nao pode demorar muito (e deve preservar a ordenacao do fecho). Optamos por guardar ainformacao da ordenacao em uma arvore binaria de busca balanceada. Alem disso, como ja dissemos, guardamos osucessor e o antecessor de um ponto. (Pode parecer que um deles basta, mas e importante que encontrar tanto umcomo outro seja uma tarefa eficiente. Vamos discudir isso com algum detalhe logo.)

Como ja discutimos, se sabemos que pnovo deve entrar no fecho, as propriedades da nossa ordenacao facilitamatualizar o fecho: encontramos o “maior” e o “menor” pontos do fecho que estao em arestas vistas por pnovo,removendo a seguir os pontos, e colocando pnovo em seu lugar.

Como os pontos do fecho estao em uma arvore binaria de busca, os algoritmos para encontrar o maior e omenor ponto que veem pnovo ficam simples. Se buscamos o maior ponto em uma aresta vista por pnovo: partindoda raiz, encontramos (recursivamente) o maior ponto em uma aresta vista por um ponto na sub-arvore dos pontosmaiores que a raiz, e retornamos esse ponto. Se nao ha ninguem satisfazendo a propriedade (ser visto por pnovo),entao testamos se a raiz e vista por pnovo, retornando a raiz se e verdade. Por fim, se a raiz tambem nao e vista,retornamos o resultado recursivo da chamada na sub-arvore menor. O algoritmo e simetrico para a busca do menorponto visto por pnovo.

Por razoes de eficiencia, essa e outras rotinas serao implementadas em uma forma iterativa. Postergamos aapresentacao dos detalhes para depois, quando soubermos mais sobre a arvore.

12

Page 13: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

27. A arvore binaria de busca balanceada

As proximas secoes tratam basicamente do gerenciamento de memoria e das primitivas para uso da arvore binaria.Ha varios tipos de arvores por aı, cada qual com seus pontos fortes. Correndo o risco de deixar boas solucoes

de fora, restringimos nossa discussao a comparacao entre arvore rubro-negra e AVL.Sinceramente, devo dizer que nao estou totalmente certo de que a decisao tomada esteja solidamente fundamen-

tada. Por isso mesmo acho importante deixar claro qual a sua base.O fato e que este algoritmo parece bastante sensıvel a ordem em que os pontos sao processados4 — alem de ser,

claro, sensıvel a proporcao de pontos que esta no fecho. A partir do ponto em que o fecho todo esta na arvore, elanao sofre mais insercoes, so buscas. Por outro lado, e certo que para cada ponto testado, sao feitas

• duas buscas para encontrar os extremos da regiao vista,

• no maximo uma insercao (de pnovo), e

• uma remocao para cada ponto que sai do fecho intermediario com a entrada de pnovo.

Em geral, o fecho intermediario tem pontos “definitivos” (que nao vao mais sair do fecho), e outros pontos, queestao esperando a entrada de um ponto definitivo para serem removidos.

Parece que a arvore adequada depende criticamente de quantos pontos se espera que sejam removidos com aentrada de um ponto no fecho. Se “poucos”, entao a arvore sofre mais consultas do que insercoes e remocoes. . . ?Nao parece claro.

Num compromisso em que pesou a curiosidade, optamos por usar uma arvore rubro-negra inclinada para aesquerda (left-leaning red-black tree), na esperanca de retornar em breve, com mais conhecimento de causa, e poras coisas preto no branco.

28. Guardamos o ponto que e a raiz da arvore em uma variavel global raiz . Um ponteiro nulo tem o valor NIL.Como a arvore e rubro-negra, e alem disso as folhas de tais arvores sao negras, definimos constantes e primitivaspara as cores tambem.

#define NIL −1#define rubro 0#define negro 1#define eh rubro(p) (p 6= NIL ∧ cor [p] 6= negro)#define eh negro(p) (p ≡ NIL ∨ cor [p] 6= rubro) /∗ Equivale a ¬eh rubro(p). ∗/〈Constantes e variaveis globais 6 〉 +≡

int raiz = NIL;

29. Cada no n da arvore tem sete campos

• ponto [n] guarda o ponto do fecho que representa,

• pai [n] ancestral direto (NIL se n e a raiz),

• filho menor [n] e filho maior [n], de modo que filho menor [n] ≺ n ≺ filho maior [n], e

• cor [n] e a cor do no: rubro ou negro .

• H[n] e o (no) sucessor de n se ele nao e o maior no da arvore; e NIL caso seja.

• antecessor em H [n] e o (no) antecessor de n se ele nao e o menor no da arvore; e NIL caso seja.

Os vetores sao alocados dinamicamente, mas quando o programa inicia os vetores associados a arvore apontampara vetores estaticamente alocados. Com isso, so faremos alocacao de memoria quando o tamanho da arvore excedeo limite tamanho inicial arvore .

#define tamanho inicial arvore tamanho inicial fecho

4O que sugere que talvez haja um ganho em aleatorizar a ordem em que os pontos sao armazenados. . .

13

Page 14: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

〈Constantes e variaveis globais 6 〉 +≡int ponto estatico [tamanho inicial arvore ], pai estatico [tamanho inicial arvore ],

filho menor estatico [tamanho inicial arvore ], filho maior estatico [tamanho inicial arvore ],H estatico [tamanho inicial arvore ], antecessor em H estatico [tamanho inicial arvore ];

short cor estatico [tamanho inicial arvore ];int ∗ponto = ponto estatico , ∗pai = pai estatico , ∗filho menor = filho menor estatico ,

∗filho maior = filho maior estatico , ∗H = H estatico , ∗antecessor em H = antecessor em H estatico ;short ∗cor = cor estatico ;int menor no = NIL, maior no = NIL;

30. Definimos tambem os “apelidos” de H e antecessor em H .

#define sucessor (x) (H[(x)] 6= NIL ? ponto [H[(x)]] : 0) /∗ pbaixo e 0. ∗/#define antecessor (x) (antecessor em H [(x)] 6= NIL ? ponto [antecessor em H [(x)]] : 0) /∗ pbaixo e 0. ∗/

31. Gerenciamos o espaco livre com o auxılio das variaveis tamanho arvore e proxima posicao livre . A primeirae o numero de posicoes que existem em cada um dos vetores apontados por ponto , pai , etc., enquanto a segundaaponta para o inıcio de uma lista ligada de posicoes livres, em que os elementos estao ligados pelo seu campo pai ,como veremos. A variavel proxima posicao livre e mantida sempre < tamanho arvore , e a posicao com esse ındiceesta livre (em todos os vetores). Alem disso,

• ou pai [proxima posicao livre ] ≡ NIL,

• ou pai [proxima posicao livre ], aponta para uma posicao livre (em todos os vetores), de modo que atribuirproxima posicao livre = pai [proxima posicao livre ] mantem as propriedades da variavel.

O pedido de um no livre ( ) retorna o ındice de uma posicao ainda nao usada nos vetores, e avanca o apontadorpara uma posicao livre. Se esse avanco invalida as propriedades do apontador (i.e., se com isso proxima posicao livre ≡tamanho arvore ), fazemos uma chamada para aumenta tamanho arvore ( ), que dobra o espaco disponıvel. O pri-meiro aumento e algo diferente dos demais, ja que passamos da alocacao estatica para um regime de alocacaodinamica, e o conteudo dos vetores estaticos e copiado para os vetores alocados. Temos ainda inicializa arvore ( ) elibera arvore ( ), com as funcoes obvias de inicializacao e liberacao da estrutura de dados.

Com isso podemos escrever o codigo que gerencia a alocacao e liberacao de memoria.

#define inicializa arvore () do{

proxima posicao livre = 0;pai [proxima posicao livre ] = NIL;raiz = NIL;menor no = maior no = NIL;}while (0)

#define aumenta tamanho arvore () do{

if (tamanho arvore 6= tamanho inicial arvore ) { /∗ A arvore ja foi aumentada alguma vez. ∗/tamanho arvore ∗= 2;ponto = realloc(ponto , tamanho arvore );pai = realloc(pai , tamanho arvore );filho menor = realloc(filho menor , tamanho arvore );filho maior = realloc(filho maior , tamanho arvore );H = realloc(H, tamanho arvore );antecessor em H = realloc(antecessor em H , tamanho arvore );cor = realloc(cor , tamanho arvore );

}else {

tamanho arvore ∗= 2;ponto = malloc(sizeof (int) ∗ tamanho arvore );pai = malloc(sizeof (int) ∗ tamanho arvore );filho menor = malloc(sizeof (int) ∗ tamanho arvore );filho maior = malloc(sizeof (int) ∗ tamanho arvore );

14

Page 15: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

H = malloc(sizeof (int) ∗ tamanho arvore );antecessor em H = malloc(sizeof (int) ∗ tamanho arvore );cor = malloc(sizeof (short) ∗ tamanho arvore );tamanho arvore /= 2;memcpy (ponto , ponto estatico , sizeof (int) ∗ (tamanho arvore ));memcpy (pai , pai estatico , sizeof (int) ∗ (tamanho arvore ));memcpy (filho menor ,filho menor estatico , sizeof (int) ∗ (tamanho arvore ));memcpy (filho maior ,filho maior estatico , sizeof (int) ∗ (tamanho arvore ));memcpy (H,H estatico , sizeof (int) ∗ (tamanho arvore ));memcpy (antecessor em H , antecessor em H estatico , sizeof (int) ∗ (tamanho arvore ));memcpy (cor , cor estatico , sizeof (short) ∗ (tamanho arvore ));tamanho arvore ∗= 2;

}}while (0)

#define libera arvore () do{

if (tamanho arvore > tamanho inicial arvore ) { /∗ Memoria foi alocada ∗/free (ponto);free (pai );free (filho maior );free (filho menor );free (H);free (antecessor em H );free (cor );tamanho arvore = tamanho inicial arvore ;

}ponto = ponto estatico ;pai = pai estatico ;filho menor = filho menor estatico ;filho maior = filho maior estatico ;H = H estatico ;antecessor em H = antecessor em H estatico ;cor = cor estatico ;}while (0)

〈Constantes e variaveis globais 6 〉 +≡int tamanho arvore = tamanho inicial arvore , proxima posicao livre = 0;

32. 〈Arquivos de cabecalho 8 〉 +≡#include <string.h> /∗ Para memcpy ( ). ∗/

33. Obtendo no livre, e liberando no.

#define libera no(no) do{

double libera (no);pai [no ] = proxima posicao livre ;proxima posicao livre = no ;}while (0)

〈Funcoes 33 〉 ≡int no livre ( ){

int resposta ;

15

Page 16: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

resposta = proxima posicao livre ;if (pai [proxima posicao livre ] ≡ NIL) {

++proxima posicao livre ;if (proxima posicao livre ≡ tamanho arvore ) aumenta tamanho arvore ( );pai [proxima posicao livre ] = NIL;

}else proxima posicao livre = pai [proxima posicao livre ];return resposta ;}

Veja tambem os trechoss 38, 47, 51, 52, 56, 60, 87, 89 e 91.

Codigo utilizado no trecho 5.

34. 〈Pre-declaracao de funcoes 34 〉 ≡int no livre ( );

Veja tambem os trechoss 48 e 90.

Codigo utilizado no trecho 5.

16

Page 17: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

35. Arvore rubro-negra

Uma implementacao de arvore rubro-negra “inclinada para a esquerda”. Garantimos que todo no e rubro ou negro ,toda folha (NIL) e negra, os filhos de um no rubro sao negros, nenhum filho direito e rubro , e, por fim, o caminhode um no ate qualquer de suas folhas tem o mesmo numero de nos negros. Para compreender melhor esse tipo dearvore, discutiremos um pouco suas propriedades.

Quando percorremos um caminho a partir da raiz da arvore (embora isso seja valido para qualquer no, de modogeral) ate alguma das folhas da arvore, as restricoes da arvore mencionadas acima implicam que nunca passaremospor dois nos vermelhos em seguida. Como o numero de nos negros pelos quais passamos e constante, nao importa emqual folha terminamos, o caminho mais longo ate alguma folha e no maximo duas vezes mais longo que o caminhomais curto.

Para entender o balanceamento de arvores rubro-negras, vamos virar o problema e observar outros tipos dearvores, a arvore 2–3 e arvore 2–3–4. Veremos como esse tipo de arvore pode ser mantido perfeitamente balanceado,e que arvores rubro-negras (em particular arvores rubro-negras inclinadas, digamos, a esquerda) possuem umacorrespondencia com essas estruturas. Essa correspondencia pode ser mantida sem grandes penas, e o resultado euma arvore com certas garantias de balanceamento — e, consequentemente, no tempo que leva para buscar, inserire remover elementos seus.

Esses tipos de arvore sao generalizacoes de arvores binarias. Em uma arvore 2–3, os nos podem ter dois ou tresfilhos, enquanto em uma arvore 2–3–4 podem ter dois, tres ou quatro filhos. Esses nos sao chamados 2-nos, 3-nosou 4-nos, dependendo da quantidade de filhos que tem. Um no com k filhos tem k − 1 chaves. Por exemplo, um3-no p = (a, b) com chaves a e b (a < b) aponta para tres filhos. Um deles e raiz de uma sub-arvore em que todasas chaves tem valor < a; os nos de outra das sub-arvores tem chaves com valores entre a e b. A terceira sub-arvore,nao e surpresa, tem nos com chaves de valor maior do que b. Arvores 2–3–4 sao definidas de modo analogo.

Acontece que e possıvel manter essas arvores completamente balanceadas (qualquer caminho da raiz ate algumafolha passa pelo mesmo numero de nos). Por enquanto, nos limitamos a descrever como e o mapeamento (umpara um!) desse tipo de arvores as arvores rubro-negras inclinadas para a esquerda (arnie). Desenvolvemos oferramental para manutencao da estrutura (preservando o mapeamento!) aos poucos, nas proximas secoes. Ao fimdeste ultimo mergulho, voltaremos quica um pouco mais sabios, e podemos cuidar das mariposas (as que ainda naohouverem fugido).

O mapeamento e o seguinte: cada 2-no corresponde a um no negro na arnie; um 3-no esta associado a um nonegro com um filho menor rubro ; um 3 no equivale a um no negro com dois filhos rubros . As folhas e raiz da arvoresao negras.

36. Buscamos na arnie de modo analogo ao que farıamos em uma arvore binaria. Se a chave buscada nao e a dono em que estamos, identificamos a qual intervalo definido pelas chaves do no a chave pertence, e seguimos a buscarecursivamente pela sub-arvore associada a esse intervalo.

Aqui vamos frequentemente buscar um ponto que nao esta presente na arvore, com o objetivo de encontrar qualseria seu sucessor ou antecessor se ele fosse acrescentado a arvore. Essa operacao, contudo, so acontece em umponto do programa, e por isso vamos deixar o procedimento la, conscientes de que em algum nıvel isso parece ferir o“encapsulamento” da arvore binaria. (Mas, de fato, este programa ja feriu o encapsulamento em alguns pontos. . . )

17

Page 18: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

37. Insercao

A insercao em arvores 2–3–4 ocorre na ultima folha encontrada em pela busca. Se o no e um 2-no ou um 3-noa insercao pode ser feita sem alterar o balanceamento da arvore. Para evitar que a folha seja um 4-no, podemostransformar (leia-se dividir) os 4-nos que encontramos pelo caminho.

Se a raiz for um 4-no, podemos transforma-la em tres 2-nos (“subindo” sua chave do meio). Ou seja, a buscasempre parte de um no com menos de tres chaves. Se, em algum passo intermediario, vamos passar de um 2-no oude um 3-no para um 4-no, podemos “subir” uma chave desse 4-no para o no em que estamos, antes de avancar paraa sub-arvore do (ex-4)-no. Assim, garantimos que nunca estamos em um 4-no, e a insercao e simples.

Acontece que nao precisamos fazer isso! Ao menos nao quando descemos pela arvore. Numa etapa final, apos ainsercao, podemos retornar pelo caminho percorrido, consertando os problemas que criamos. . . desde que consigamosassegurar que qualquer problema criado de fato fica no caminho de volta.

O que chamamos acima de “subir” uma chave nada mais e do que dividir um no que tem mais de uma chave.As ferramentas que nos ajudam a fazer isso em nossa arnie sao rotacoes e trocas de cor.

Nao descreveremos aqui o que e uma rotacao, mas vale comentar que tanto rotacoes quanto trocas de cor podemdestruir as propriedades da arnie pelas quais tanto zelamos. Podemos consertar as coisas, contudo, se depois deinserido o no (ou removido, ja que a ideia e parecida) retrocedermos “geracao por geracao” na arvore, seguindo osponteiros pai [ ] do no. Esse trabalho e feito por 〈Conserta o que foi baguncado 45 〉.

38. A insercao comeca com uma busca pelo ponto de insercao. Essa busca continua ate que os limites da arvore.Nesse ponto, no atual aponta para o ultimo vertice visitado antes de uma folha da arvore ter sido atingida — asfolhas sao sempre NIL.

#define verdade 1

〈Funcoes 33 〉 +≡void insere (int p novo){〈Variaveis locais de insere 46 〉if (raiz 6= NIL) { /∗ Arvore nao esta vazia. ∗/

no atual = raiz ;while (verdade ) {〈Segue a busca, avancando no atual . Prepara a insercao em uma folha de no atual e escapa do loop 39 〉

}〈 Insere pnovo na folha 44 〉〈Conserta o que foi baguncado 45 〉

}else {〈 Insere pnovo na arvore vazia 43 〉

}}

39. 〈Segue a busca, avancando no atual . Prepara a insercao em uma folha de no atual e escapa do loop 39 〉 ≡if (〈 pnovo ≺ ponto [no atual ] 40 〉) {

printf ("(%d) < (%d)\n", p novo , ponto [no atual ]);if (filho menor [no atual ] ≡ NIL) {

filho menor [no atual ] = no livre ( ); proximo no = filho menor [no atual ];〈Altera apontadores de antecessor e sucessor para inclusao do filho menor 41 〉break;

}no atual = filho menor [no atual ];}else {

printf ("(%d) > (%d)\n", p novo , ponto [no atual ]);if (filho maior [no atual ] ≡ NIL) {

filho maior [no atual ] = no livre ( ); proximo no = filho maior [no atual ];〈Altera apontadores de antecessor e sucessor para inclusao do filho maior 42 〉break;

}

18

Page 19: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

no atual = filho maior [no atual ];}

Codigo utilizado no trecho 38.

40. 〈 pnovo ≺ ponto [no atual ] 40 〉 ≡menor (p novo , ponto [no atual ])

Codigo utilizado no trecho 39.

41. 〈Altera apontadores de antecessor e sucessor para inclusao do filho menor 41 〉 ≡if (antecessor em H [no atual ] 6= NIL) {H[antecessor em H [no atual ]] = proximo no ; /∗ Altera sucessor do antecessor. ∗/}else { /∗ O no que estamos inserindo e o menor na arvore. ∗/

menor no = proximo no ;}antecessor em H [proximo no ] = antecessor em H [no atual ];H[proximo no ] = no atual ;antecessor em H [no atual ] = proximo no ;

Codigo utilizado no trecho 39.

42. 〈Altera apontadores de antecessor e sucessor para inclusao do filho maior 42 〉 ≡if (H[no atual ] 6= NIL) {

antecessor em H [H[no atual ]] = proximo no ; /∗ Altera antecessor do sucessor. ∗/}else { /∗ O no que estamos inserindo e o maior na arvore. ∗/

maior no = proximo no ;}H[proximo no ] = H[no atual ];antecessor em H [proximo no ] = no atual ;H[no atual ] = proximo no ;

Codigo utilizado no trecho 39.

43. 〈 Insere pnovo na arvore vazia 43 〉 ≡raiz = no livre ( );ponto [raiz ] = p novo ;cor [raiz ] = negro ;filho menor [raiz ] = filho maior [raiz ] = NIL;pai [raiz ] = NIL;H[raiz ] = antecessor em H [raiz ] = NIL; /∗ A raiz e o maximo e o mınimo. ∗/menor no = maior no = raiz ;

Codigo utilizado no trecho 38.

44. 〈 Insere pnovo na folha 44 〉 ≡ponto [proximo no ] = p novo ;cor [proximo no ] = rubro ;filho menor [proximo no ] = filho maior [proximo no ] = NIL;pai [proximo no ] = no atual ;

Codigo utilizado no trecho 38.

19

Page 20: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

45. Subimos pela arvore, ancestral por ancestral, consertando as infracoes as regras da arnie que foram deixadasem nosso caminho. Da algum trabalho verificar que todo estrago que pode ter sido feito vai ser encontrado nesseprocesso. . . (quem sabe facamos isso um dia?) Mas ao menos vamos comentar os tres tipos de infracao.

Um tipo de infracao e um no com filho direito vermelho. Esse caso resolvemos com uma rotacao na direcaodo filho menor . Outros tipo e a ocorrencia de dois filho menor vermelhos em seguida. Isso resolvemos com umarotacao na direcao do filho maior do primeiro ancestral comum5. Finalmente, se ambos os filhos de um no saovermelhos, trocamos as cores dos filhos e do no (isso e necessario para que que possamos “avancar” para o ancestralsem medo de algum infracao de sete cabecas).

〈Conserta o que foi baguncado 45 〉 ≡printf ("O conserto esta para comecar.\n");lis ( );proximo no = no atual ;while (proximo no 6= NIL) {

no atual = proximo no ;#ifdef BLOBDIGNAG

printf ("no_atual = %d, ponto[no_atual] = %d, filho_maior[no_atual] = %d, filho_menor[no\_atual] = %d, pai[no_atual] = %d\n",no atual , ponto [no atual ],filho maior [no atual ],filho menor [no atual ], pai [no atual ]);

getchar ( );#endif

if (eh rubro(filho maior [no atual ])) no atual = rotaciona menor (no atual );if (eh rubro(filho menor [no atual ]) ∧ eh rubro(filho menor [filho menor [no atual ]]))

no atual = rotaciona maior (no atual );if (eh rubro(filho menor [no atual ]) ∧ eh rubro(filho maior [no atual ])) troca cores (no atual );proximo no = pai [no atual ];}raiz = no atual ;cor [raiz ] = negro ;printf ("O conserto terminou.\n");

Codigo citado no trecho 37.

Codigo utilizado nos trechos 38, 52, 56 e 64.

46. 〈Variaveis locais de insere 46 〉 ≡int no atual , proximo no ;

Codigo utilizado no trecho 38.

47. A funcao rotaciona menor ( ) assume que filho maior [p] 6= NIL e cor [filho maior [p]] ≡ rubro , e rotaciona maior ( )assume que filho menor [p] 6= NIL e cor [filho menor [p]] ≡ rubro .

〈Funcoes 33 〉 +≡int rotaciona menor (int p){

int q;

q = filho maior [p];filho maior [p] = filho menor [q];filho menor [q] = p;pai [q] = pai [p];pai [filho maior [p]] = p;pai [p] = q;cor [q] = cor [p];cor [p] = rubro ;return q;

}5Note que isso significa que o concerto nao pode iniciar com o pai de uma folha, nao haveria nıveis o suficiente para esse teste —

sendo assim, se houvesse algo que consertar para o pai da folha, isso tem que ser feito antes deste trecho.

20

Page 21: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

int rotaciona maior (int p){

int q;

q = filho menor [p];filho menor [p] = filho maior [q];filho maior [q] = p;pai [q] = pai [p];pai [filho menor [p]] = p;pai [p] = q;cor [q] = cor [p];cor [p] = rubro ;return q;

}

48. 〈Pre-declaracao de funcoes 34 〉 +≡int rotaciona menor (int p);int rotaciona maior (int p);

49. Ajuste de cores. Se o no p e interno, podemos usar:

#define troca cores (p) do{

cor [p] = outra cor (cor [p]);cor [filho menor [p]] = outra cor (cor [filho menor [p]]);cor [filho maior [p]] = outra cor (cor [filho maior [p]]);}while (0)

#define outra cor (c) (1− c)

21

Page 22: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

50. Remocao

Tornamos agora para a retirada de um no da arvore. Vamos usar uma combinacao de duas ideias. Primeiro, eanalogamente ao que acontece na insercao, notamos que existem nos cuja remocao e simples de fazer. Aqui, estamosfalando dos nos que contem a maior e a menor chaves de alguma sub-arvore, desde que esse no nao seja uma 2-no.Buscaremos um meio de garantir que o caso indesejado nao aconteca, transformando a arvore a medida que buscamoso no que vamos remover (como na insercao, isso invalida algumas propriedades da arnie, que conseguimos consertarexatamente como fizemos antes). A segunda ideia e remover um no qualquer usando, por exemplo, a remocao domenor elemento de sua sub-arvore filho maior .

Para remover o no de maior chave, passamos de filho maior para filho maior , enquanto pudermos. Idealmente,quando nao pudermos mais prosseguir, estaremos em um 3-no ou 4-no, e a remocao do no nao estraga a arvore!Trata-se entao de garantir que nesse percurso o no atual nunca e um 2-no. Podemos fazer isso combinando nos-irmaos (caso tanto o no para o qual se quer seguir “descendo” como seu irmao sejam 2-nos) ou, se o irmao dono tem mais do que uma chave, tomando emprestado dele uma das chaves. Como antes, usaremos as rotacoes etrocas de cores para obter as transformacoes equivalentes da arnie, de modo que qualquer transgressao de suaspropriedades fique na linha de ancestrais do no por onde continuamos procurando — assim podemos consertar oestrago “na volta”.

O procedimento e analogo para a remocao do no de menor chave, mas em geral precisamos baguncar menos ascoisas, ja que, por definicao da arnie, os 3-nos e 4-nos sao inclinados no sentido da sub-arvore das chaves menores.

Uma ultima palavra sobre o significado de carregarmos 3-nos e 4-nos a medida que prosseguimos. O invarianteque mantemos e que ou o no atual e rubro , ou o seu filho por onde pretendemos prosseguir e rubro (?). O unicocaso em que nao conseguimos carregar esses nos ocorre quando a arvore so tem um no: a raiz. Esse caso podemostratar a parte sem problemas.

51. Usando rotacoes e trocas de cores, vamos construir agora duas novas primitivas: move rubro para menor (no)e move rubro para maior (no). Sao analogas, entao vamos discutir apenas a segunda.

A ideia e assegurar o invariante (?) para o filho maior (em suma, estamos em um 3-no ou 4-no). Partimos dopressuposto que no e rubro, pois se seu filho maior e rubro, esse metodo nao tera sido chamado. Trocamos as coresde no e de seus filhos com troca cores (no). Mas isso pode ter causado uma violacao das propriedades da arnieno filho menor do no. Isso acontece se filho menor [filho menor [no ]] e vermelho tambem. Nesse caso, eliminamos atransgressao com uma rotacao e ainda outra troca de cores.

〈Funcoes 33 〉 +≡int move rubro para maior (int no){

troca cores (no);if (eh rubro(filho menor [filho menor [no ]])) {

no = rotaciona maior (no);troca cores (no);

}return no ;}int move rubro para menor (int no){

troca cores (no);if (eh rubro(filho menor [filho maior [no ]])) {

filho maior [no ] = rotaciona maior (filho maior [no ]);no = rotaciona menor (no);troca cores (no);

}return no ;}

52. Conseguimos agora remover o maximo! Se o filho menor do no e rubro, movemos a ligacao rubra com umarotacao no sentido do filho maior — e entao podemos prosseguir para esse no mantendo o invariante (?). Se tantoo proximo no na busca filho maior [no ] quanto seus filhos6 sao negros, entao movemos a ligacao rubra do no atualpara o seu filho maior usando a primitiva que acabamos de criar. Por fim, quando encontramos o maximo, podemosremove-lo sem maiores pesares, passando depois disso a tarefa de “normalizar” os ancestrais na arnie.

6Na verdade so os filhos menores de no e de seu filho maior precisam ser testados, gracas a inclinacao da arnie.

22

Page 23: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

〈Funcoes 33 〉 +≡void remove maximo de subarvore (int no){〈Variaveis locais de remove maximo de subarvore 55 〉if (no 6= NIL) { /∗ Sub-arvore nao esta vazia. ∗/

no atual = no ;while (verdade ) {〈Segue a busca pelo maximo, garantindo nunca estar em um 2-no. Sai do loop garantindo

proximo no ≡ filho maior [no atual ] e o maximo 53 〉}〈Remove o maximo (proximo no) 54 〉〈Conserta o que foi baguncado 45 〉

}}

53. 〈Segue a busca pelo maximo, garantindo nunca estar em um 2-no. Sai do loop garantindoproximo no ≡ filho maior [no atual ] e o maximo 53 〉 ≡

if (eh rubro(filho menor [no atual ])) no atual = rotaciona maior (no atual );if (filho maior [no atual ] ≡ NIL) { /∗ Encontramos o no com a maior chave! ∗/

proximo no = no atual ;no atual = pai [no atual ];break;}if (eh negro(filho maior [no ]) ∧ eh negro(filho menor [filho maior [no atual ]]))

no atual = move rubro para maior (no atual );no atual = filho maior [no atual ];

Codigo utilizado no trecho 52.

54. Testamos se no atual (que e o pai do no a ser removido) e NIL. Isso acontece quando a arvore da qualqueremos remover o maximo tem apenas um no.

〈Remove o maximo (proximo no) 54 〉 ≡if (no atual 6= NIL) {

filho maior [no atual ] = NIL;maior no = antecessor em H [proximo no ];libera no(proximo no);}else maior no = menor no = NIL;

Codigo citado no trecho 58.

Codigo utilizado no trecho 52.

55. 〈Variaveis locais de remove maximo de subarvore 55 〉 ≡int no atual , proximo no ;

Codigo utilizado no trecho 52.

56. Vamos cuidar do mınimo agora. A ideia basica e a mesma: garantir que nao estamos em um 2-no a medidaque a busca progride, remover o menor no, arrumar a casa depois que a farra termina.

〈Funcoes 33 〉 +≡void remove minimo de subarvore (int no){〈Variaveis locais de remove minimo de subarvore 59 〉if (no 6= NIL) { /∗ Sub-arvore nao esta vazia. ∗/

no atual = no ;while (verdade ) {〈Segue a busca pelo mınimo, garantindo nunca estar em um 2-no. Sai do loop garantindo

proximo no ≡ filho menor [no atual ] e o mınimo 57 〉

23

Page 24: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

}〈Remove o mınimo (proximo no) 58 〉〈Conserta o que foi baguncado 45 〉

}}

57. 〈Segue a busca pelo mınimo, garantindo nunca estar em um 2-no. Sai do loop garantindoproximo no ≡ filho menor [no atual ] e o mınimo 57 〉 ≡

if (filho menor [no atual ] ≡ NIL) { /∗ Dessa vez encontramos o no com a menor chave! ∗/proximo no = no atual ;no atual = pai [no atual ];break;}if (eh negro(filho menor [no ]) ∧ eh negro(filho menor [filho menor [no atual ]]))

no atual = move rubro para menor (no atual );no atual = filho menor [no atual ];

Codigo utilizado no trecho 56.

58. Assim como em 〈Remove o maximo (proximo no) 54 〉, o teste e necessario.

〈Remove o mınimo (proximo no) 58 〉 ≡if (no atual 6= NIL) {

filho menor [no atual ] = NIL;menor no = H[proximo no ];libera no(proximo no);}else maior no = menor no = NIL;

Codigo utilizado no trecho 56.

59. 〈Variaveis locais de remove minimo de subarvore 59 〉 ≡int no atual , proximo no ;

Codigo utilizado no trecho 56.

60. Combinamos agora as ferramentas que construımos, para poder remover um elemento arbitrario psai da arvore.A ideia e a seguinte: partindo da raiz, seguimos procurando o no que queremos remover. Nesse processo, asseguramos(usando move rubro para maior ( ) que estamos em um 3-no ou em um 4-no. Quando encontramos o elementobuscado, substituımos o valor de sua chave pelo valor da chave de seu sucessor (o antecessor funcionaria igualmentebem). A seguir, removemos sucessor, que e o no de menor chave na sub-arvore filho maior do no!

Note que nao e preciso se preocupar em arrumar os nos que foram manipulados no inıcio, ja que o ultimo passode remove minimo de subarvore ( ) e iniciar o concerto da arvore, que prossegue ate a raiz da arvore.

〈Funcoes 33 〉 +≡void remove da arvore (int p sai ){〈Variaveis locais de remove da arvore 67 〉if (raiz 6= NIL) { /∗ Arvore nao esta vazia. ∗/

no atual = raiz ;while (verdade ) {〈Caminha pela arvore buscando psai, e removendo-o se encontrado. Conserta a arvore e retorna. 61 〉

}}}

24

Page 25: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

61. Se o no esta a esquerda, use move rubro para menor , e analogamente, ate encontrar o no. . . Uma palavrasobre a condicao (? ?). Testamos apenas o filho maior para saber se o no e uma folha. Por que? A condicao anteriorgarante que se o filho menor fosse vermelho, aconteceria uma rotacao, e entao o filho maior seria vermelho. Se ono vermelho e nulo, significa que a condicao anterior resultou falsa, e o no filho menor e negro tambem. Como paraqualquer no a “altura negra” e igual, se o no filho maior e NIL, entao o filho menor tem que ser NIL tambem.

Sobre a consicao (? ? ?): neste ponto, sabemos que a psai ⊀ ponto [no atual ], e que, se p sai ≡ ponto [no atual ],entao nao estamos em uma folha (mais ainda, a sub-arvore maior do no atual tem pelo menos um no nao NIL).Sendo assim, ou o no atual e o no buscado, ou o no procurado esta na sub-arvore maior. Em ambos os casos,queremos garantir que a busca possa prosseguir por essa arvore.

〈Caminha pela arvore buscando psai, e removendo-o se encontrado. Conserta a arvore e retorna. 61 〉 ≡if (〈 psai ≺ ponto [no atual ] 62 〉) {

printf ("(%d) < (%d)\n", p sai , ponto [no atual ]);〈 “Empurra” um link rubro para o filho menor se necessario, e prossegue para esse filho. 63 〉}else {

printf ("(%d) > (%d)\n", p sai , ponto [no atual ]);if (eh rubro(filho menor [no atual ])) no atual = rotaciona maior (no atual );if (ponto [no atual ] ≡ p sai ∧ filho maior [no atual ] ≡ NIL) { /∗ (? ?) ∗/〈Estamos em uma folha (no atual ), que e o no a ser removido. Remove no atual e percorre a arvore “ao

contrario”, consertando o que houver de errado; retorna da rotina 64 〉}if (eh negro(filho maior [no atual ]) ∧ eh negro(filho menor [filho maior [no atual ]])) { /∗ (? ? ?) ∗/

no atual = move rubro para maior (no atual );}if (ponto [no atual ] ≡ p sai ) {〈Estamos em um no interno (no atual ), que e o no a ser removido. Coloca o valor do sucessor de no atual

em no atual e atualiza sucessor, remove o mınimo do filho maior do no atual ; retorna da rotina 66 〉}else {

no atual = filho maior [no atual ];}}

Codigo utilizado no trecho 60.

62. 〈 psai ≺ ponto [no atual ] 62 〉 ≡menor (p sai , ponto [no atual ])

Codigo utilizado no trecho 61.

63. 〈 “Empurra” um link rubro para o filho menor se necessario, e prossegue para esse filho. 63 〉 ≡if (eh negro(filho menor [no atual ]) ∧ eh negro(filho menor [filho menor [no atual ]])) {

no atual = move rubro para menor (no atual );}no atual = filho menor [no atual ];

Codigo utilizado no trecho 61.

64.〈Estamos em uma folha (no atual ), que e o no a ser removido. Remove no atual e percorre a arvore “aocontrario”, consertando o que houver de errado; retorna da rotina 64 〉 ≡

if (pai [no atual ] ≡ NIL) { /∗ O no e folha, e e raiz da arvore. Vamos deixar a arvore vazia. . . ∗/libera no(no atual );raiz = maior no = menor no = NIL;}else {

if (filho menor [pai [no atual ]] ≡ no atual ) filho menor [pai [no atual ]] = NIL;else filho maior [pai [no atual ]] = NIL;〈Liga antecessor em H [no atual ] a H[no atual ] e vice-versa 65 〉libera no(no atual );

25

Page 26: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

no atual = pai [no atual ];〈Conserta o que foi baguncado 45 〉}return;

Codigo utilizado no trecho 61.

65. 〈Liga antecessor em H [no atual ] a H[no atual ] e vice-versa 65 〉 ≡if (antecessor em H [no atual ] 6= NIL) H[antecessor em H [no atual ]] = H[no atual ];else /∗ O ponto removido e o menor na arvore. ∗/

menor no = H[no atual ];if (H[no atual ] 6= NIL) antecessor em H [H[no atual ]] = antecessor em H [no atual ];else /∗ O ponto removido e o maior na arvore. ∗/

maior no = antecessor em H [no atual ];

Codigo utilizado no trecho 64.

66. Fazemos duas intervencoes cirurgicas, que nao usam as primitivas ja escritas para manipulacao da arvore. Asaber: copiamos o valor do sucessor do ponto atual para ele (como e um no interno, sabemos que nao e o maximo,donde o seu sucessor nao e NIL); e tambem corrigimos o ponteiro do no para o seu sucessor (que passa a serH[H[no atual ]]). Para o resto contamos com as funcoes que ja escrevemos.

〈Estamos em um no interno (no atual ), que e o no a ser removido. Coloca o valor do sucessor de no atual emno atual e atualiza sucessor, remove o mınimo do filho maior do no atual ; retorna da rotina 66 〉 ≡

ponto [no atual ] = ponto [H[no atual ]];H[no atual ] = H[H[no atual ]];remove minimo de subarvore (filho maior [no atual ]);return;

Codigo utilizado no trecho 61.

67. 〈Variaveis locais de remove da arvore 67 〉 ≡int no atual , proximo no ;

Codigo utilizado no trecho 60.

26

Page 27: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

68. Inicializacao e incremento do fecho

La e de volta outra vez. Ca estamos, depois de uma pequena incursao pelos bosques rubro-negros. Se voce ainda serecorda do que estavamos a fazer algumas paginas atras, inicializar o fecho e colocar mais pontos nele nao ha de lhefazer cocar a cabeca. Se nao, talvez seja uma boa ideia bater os olhos no vocabulario que estivemos construindo.

Vamos compor o fecho inicial com pbaixo e palto.Um pouco estranhamente, se seguimos interpretando as coisas como temos feito a inicializacao de H como uma

lista circular fica estranha (porque subito pbaixo parece ser mınimo e maximo entre os vertices do fecho!). MasLembre-se de que pbaixo nunca e inserido na arvore, e entao jamais sera comparado aos outros pontos. Isso e aomesmo tempo uma salvacao e um alerta, porque pbaixo, apesar de tudo, pode ser um extremo da sequencia devertices vista por pnovo. . . Vamos sair desse aparente aperto com testes explıcitos para pbaixo (mais sobre isso embreve).

〈 Inicializa fecho e p novo , de modo que pontos < pnovo nao precisem mais ser analisados 68 〉 ≡inicializa arvore ( );insere (1);p novo = 2;

Codigo utilizado no trecho 19.

69. Vamos agora esmiucar como fazer o incremento do fecho. Descobrimos se o ponto deve entrar no fecho; busca-mos os extremos da aresta decisora; se pnovo deve entrar no fecho, removemos os pontos vistos por pnovo e inserimospnovo na arvore. Testamos explicitamente se as arestas (pbaixo, ponto [menor no ])) e (pbaixo, ponto [maior no ])) saovistas por pnovo.

Dividimos o incremento em tres casos. A aresta decisora define em qual deles estamos. Se o pnovo sera vizinhode pbaixo quando for acrescentado ao fecho, entao alguma das extremidades da aresta decisora (menor no da arestaou maior no da aresta ) sera NIL.

〈Coloca pnovo no fecho se necessario, removendo pontos que devem sair 69 〉 ≡printf ("Sera que %d entra no fecho?\n", p novo);〈Encontra a aresta decisora 70 〉printf ("Pontos da aresta decisora: (%d %d)\n",menor no da aresta ≡ N ? 0 : ponto [menor no da aresta ],

maior no da aresta ≡ N ? 0 : ponto [maior no da aresta ]);if (〈Ponto nao esta a direita estrita da aresta decisora 74 〉) {

while (menor no da aresta 6= NIL) {if (〈Aresta que termina em menor no da aresta e vista por pnovo 71 〉) {

printf ("A aresta que termina em %d e vista por %d.\n",menor no da aresta , p novo);no aux = antecessor em H [menor no da aresta ];printf ("opa<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # ## # . # # ###\n");remove da arvore (ponto [menor no da aresta ]);menor no da aresta = no aux ;

}else break;

}if (menor no da aresta ≡ NIL ∧ 〈Aresta que comeca em pbaixo e vista por pnovo 72 〉)

remove da arvore (ponto [menor no da aresta ]);while (maior no da aresta 6= NIL) {

if (〈Aresta que inicia em maior no da aresta e vista por pnovo 73 〉) {no aux = H[maior no da aresta ];remove da arvore (ponto [maior no da aresta ]);maior no da aresta = no aux ;

}else break;

}if (maior no da aresta ≡ NIL ∧ 〈Aresta que termina em pbaixo e vista por pnovo 75 〉)

remove da arvore (ponto [maior no da aresta ]);printf ("O ponto %d vai entrar no fecho.\n", p novo);insere (p novo);}else {

printf ("N~ao, n~ao entra.\n");

27

Page 28: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

}Codigo utilizado no trecho 19.

70. 〈Encontra a aresta decisora 70 〉 ≡no atual = raiz ;while (verdade ) {

if (menor (p novo , ponto [no atual ])) { /∗ pnovo ≺ ponto [no atual ]. ∗/if (filho menor [no atual ] 6= NIL) no atual = filho menor [no atual ];else {

menor no da aresta = antecessor em H [no atual ];maior no da aresta = no atual ;break;

}}else { /∗ pnovo � ponto [no atual ]. ∗/

if (filho maior [no atual ] 6= NIL) no atual = filho maior [no atual ];else {

menor no da aresta = no atual ;maior no da aresta = H[no atual ];break;

}}}

Codigo utilizado no trecho 69.

71. Sabemos que se pnovo e colinear a aresta que termina em menor no da aresta , ele nao pertence ao segmentoda aresta. Isso acontece pelo modo como a ordenacao foi definida. Se pnovo esta em alguma aresta qr do polıgono(q ≺ r) entao ponto [menor no da aresta ] � q e tambem r � ponto [maior no da aresta ]. Sendo assim, a “aresta quetermina em menor no da aresta” so e vista por pnovo se o ponto estiver a sua esquerda estrita.

A dita aresta inicia no ponto [antecessor em H [menor no da aresta ]], geralmente. Isso nao vale so quando omenor no da aresta e o menor no na arvore. Nesse caso, usamos esquerda estrita ( . . . ) (nao a versao geral) parausar o ponto zero (pbaixo) como referencia. Vamos usar uma estrategia analoga para o teste da aresta que inicia emmaior no da aresta .

〈Aresta que termina em menor no da aresta e vista por pnovo 71 〉 ≡((antecessor em H [menor no da aresta ] 6= NIL ∧

esquerda estrita geral (ponto [antecessor em H [menor no da aresta ]], p novo ,ponto [menor no da aresta ])) ∨ (antecessor em H [menor no da aresta ] ≡ NIL ∧ esquerda estrita (p novo ,ponto [menor no da aresta ])))

Codigo utilizado no trecho 69.

72. Esta e uma parte da condicao do item acima.

〈Aresta que comeca em pbaixo e vista por pnovo 72 〉 ≡(esquerda estrita (p novo , ponto [menor no da aresta ]))

Codigo utilizado no trecho 69.

73. Aqui testamos a direita estrita caso pbaixo esteja envolvido — e por isso alteramos a ordem dos parametrosda chamada.

〈Aresta que inicia em maior no da aresta e vista por pnovo 73 〉 ≡((H[maior no da aresta ] 6= NIL ∧ esquerda estrita geral (ponto [maior no da aresta ], p novo ,

ponto [H[maior no da aresta ]])) ∨ (H[maior no da aresta ] ≡ NIL ∧ direita estrita (p novo ,ponto [maior no da aresta ])))

Codigo utilizado no trecho 69.

28

Page 29: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

74. Atente que alguma das extremidades da aresta decisora pode ser NIL.

〈Ponto nao esta a direita estrita da aresta decisora 74 〉 ≡(¬direita estrita geral (ponto [menor no da aresta ] 6= NIL ? ponto [menor no da aresta ] : 0, p novo , ponto [maior no da aresta ] 6= NIL ? ponto [maior no da aresta ] : 0))

Codigo utilizado no trecho 69.

75. 〈Aresta que termina em pbaixo e vista por pnovo 75 〉 ≡(direita estrita (p novo , ponto [maior no da aresta ]))

Codigo utilizado no trecho 69.

76. 〈Variaveis locais de main 12 〉 +≡int menor no da aresta , maior no da aresta ;int no atual , no aux ;

29

Page 30: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

77. Algumas coisas que vou deixar aqui por enquanto

Talvez para lembrar no que e que eu estava pensando quando escrevi colineares. . .

〈 pnovo esta no segmento (0, H[0]) 77 〉 ≡(colineares (p novo , H[0]) ∧ (〈x-coordenadas estao na projecao no eixo x do segmento (0,H[0]) 78 〉∨ (〈x-coordenadas sao iguais, e as y-coordenadas estao na projecao no eixo x do segmento (0,H[0]) 79 〉)))

78. 〈x-coordenadas estao na projecao no eixo x do segmento (0,H[0]) 78 〉 ≡((X[0]+eps < X[p novo ]∧X[p novo ]+eps < X[H[0]])∨ (X[0] > X[p novo ]+eps ∧X[p novo ] > X[H[0]]+eps ))

Codigo utilizado no trecho 77.

79. 〈x-coordenadas sao iguais, e as y-coordenadas estao na projecao no eixo x do segmento (0,H[0]) 79 〉 ≡((fabs (X[0]−X[H[0]]) < eps ) ∧ (fabs (X[0]−X[p novo ]) < eps )∧ 〈 y-coordenadas estao na projecao no eixo x do segmento (0,H[0]) 80 〉)

Codigo utilizado no trecho 77.

80. 〈 y-coordenadas estao na projecao no eixo x do segmento (0,H[0]) 80 〉 ≡((Y [0] + eps < Y [p novo ]∧ Y [p novo ] + eps < Y [H[0]])∨ (Y [0] > Y [p novo ] + eps ∧ Y [p novo ] > Y [H[0]] + eps ))

Codigo utilizado no trecho 79.

30

Page 31: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

81. Gerando a saıda

A saıda do programa nao tem segredos. Imprimimos o numero da regiao, e a medida que imprimimos os pontosvamos calculando o perımetro, que e, por fim, impesso tambem.

Abaixo, no aux e no aux 2 apontam para nos da arvore, mas nos referimos a eles (com alguma licenca poetica)como pontos tambem, como em “distancia entre no aux e no aux 2 ”.

#define distancia (p1 , p2 ) /∗ Distancia entre pontos. ∗/(sqrt ((X[p2 ]−X[p1 ]) ∗ (X[p2 ]−X[p1 ]) + (Y [p2 ]− Y [p1 ]) ∗ (Y [p2 ]− Y [p1 ])))

〈 Imprime a resposta para a regiao 81 〉 ≡if (numero regiao > 1) printf ("\nRegion #%d:\n",numero regiao);else printf ("Region #%d:\n",numero regiao);printf ("(%.1f,%.1f)", X[0], Y [0]);perimetro = 0;no aux = 0;no aux 2 = menor no ;if (no aux 2 ≡ NIL) goto depois do while ; /∗ Arvore vazia. ∗/while (verdade ) {〈 Imprime no aux 2 82 〉perimetro += distancia (ponto [no aux 2 ], ponto [no aux ]);〈Avanca no aux . Sai do laco se no aux ≡ NIL, imprimindo o ponto 0 e incrementando o perımetro com a

aresta que fecha o polıgono 84 〉〈 Imprime no aux 83 〉perimetro += distancia (ponto [no aux 2 ], ponto [no aux ]);〈Avanca no aux 2 . Sai do laco se no aux 2 ≡ NIL, imprimindo o ponto 0 e incrementando o perımetro com a

aresta que fecha o polıgono 85 〉}

depois do while :printf ("\n%.2f\n", perimetro); /∗ Perımetro da regiao. ∗/

Codigo utilizado no trecho 7.

82. 〈 Imprime no aux 2 82 〉 ≡printf ("-(%.1f,%.1f)", X[ponto [no aux 2 ]], Y [ponto [no aux 2 ]]);

Codigo utilizado no trecho 81.

83. 〈 Imprime no aux 83 〉 ≡printf ("-(%.1f,%.1f)", X[ponto [no aux ]], Y [ponto [no aux ]]);

Codigo utilizado no trecho 81.

84. 〈Avanca no aux . Sai do laco se no aux ≡ NIL, imprimindo o ponto 0 e incrementando o perımetro com aaresta que fecha o polıgono 84 〉 ≡

no aux = H[no aux 2 ]; /∗ Avanca no aux . ∗/if (no aux ≡ NIL) {

printf ("-(%.1f,%.1f)", X[0], Y [0]);perimetro += distancia (0, ponto [no aux 2 ]);break;}

Codigo utilizado no trecho 81.

85. 〈Avanca no aux 2 . Sai do laco se no aux 2 ≡ NIL, imprimindo o ponto 0 e incrementando o perımetro coma aresta que fecha o polıgono 85 〉 ≡

no aux 2 = H[no aux ];if (no aux 2 ≡ NIL) {

printf ("-(%.1f,%.1f)", X[0], Y [0]);perimetro += distancia (0, ponto [no aux ]);break;}

Codigo utilizado no trecho 81.

31

Page 32: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

86. 〈Variaveis locais de main 12 〉 +≡int no aux 2 ;double perimetro ;int i;

87.#define AB printf ("[");imprime rac(raiz );printf (" -> ");

#define BA imprime rac(raiz );printf ("]\n");

#define C printf ("|%d",no atual );#define c(x) (eh rubro((x)) ? "R" : "N")#define FIX printf ("{%d,%s%s%s}",no atual , c(no atual ), c(filho menor [no atual ]), c(filho maior [no atual ]));

〈Funcoes 33 〉 +≡void imprime rec(int no){

if (no ≡ NIL) printf (".");else {

printf ("(");if (eh rubro(no)) printf ("R");else printf ("N");imprime rec(filho menor [no ]);imprime rec(filho maior [no ]);printf (")");

}}void imprime rac(int no){

if (no ≡ NIL) printf (" %d ",no);else {

printf ("(");printf ("%d ",no);imprime rec(filho menor [no ]);imprime rec(filho maior [no ]);printf (")");

}}void lis ( ){

int i, livre , max livre = NIL;

printf ("A Arvore\n");max livre = proxima posicao livre ;printf ("proxima_posicao_livre: %d, pai[ppl]=%d\n", proxima posicao livre , pai [proxima posicao livre ]);while (pai [max livre ] 6= NIL) max livre = pai [max livre ];i = 0;printf ("%7s", "i");while (i < max livre ) {〈 Incrementa o i enquanto e uma posicao vazia 88 〉printf ("%3d", i);++i;

}printf ("\n");i = 0;printf ("%7s", "ponto");while (i < max livre ) {〈 Incrementa o i enquanto e uma posicao vazia 88 〉printf ("%3d", ponto [i]);

32

Page 33: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

++i;}printf ("\n");i = 0;printf ("%7s", "menor");while (i < max livre ) {〈 Incrementa o i enquanto e uma posicao vazia 88 〉printf ("%3d",filho menor [i]);++i;

}printf ("\n");i = 0;printf ("%7s", "maior");while (i < max livre ) {〈 Incrementa o i enquanto e uma posicao vazia 88 〉printf ("%3d",filho maior [i]);++i;

}printf ("\n");i = 0;printf ("%7s", "pai");while (i < max livre ) {〈 Incrementa o i enquanto e uma posicao vazia 88 〉printf ("%3d", pai [i]);++i;

}printf ("\n");i = 0;printf ("%7s", "cor");while (i < max livre ) {〈 Incrementa o i enquanto e uma posicao vazia 88 〉printf ("%3s", eh rubro(i) ? "R" : "N");++i;

}printf ("\n");printf ("raiz: %d, menor no: %d (%.1f,%.1f), maior no: %d (%.1f,%.1f)\n", raiz ,menor no ,

X[ponto [menor no ]], Y [ponto [menor no ]],maior no , X[ponto [maior no ]], Y [ponto [maior no ]]);}

88. 〈 Incrementa o i enquanto e uma posicao vazia 88 〉 ≡livre = proxima posicao livre ;while (pai [livre ] 6= NIL) {

if (i ≡ livre ) {++i;livre = proxima posicao livre ;continue;

}livre = pai [livre ];}

Codigo utilizado no trecho 87.

89. 〈Funcoes 33 〉 +≡void las ( ){

int i, livre , max livre = 10;

33

Page 34: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

printf ("A Arvore (las)\n");printf ("proxima_posicao_livre: %d, pai[ppl]=%d\n", proxima posicao livre , pai [proxima posicao livre ]);i = 0;printf ("%7s", "i");while (i < max livre ) {

printf ("%3d", i);++i;

}printf ("\n");i = 0;printf ("%7s", "ponto");while (i < max livre ) {

printf ("%3d", ponto [i]);++i;

}printf ("\n");i = 0;printf ("%7s", "menor");while (i < max livre ) {

printf ("%3d",filho menor [i]);++i;

}printf ("\n");i = 0;printf ("%7s", "maior");while (i < max livre ) {

printf ("%3d",filho maior [i]);++i;

}printf ("\n");i = 0;printf ("%7s", "pai");while (i < max livre ) {

printf ("%3d", pai [i]);++i;

}printf ("\n");i = 0;printf ("%7s", "cor");while (i < max livre ) {

printf ("%3d", cor [i]);++i;

}printf ("\n");printf ("raiz: %d, menor no: %d (%.1f,%.1f), maior no: %d (%.1f,%.1f)\n", raiz ,menor no ,

X[ponto [menor no ]], Y [ponto [menor no ]],maior no , X[ponto [maior no ]], Y [ponto [maior no ]]);}

90. 〈Pre-declaracao de funcoes 34 〉 +≡void imprime rec(int no);void imprime rac(int no);void lis ( );void las ( );void double libera ( );

91. 〈Funcoes 33 〉 +≡void double libera (int no) /∗ imprime mensagem de erro e aborta se dupla liberacao. ∗/

34

Page 35: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

{int livre ;

livre = proxima posicao livre ;while (pai [livre ] 6= NIL) {

if (no ≡ livre ) {fprintf (stderr , "EI EI EI EI! Tentaram liberar um no (4) que ja estava livre! T^o fora.\n");lis ( );exit (1);

}livre = pai [livre ];

}}

35

Page 36: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

Indice Remissivo

AB: 87.antecessor : 9, 13, 21, 30.antecessor em H : 9, 13, 29, 30, 31, 41, 42, 43,

54, 65, 69, 70, 71.antecessor em H estatico : 29, 31.argc : 7.argv : 7.aumenta tamanho arvore : 31, 33.BA: 87.BLOBDIGNAG: 45.C: 87.c: 87.colineares : 21, 77.colineares geral : 21.cor : 28, 29, 31, 43, 44, 45, 47, 49, 89.cor estatico : 29, 31.depois do while : 81.direita estrita : 21, 73, 75.direita estrita geral : 21, 74.distancia : 81, 84, 85.double libera : 33, 90, 91.eh negro : 28, 53, 57, 61, 63.eh rubro : 28, 45, 51, 53, 61, 87.eps : 21, 23, 24, 25, 78, 79, 80.esquerda estrita : 21, 71, 72.esquerda estrita geral : 21, 71, 73.exit : 91.fabs : 21, 22, 23, 24, 25, 79.fflush : 7.filho maior : 29, 31, 39, 43, 44, 45, 47, 49, 50, 51,

52, 53, 54, 60, 61, 64, 66, 70, 87, 89.filho maior estatico : 29, 31.filho menor : 29, 31, 35, 39, 43, 44, 45, 47, 49, 51,

52, 53, 57, 58, 61, 63, 64, 70, 87, 89.filho menor estatico : 29, 31.filhos menores : 52.FIX: 87.fprintf : 91.free : 14, 31.geral : 21.getchar : 45.H: 29.H estatico : 29, 31.i: 86, 87, 89.imprime rac : 87, 90.imprime rec : 87, 90.inicializa arvore : 31, 68.insere : 38, 68, 69.las : 89, 90.libera arvore : 18, 31.libera no : 33, 54, 58, 64.libera pontos : 13, 14, 18.lis : 19, 45, 87, 90, 91.livre : 87, 88, 89, 91.main : 7.maior no : 29, 31, 42, 43, 54, 58, 64, 65, 69, 87, 89.maior no da aresta : 69, 70, 71, 73, 74, 75, 76.malloc : 13, 31.

math : 22.max livre : 87, 89.memcpy : 31, 32.menor : 21, 40, 62, 70.menor no : 29, 31, 41, 43, 54, 58, 64, 65, 69,

81, 87, 89.menor no da aresta : 69, 70, 71, 72, 74, 76.move rubro para maior : 51, 53, 60, 61.move rubro para menor : 51, 57, 61, 63.N : 6.negro : 28, 29, 35, 43, 45.NIL: 28, 29, 30, 31, 33, 35, 38, 39, 41, 42, 43, 44,

45, 47, 52, 53, 54, 56, 57, 58, 60, 61, 64, 65, 66,69, 70, 71, 73, 74, 81, 84, 85, 87, 88, 91.

no : 21, 33, 51, 52, 53, 56, 57, 87, 90, 91.no atual : 38, 39, 40, 41, 42, 44, 45, 46, 50, 52,

53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,65, 66, 67, 70, 76, 87.

no aux : 69, 76, 81, 83, 84, 85.no aux 2 : 81, 82, 84, 85, 86.no livre : 31, 33, 34, 39, 43.numero regiao : 6, 7, 81.outra cor : 49.p: 47, 48.p alto : 10, 11, 16, 17, 24.p baixo : 10, 11, 16, 17, 23.p novo : 11, 12, 19, 23, 24, 38, 39, 40, 43, 44, 68, 69,

70, 71, 72, 73, 74, 75, 77, 78, 79, 80.p sai : 60, 61, 62.pai : 29, 31, 33, 37, 43, 44, 45, 47, 53, 57, 64,

87, 88, 89, 91.pai estatico : 29, 31.perimetro : 81, 84, 85, 86.ponto : 21, 29, 30, 31, 39, 40, 43, 44, 45, 61, 62, 66,

69, 70, 71, 72, 73, 74, 75, 81, 82, 83, 84, 85, 87, 89.ponto estatico : 29, 31.printf : 7, 9, 39, 45, 61, 69, 81, 82, 83, 84, 85, 87, 89.produto interno : 21.produto interno geral : 21.proxima posicao livre : 31, 33, 87, 88, 89, 91.proximo no : 39, 41, 42, 44, 45, 46, 53, 54, 55,

57, 58, 59, 67.pto : 21.p1 : 21, 81.p2 : 21, 81.q: 47.raiz : 28, 31, 38, 43, 45, 60, 64, 70, 87, 89.realloc : 31.ref : 21.remove da arvore : 60, 69.remove maximo de subarvore : 52.remove minimo de subarvore : 56, 60, 66.resposta : 33.rotaciona maior : 45, 47, 48, 51, 53, 61.rotaciona menor : 45, 47, 48, 51.rubro : 28, 29, 35, 44, 47, 50.rubros : 35.scanf : 7, 9, 10, 11.

36

Page 37: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

sentidos opostos : 21.sqrt : 81.stderr : 91.stdin : 7.sucessor : 9, 19, 21, 30.tamanho arvore : 31, 33.tamanho inicial arvore : 29, 31.tamanho inicial fecho : 13, 29.tamanho inicial pontos : 13, 14, 15.tamanho pontos : 13, 14, 15.troca cores : 45, 49, 51.verdade : 38, 52, 56, 60, 70, 81.X: 15.x aux : 16, 17.X estatico : 14, 15.Y : 15.y aux : 16, 17.Y estatico : 14, 15.

37

Page 38: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

Lista de trechos

〈 pnovo ≺ ponto [no atual ] 40 〉 Utilizado no trecho 39.

〈 psai ≺ ponto [no atual ] 62 〉 Utilizado no trecho 61.

〈x-coordenadas estao na projecao no eixo x do segmento (0,H[0]) 78 〉 Utilizado no trecho 77.

〈x-coordenadas sao iguais, e as y-coordenadas estao na projecao no eixo x do segmento (0,H[0]) 79 〉 Utilizado no

trecho 77.

〈 y-coordenadas estao na projecao no eixo x do segmento (0,H[0]) 80 〉 Utilizado no trecho 79.

〈Aloca espaco para X e Y ; para o programa em caso de erro 13 〉 Utilizado no trecho 9.

〈Altera apontadores de antecessor e sucessor para inclusao do filho maior 42 〉 Utilizado no trecho 39.

〈Altera apontadores de antecessor e sucessor para inclusao do filho menor 41 〉 Utilizado no trecho 39.

〈Aresta que comeca em pbaixo e vista por pnovo 72 〉 Utilizado no trecho 69.

〈Aresta que inicia em maior no da aresta e vista por pnovo 73 〉 Utilizado no trecho 69.

〈Aresta que termina em pbaixo e vista por pnovo 75 〉 Utilizado no trecho 69.

〈Aresta que termina em menor no da aresta e vista por pnovo 71 〉 Utilizado no trecho 69.

〈Arquivos de cabecalho 8, 22, 32 〉 Utilizado no trecho 5.

〈Avanca no aux 2 . Sai do laco se no aux 2 ≡ NIL, imprimindo o ponto 0 e incrementando o perımetro com aaresta que fecha o polıgono 85 〉 Utilizado no trecho 81.

〈Avanca no aux . Sai do laco se no aux ≡ NIL, imprimindo o ponto 0 e incrementando o perımetro com a arestaque fecha o polıgono 84 〉 Utilizado no trecho 81.

〈Caminha pela arvore buscando psai, e removendo-o se encontrado. Conserta a arvore e retorna. 61 〉 Utilizado no

trecho 60.

〈Coloca pnovo no fecho se necessario, removendo pontos que devem sair 69 〉 Utilizado no trecho 19.

〈Conserta o que foi baguncado 45 〉 Citado no trecho 37. Utilizado nos trechos 38, 52, 56 e 64.

〈Constantes e variaveis globais 6, 15, 28, 29, 31 〉 Utilizado no trecho 5.

〈Encontra a aresta decisora 70 〉 Utilizado no trecho 69.

〈Encontra o fecho convexo da regiao 19 〉 Utilizado no trecho 9.

〈Estamos em um no interno (no atual ), que e o no a ser removido. Coloca o valor do sucessor de no atual emno atual e atualiza sucessor, remove o mınimo do filho maior do no atual ; retorna da rotina 66 〉 Utilizado no

trecho 61.

〈Estamos em uma folha (no atual ), que e o no a ser removido. Remove no atual e percorre a arvore “ao contrario”,consertando o que houver de errado; retorna da rotina 64 〉 Utilizado no trecho 61.

〈Funcoes 33, 38, 47, 51, 52, 56, 60, 87, 89, 91 〉 Utilizado no trecho 5.

〈 Imprime a resposta para a regiao 81 〉 Utilizado no trecho 7.

〈 Imprime no aux 2 82 〉 Utilizado no trecho 81.

〈 Imprime no aux 83 〉 Utilizado no trecho 81.

〈 Incrementa o i enquanto e uma posicao vazia 88 〉 Utilizado no trecho 87.

〈 Inicializa fecho e p novo , de modo que pontos < pnovo nao precisem mais ser analisados 68 〉 Utilizado no trecho 19.

〈 Insere pnovo na arvore vazia 43 〉 Utilizado no trecho 38.

〈 Insere pnovo na folha 44 〉 Utilizado no trecho 38.

〈Le o segundo ponto e inicializa ındices pbaixo e palto 10 〉 Utilizado no trecho 9.

〈Le os demais pontos, mantendo pbaixo e palto apontando para os pontos certos 11 〉 Utilizado no trecho 9.

〈Leitura e processamento do registro da regiao 9 〉 Utilizado no trecho 7.

〈Libera memoria alocada 18 〉 Utilizado no trecho 7.

〈Liga antecessor em H [no atual ] a H[no atual ] e vice-versa 65 〉 Utilizado no trecho 64.

〈O ponto 0 tem y-coordenada menor do que a do ponto 1, ou ambos tem mesma y-coordenada mas 0 temx-coordenada menor 25 〉 Utilizado no trecho 10.

〈Ponto pnovo deve entrar no lugar de palto 24 〉 Utilizado no trecho 11.

〈Ponto pnovo deve entrar no lugar de pbaixo 23 〉 Utilizado no trecho 11.

〈Ponto nao esta a direita estrita da aresta decisora 74 〉 Utilizado no trecho 69.

〈Pre-declaracao de funcoes 34, 48, 90 〉 Utilizado no trecho 5.

〈Remove o maximo (proximo no) 54 〉 Citado no trecho 58. Utilizado no trecho 52.

〈Remove o mınimo (proximo no) 58 〉 Utilizado no trecho 56.

〈Rotina principal 7 〉 Utilizado no trecho 5.

〈Segue a busca pelo maximo, garantindo nunca estar em um 2-no. Sai do loop garantindo proximo no ≡filho maior [no atual ] e o maximo 53 〉 Utilizado no trecho 52.

〈Segue a busca pelo mınimo, garantindo nunca estar em um 2-no. Sai do loop garantindo proximo no ≡filho menor [no atual ] e o mınimo 57 〉 Utilizado no trecho 56.

38

Page 39: Exterm nio de mariposastassio/arquivo/2011-ii/webs/5-moth-eradication/... · uxo de mariposas de julho em uma dada regi~ao do planeta. A inten˘c~ao e estudar programas de exterm

〈Segue a busca, avancando no atual . Prepara a insercao em uma folha de no atual e escapa do loop 39 〉 Utilizado

no trecho 38.

〈Troca pbaixo e 0 de posicao e tambem palto e 1 em X[ ] e Y [ ] 16 〉 Utilizado no trecho 9.

〈Variaveis locais de insere 46 〉 Utilizado no trecho 38.

〈Variaveis locais de main 12, 17, 76, 86 〉 Utilizado no trecho 7.

〈Variaveis locais de remove da arvore 67 〉 Utilizado no trecho 60.

〈Variaveis locais de remove maximo de subarvore 55 〉 Utilizado no trecho 52.

〈Variaveis locais de remove minimo de subarvore 59 〉 Utilizado no trecho 56.

〈 pnovo esta no segmento (0, H[0]) 77 〉〈 “Empurra” um link rubro para o filho menor se necessario, e prossegue para esse filho. 63 〉 Utilizado no trecho 61.

39