ALGUMAS ESTRUTURAS MATEMÁTICAS BÁSICAS PARA A CIÊNCIA DA COMPUTAÇÃO Bruno Maffeo Departamento de Informática PUC-Rio CONJUNTOS DEFINIÇÕES BÁSICAS O conceito de conjunto associa-se ao modelo de dados mais fundamental da Ciência da Computação. Mais freqüentemente, devido a seu elevado nível de abstração, associa-se ao modelo conceitual de uma realidade em estudo. Qualquer conceito associado a modelagem de dados, de árvores a números reais, pode ser expresso matematicamente como um tipo especial de conjunto. Assim, por referir-se tanto à modelagem conceitual quanto ao design de sistemas de software, não é surpreendente que conjunto seja um conceito fundamental em Ciência da Computação. Como no caso de “ponto” e “reta” em Geometria, em Matemática, o termo “conjunto” não é definido de maneira explícita. Assim sendo, um conjunto específico será definido seja através da enumeração de seus membros, seja através das propriedades que seus membros possuem em comum. A noção de pertinência, especificamente, só faz sentido no caso de conjuntos. Quando C é um conjunto e x representa uma coisa qualquer, é possível a pergunta: “O valor de x é membro do conjunto C?”. O conjunto C será constituído por todos os valores de x para os quais a resposta a essa pergunta for afirmativa. Os itens a seguir resumem notações importantes para referir-se a conjuntos. ♦ A fórmula x ∈ C indica, quando seu valor é VERDADEIRO, que o valor representado por x é um membro do conjunto C. ♦ Se x 1, x 2, ... , x n são todos membros do conjunto C, pode-se escrever C = {x 1, x 2, ... , x n}. Aqui, cada um dos valores de x é distinto, não sendo permitida mais de uma ocorrência de um valor em um conjunto. Além disso, é irrelevante a ordem de ocorrência dos valores entre as chaves. ♦ O conjunto vazio, denotado por ∅, é o conjunto que não possui membros. Isto é, x ∈ ∅ é falso para todo valor de x. ⇒ exemplos ♦ Seja C = {1, 3, 6}, isto é, o conjunto C possui como membros os números inteiros 1, 3 e 6 e nada mais. Pode-se escrever 1 ∈ C, 3 ∈ C e 6 ∈ C. Entretanto, a fórmula 2 ∈ C tem valor FALSO, da mesma forma que teria para qualquer número distinto de 1, de 3 e de 6. ♦ Conjuntos também podem ser membros de conjuntos. Seja D = {{1, 2}, 3, ∅}. Neste caso, D possui três membros: o conjunto {1, 2}, o número inteiro 3 e o conjunto vazio ∅. São verdadeiras as fórmulas: {1, 2} ∈ D, 3 ∈ D e ∅ ∈ D. Entretanto, a fórmula 1 ∈ D tem valor FALSO, pois, mesmo sendo membro de um membro de D, 1 não é membro do próprio D. Conjuntos e Seqüências B. Maffeo página 2 de 32 ÁTOMOS Na teoria formal de conjuntos, nada existe além de conjuntos. Entretanto, na teoria informal de conjuntos aqui apresentada, bem como na definição de estruturas de dados que implementam conjuntos e de algoritmos que implementam operações sobre conjuntos, é conveniente assumir a existência de átomos, elementos que não são conjuntos e que podem ser membros de conjuntos. É importante lembrar que embora não possua membros, da mesma forma que um átomo, o conjunto vazio, ∅, é um conjunto e não um átomo. Será adotada a convenção de que números inteiros e letras minúsculas denotam átomos. Ao abordar estruturas de dados, é conveniente, com freqüência, utilizar tipos de dados complexos, estruturados, como tipos de átomos. Assim, átomos podem ter a estrutura de registro ou de arranjo. DEFINIÇÃO DE CONJUNTO POR MEIO DE PROPRIEDADE A enumeração de seus membros não é a única forma de definir conjuntos. Com freqüência, é mais conveniente começar com algum conjunto C e alguma propriedade de membros representada por um predicado P e definir o conjunto dos membros de C que possuem a propriedade representada por P. A notação para essa operação, denominada abstração, é {x | x ∈ C ∧ P (x)}, que designa a expressão “x é uma variável tal que os valores do seu domínio são membros do conjunto C e possuem a propriedade representada por P”. O símbolo ∧ designa o operador lógico AND. A expressão {x | x ∈ C ∧ P (x)} é dita um construtor de conjunto. A variável x, nesse construtor, é local à expressão, conseqüentemente, para descrever o mesmo conjunto, poderia ser utilizada a expressão {y | y ∈ C ∧ P (y)} . ⇒ exemplos ♦ Seja C = {1, 3, 6} e É_ímpar o predicado que representa a propriedade “é ímpar”. Assim, {x | x ∈ C ∧ É_ímpar (x)} é outra maneira de definir o conjunto {1, 3}. Isto é, aceita-se os elementos 1 e 3 por serem ímpares e rejeita-se (abstrai-se) 6 por ser par. ♦ Seja D = {{1, 2}, 3, ∅}. Então, {A | A ∈ D ∧ É_conjunto (A)} denota o conjunto {{1, 2}, ∅}. ♦ Seja o conjunto de números inteiros não negativos (ou “números naturais”), freqüentemente denotado por N. Seja É_primo o predicado que representa a propriedade que caracteriza um número primo isto é, um número inteiro maior do que 1 que não possui divisor além de 1 e de si mesmo . Então, o conjunto de números primos é denotado por {x | x ∈ N ∧ É_primo (x)}. Essa expressão denota o conjunto infinito {1, 3, 5, 7, 11, ...}. Conjuntos e Seqüências B. Maffeo página 3 de 32 CONJUNTOS INFINITOS É confortável pensar que conjuntos possuem cardinalidade finita, isto é, que existe algum número inteiro n particular de maneira que o conjunto em questão possui exatamente n membros. Por exemplo, o conjunto {1, 3, 6} possui três membros. Alguns conjuntos, entretanto, são infinitos, o que significa que não há um número inteiro que estabeleça limite para o número de membros do conjunto. Comumente, são conhecidos: N, Z, R, C, o conjunto dos números inteiros não negativos o conjunto dos números inteiros negativos e não negativos o conjunto dos números reais o conjunto dos números complexos. A partir desses, é possível construir, por abstração, outros conjuntos infinitos. ⇒ exemplos O construtor {x | x ∈ Z ∧ x < 3} acrescido de 0, 1 e 2. designa o conjunto de todos os números inteiros negativos O construtor {x | x ∈ Z ∧ x 1/2 ∈ Z} representa o conjunto de todos os números inteiros que são quadrados perfeitos, ou seja {0, 1, 4, 9, 16, ...}. OPERAÇÕES BÁSICAS SOBRE CONJUNTOS União, Interseção e Diferença ♦ A união de dois conjuntos C e D, denotada por C ∪ D, é o conjunto que contém membros encontrados em C, em D ou em ambos. Formalmente: C ∪ D = {x | x ∈ C ∨ x ∈ D} , onde símbolo ∨ designa o operador lógico OR. ♦ A interseção de dois conjuntos C e D, denotada por C ∩ D, é o conjunto que contém os membros encontrados em C e em D. Formalmente: C ∩ D = {x | x ∈ C ∧ x ∈ D} . ♦ A diferença entre dois conjuntos C e D, denotada por C − D, é o conjunto que contém os membros encontrados em C, mas não em D. Formalmente: C − D = {x | x ∈ C ∧ ¬ x ∈ D} , onde símbolo ¬ designa o operador lógico NOT. ⇒ exemplos Seja C = {1, 2, 3} e D = {3, 4, 5}. Então C ∪ D = {1, 2, 3, 4, 5}, C ∩ D = {3} e C − D = {1, 2}. Conjuntos e Seqüências B. Maffeo página 4 de 32 Diagramas de Venn Freqüentemente, é útil representar as operações envolvendo conjuntos através de figuras denominadas Diagramas de Venn. Um Diagrama de Venn reproduzindo dois conjuntos, C e D, cada um deles representado por uma elipse, é exibido pela figura a seguir. As duas elipses dividem o plano em quatro regiões, numeradas de 1 a 4. 1. a região 1 representa os elementos que não estão, seja em C, seja em D. 2. a região 2 representa C − D, membros em C que não estão em D. região 1 C D região 2 região 3 região 4 3. a região 3 representa C ∩ D, membros que estão em C e em D. 4. a região 4 representa D − C, membros em D que não estão em C. 5. as regiões 2, 3 e 4, combinadas representam C ∪ D, membros que estão em C, em D ou em ambos. Conjuntos e Seqüências B. Maffeo página 5 de 32 SUBCONJUNTOS Há uma família de operadores de comparação entre subconjuntos análoga à família existente para números. Sejam C e D conjuntos. ♦ Diz-se que C ⊆ D quando todo membro de C é, também, membro de D. Em linguagem corrente, diz-se que "C é um subconjunto de D" ou "D contém C". Formalmente: C ⊆ D ↔ ∀x ( x ∈ C → x ∈ D ) , onde símbolo → designa o operador lógico de implicação e o símbolo ∀ designa o quantificador universal da lógica. ♦ Diz-se que C ⊂ D quando C ⊆ D e existe pelo menos um membro de D que não é membro de C. A relação C ⊂ D pode ser expressa, igualmente, através de: "C é um subconjunto próprio de D" ou "D é um superconjunto próprio de C" ou "C está propriamente contido em D" ou, ainda, "D contém propriamente C". Formalmente: C ⊂ D ↔ ∀x ( x ∈ C → ( x ∈ D ∧ ∃y (y ∈ D ∧ ¬ y ∈ C ) ) , onde o símbolo ∃ designa o quantificador existencial da lógica. De maneira análoga à relação "menor do que", é possível inverter o sentido dos operadores: C ⊃ D é sinônimo de D ⊂ C e C ⊇ D é sinônimo de D ⊆ C. ⇒ exemplo ♦ As seguintes comparações são verdadeiras: • {1, 2} ⊆ {1, 2, 3} • {1, 2} ⊂ {1, 2, 3} • {1, 2} ⊆ {1, 2} ♦ A próxima, entretanto, é falsa: • {1, 2} ⊂ {1, 2} A seguir, algumas leis algébricas que envolvem operadores de comparação. ♦ ∅ ⊆ C, para qualquer conjunto C. ♦ Se C ⊆ D, então: • (C ∪ D) ≡ D • (C ∩ D) ≡ C • (C − D) ≡ ∅. Conjuntos e Seqüências B. Maffeo página 6 de 32 CONJUNTO POTÊNCIA DE UM CONJUNTO Seja C um conjunto qualquer. O conjunto potência de C é o conjunto dos subconjuntos de C, denotado por P (C). Formalmente: P (C) = { X | X ⊆ C } . ⇒ exemplos ♦ Seja C = {1, 2, 3}. Então, P (C) = {∅, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}} ♦ P (∅) = {∅} Note-se que {∅}, conjunto unitário que contém o conjunto vazio, não é equivalente a ∅, conjunto que não possui membros. Cardinalidade de um Conjunto Potência Se C possui n membros, então P (C) possui 2n membros, tal como é demonstrado a seguir para C = {a1, a2, ... , an} , empregando indução sobre n. base Se n = 0, então C = ∅ e P (∅) é um conjunto unitário, logo, a cardinalidade de P (C) é dada por 2n. passo indutivo Considera-se verdadeira a hipótese indutiva: com C = {a1, a2, ... , an}, a cardinalidade de P (C) é dada por 2n. Seja an+1 um novo membro e seja D = C ∪ {an+1} um conjunto com n + 1 membros. Um subconjunto de D possui ou não o membro an+1. Assim, considera-se as duas possibilidades: ♦ Os subconjuntos de D que não possuem an+1 são, também, subconjuntos de C e, por definição, são membros de P (C). Pela hipótese indutiva, o número desses subconjuntos é dado exatamente por 2n. ♦ Se F for um subconjunto de D que inclua an+1, seja G = F − {an+1}; isto é, G é obtido de F removendo-se o membro an+1. Pela hipótese indutiva, existem 2n subconjuntos do tipo de G, cada um deles correspondendo-se com um único conjunto do tipo F, posto que F = G ∪ {an+1}. Conclui-se que existem exatamente 2 × 2n, ou 2n+1 subconjuntos de D, metade constituída de subconjuntos de C e metade formada por um subconjunto de C acrescido do membro an+1. Dessa forma, provou-se o passo indutivo: dado que qualquer conjunto C de n membros possui 2n subconjuntos, mostrou-se que qualquer conjunto contendo n + 1 membros possui 2n+1 subconjuntos. Conjuntos e Seqüências B. Maffeo página 7 de 32 DICIONÁRIO Uma atividade comum, refletida em um grande número de programas de computador, consiste na manutenção de um conjunto de valores sobre o qual deseja-se: ♦ inserir elementos ♦ retirar elementos ♦ verificar se um dado elemento faz parte desse conjunto. Um exemplo é o de um dicionário de palavras em Inglês onde, de tempos em tempos, é inserida uma nova palavra, tal como fax, é retirada uma palavra que caiu em desuso, como aegilops, ou é verificado se uma determinada cadeia de letras é ou não uma palavra (como parte de um programa de verificação ortográfica, por exemplo). Em virtude desse exemplo familiar, denomina-se dicionário um conjunto sobre o qual são executadas as operações inserir, suprimir e buscar, independentemente do tipo dos elementos do conjunto. Como outro exemplo de dicionário, é possível considerar a “lista de presença” de uma disciplina: ocasionalmente, um estudante será acrescentado à turma (uma inserção), será retirado dela (uma supressão) ou terá sua alocação verificada (uma busca). Visando-se à realização eficiente dessas operações básicas, um dos temas primordiais em Ciência da Computação é uma boa escolha de design ou seja, do modelo de dados no caso de ser necessário implementar um dicionário. Conjuntos e Seqüências B. Maffeo página 8 de 32 SEQÜÊNCIAS Denomina-se seqüência a estrutura matemática linear na qual os itens que a compõem mantêm um posicionamento relativo bem definido. Embora a notação para seqüências, (x 1, x 2, ... , x n), e a notação para conjuntos, {x 1, x 2, ... , x n}, sejam muito semelhantes, há diferenças significativas entre os dois conceitos. Em primeiro lugar, a ordem dos membros de um conjunto é irrelevante O conjunto {1, 2} pode ser igualmente denotado por {2, 1}. Opostamente, a seqüência (1, 2) é diferente da seqüência (2, 1). Em segundo lugar, qualquer elemento pode ocorrer mais de uma vez, mantendo sua individualidade, em uma seqüência; essa individualidade é estabelecida pela posição relativa ocupada pela ocorrência específica do elemento. A seqüência (1, 2, 2), por exemplo, possui três elementos: O primeiro é 1, o segundo é 2 e o terceiro é, também, 2. Já a notação {1, 2, 2} não faz sentido pois não pode haver mais de uma ocorrência de membro em um conjunto. Se fizesse sentido, essa notação denotaria o mesmo conjunto denotado por {1, 2} ou {2, 1}. Algumas vezes, há referência ao conceito de multiconjunto, ou bolsa, que é um conjunto onde qualquer membro pode ocorrer mais de uma vez, isto é, cada membro possui uma multiplicidade associada. Seria possível, por exemplo, falar de um multiconjunto que contivesse 1 uma vez e 2 duas vezes. Multiconjuntos, entretanto, não são o mesmo que seqüências pois não admitem qualquer relação posicional entre seus membros. Assim como se admite a noção de conjunto vazio, denotado pelo símbolo ∅, admite-se a ocorrência de seqüência vazia, denotada pelo símbolo seq-vazia, correspondendo a uma seqüência que não possui itens. OPERAÇÕES BÁSICAS SOBRE SEQÜÊNCIAS Cabeça, Cauda e Insere ♦ A função cabeça (seq) retorna o item, denominado cabeça, situado na primeira posição da seqüência seq. ♦ A função cauda (seq) retorna a seqüência, denominada cauda, constituída pela seqüência seq da qual é retirado o cabeça ♦ A função insere (item, seq) retorna a seqüência constituída pelo valor de seq no qual estará inserido o valor de item na primeira posição ⇒ exemplos Seja seq = (1, 2, 3) e item = 5. Então cabeça (seq) = 1, cauda (seq) = {2, 3} e insere (item, seq) = {5, 1, 2, 3}. Conjuntos e Seqüências B. Maffeo página 9 de 32 BIBLIOGRAFIA UTILIZADA Foundations of Computer Science Alfred V. Aho e Jeffrey D. Ullman ( Computer Science Press, 1992 ) seções: 7.2, 7.3, 7.4, 7.5, 7.6 Conjuntos e Seqüências B. Maffeo página 10 de 32 RELAÇÕES DEFINIÇÕES BÁSICAS Geralmente, considera-se que são atômicos (sem estrutura) os elementos de um conjunto. Entretanto, na prática, é útil considerar tais elementos como possuindo alguma estrutura. Por exemplo, numa aplicação clássica do tipo dicionário, considera-se que os membros do conjunto relevante, as palavras dicionarizadas, são cadeias de caracteres. Referindo-se a outras realidades, será conveniente o uso de tuplas para representar os membros do conjunto. Este será o caso, por exemplo, em uma aplicação do tipo dicionário relativa a alunos de uma universidade, a respeito dos quais deseja-se registrar informações de distintas categorias (por exemplo: nome, endereço, telefone, …). Tupla Uma seqüência de elementos será chamada de tupla e cada elemento da seqüência será chamado de componente. O número de componentes de uma tupla é chamado de aridade. Por exemplo, (a, b) é uma tupla de aridade 2. Seu primeiro componente é a e seu segundo componente é b. De um modo geral, tupla é o modelo matemático apropriado para cada membro de um conjunto cujos membros: ♦ possuem uma mesma estrutura ♦ essa estrutura é uma seqüência. Relação Um conjunto de elementos, cada um deles sendo uma tupla e todos possuindo a mesma aridade seja k é denominado relação. A aridade da relação é k. Uma tupla, ou relação, de aridade 1 é dita unária. Se a aridade for 2, será dita binária e, em geral, se a aridade for k, será dita k-ária. Uma tupla de aridade k é também chamada k-tupla. ⇒ exemplo A relação R = {(1, 2), (1, 3), (2, 2)} tem aridade 2, ou seja, é uma relação binária. Seus elementos são (1, 2), (1, 3) e (2, 2), cada um deles sendo uma tupla de aridade 2. Relações e Funções B. Maffeo página 11 de 32 PRODUTO CARTESIANO Um produto cartesiano é uma operação definida sobre conjuntos. Sejam os conjuntos A e B. O produto cartesiano de A e B, denotado por A × B, é definido como o conjunto de todos os pares nos quais o primeiro componente é escolhido de A e o segundo, de B. Assim, A × B = {(a, b) | a ∈ A ∧ b ∈ B} Se A e B são conjuntos finitos de cardinalidade m e n, respectivamente, a cardinalidade de A × B é mn. ⇒ exemplos ♦ considerando que o símbolo Z denota, convencionalmente, o conjunto de todos os números inteiros, Z × Z representa o conjunto de todos os pares de números inteiros ♦ se A = {1, 2} e B = {a, b, c}, então A × B = {(1, a), (1, b), (1, c), (2, a), (2, b), (2, c)} RELAÇÕES BINÁRIAS Uma relação binária R é um conjunto de pares que é subconjunto do produto cartesiano de dois conjuntos. Formalmente, sendo esses conjuntos A e B : R ⊆ A × B . Se a relação R é um subconjunto de A × B, diz-se que R é de A para B. O conjunto A constitui o domínio e o conjunto B constitui a imagem da relação. Se B coincide com A, diz-se que R é uma relação sobre A ou sobre o domínio de A. ⇒ exemplos ♦ A relação aritmética < sobre os números inteiros é um subconjunto de Z × Z consistindo nos pares (a, b) tais que o valor de a é menor do que o valor de b. Assim, o símbolo < pode ser entendido como o nome do conjunto {(a, b) | (a, b) ∈ Z × Z ∧ (o valor de a é menor do que o valor de b)}. Usa-se a abreviatura a < b significando “(a, b) ∈ <” . As demais relações aritméticas sobre números inteiros, tais como > ou ≤ , podem ser definidas analogamente. Da mesma forma, as comparações sobre números reais. Relações e Funções B. Maffeo página 12 de 32 ♦ Seja R = {(1, 2), (1, 3), (2, 2)}. São incertos o domínio e a imagem dessa relação. Certamente, 1 e 2 pertencem ao domínio de R, pois aparecem como primeiros componentes das tuplas em R. Analogamente, a imagem de R deve incluir 2 e 3. Entretanto, é possível ver R como uma relação de {1, 2} para {2, 3} ou como uma relação sobre Z, dois exemplos tomados dentre uma infinidade de escolhas possíveis. O segundo exemplo indica que o uso consistente dos conceitos aqui apresentados exige que sejam especificados o domínio e a imagem da relação considerada. Notação In-Fixada para Relações Binárias É comum o uso da notação in-fixada para representar a fórmula que indica a pertinência de um dado elemento a uma relação binária. Assim, as fórmulas 1 < 2 e 4 ≥ 4 são usadas, normalmente, no lugar das escolhas mais rebuscadas (1, 2) ∈ < e (4, 4) ∈ ≥ . ⇒ exemplo A mesma notação pode ser usada para relações binárias quaisquer e, no caso do exemplo anterior, a relação R poderia ser escrita como os três “fatos” 1R2, 1R3 e 2R2. PRODUTO CARTESIANO ENVOLVENDO MAIS DE DOIS CONJUNTOS Diferentemente do produto aritmético, o produto cartesiano não goza das propriedades de comutatividade e de associatividade . É fácil encontrar exemplos onde A × B ≠ B × A, invalidando a comutatividade. A lei associativa nem mesmo faz sentido, pois (A × B) × C teria, como elementos, pares do tipo ((a, b), c), enquanto A × (B × C) apresentaria pares do tipo (a, (b, c)). Entretanto, o conceito de produto cartesiano pode ser estendido, visando fundamentar a existência de tuplas com mais de dois componentes, para um conceito de produto cartesiano envolvendo mais de dois conjuntos. Para isso, considera-se que A1 × A2 × ... × Ak designa o produto cartesiano dos conjuntos A1, A2, ... , Ak , isto é, designa o conjunto de k-tuplas (a1, a2, ... , ak) tal que a1 ∈ A1, a2 ∈ A2, ... e ak ∈ Ak. ⇒ exemplo Z × Z × Z representa o conjunto de triplas de números inteiros (i, j, k) contendo, por exemplo, a tripla (1, 2, 3) . Esse produto não deve ser confundido com (Z × Z) × Z, que representa pares como ((1, 2), 3), ou com Z × (Z × Z), que representa pares como (1, (2, 3 )). Relações e Funções B. Maffeo página 13 de 32 GRAFOS REPRESENTANDO RELAÇÕES Uma relação R, cujos domínio A e imagem B são conjuntos finitos, pode ser representada por um grafo. Desenha-se um nodo para cada elemento em A e/ou B. Se aRb, desenha-se um arco de a para b. ⇒ exemplo R = {(1, 2), (1, 3), (2, 2)} pode ser representada por 2 1 3 Relações e Funções B. Maffeo página 14 de 32 FUNÇÕES DEFINIÇÕES BÁSICAS Seja uma relação R, do domínio A para a imagem B, com a propriedade: “para todo membro a em A existe, no máximo, um elemento b em B tal que aRb”. Então, R é considerada uma função parcial do domínio A para a imagem B. Formalmente: f ⊆ { (a,b) | a ∈ A ∧ b ∈ B ∧ aRb ∧ R ⊆ A × B ∧ ∀a, b1, b2 ( b1 ∈ B ∧ b2 ∈ B ∧ aRb1 ∧ aRb2 → b1 = b2 ) } Se, para cada membro a em A, existir exatamente um elemento b em B tal que aRb, então R é considerada uma função total de A para B. Formalmente: f ⊆ { (a,b) | aRb ∧ R ⊆ A × B ∧ ∀a ( a ∈ A → ∃b ( b ∈ B ∧ aRb ) ) ∧ ∀a, b1, b2 ( b1 ∈ B ∧ b2 ∈ B ∧ aRb1 ∧ aRb2 → b1 = b2 ) } A diferença entre uma função parcial e uma função total é que uma função parcial pode ser indefinida sobre alguns elementos de seu domínio. Por exemplo, para algum a em A, pode não existir b em B tal que aRb. Aqui, o termo função será utilizado para referências à noção mais geral de função parcial. Notação comumente usada para função: f: A→B (denotando a relação R de A para B) com f (a) = b (o uso de f no lugar de R convencionando a unicidade de cada par associado a um dado elemento do domínio). ⇒ exemplo Seja Q a função total de Z para Z dada por Q ⊆ { (a, b) | aRb ∧ R ⊆ Z × Z ∧ ∀a ( a ∈ Z → ∃b ( b ∈ Z ∧ b = a ∗ a ) ) }, conjunto dos pares de inteiros cujo segundo componente é o quadrado do primeiro componente. Então Q possui membros tais como (3, 9), (−4, 16) e (0, 0). É possível, também, expressar que Q é a função “elevar ao quadrado”, escrevendo-se Q (3) = 9, Q (−4) =16 e Q (0) = 0. Relações e Funções B. Maffeo página 15 de 32 AS MUITAS NOTAÇÕES PARA FUNÇÃO Uma função f, de A × B para C, é, formalmente, um subconjunto de (A × B) × C. Um par típico na função f teria a forma ((a, b), c), ande a, b e c, seriam membros de A, B e C, respectivamente. Utilizando a notação especial para funções, pode-se escrever f (a, b) = c. f pode ser vista como uma relação binária de A × B para C, uma vez que toda função é uma relação. Utilizando a notação in-fixada para denotar relações, a ocorrência de ((a, b), c) em f pode ser também escrita (a, b) f c. Ao estender-se para mais de dois conjuntos o conceito de produto cartesiano, pode ser desejável remover os parênteses da expressão para o produto. Assim, estariam sendo identificadas duas expressões formalmente não equivalentes, (A × B) × C e A × B × C. Nesse caso, se f for armazenada como um conjunto de triplas, será necessário lembrar que os dois primeiros componentes fazem parte do domínio da função e o terceiro componente faz parte da imagem da função. FUNÇÃO EM SCHEME Note-se que o conceito de função baseado em Teoria de Conjuntos não é muito diferente da noção de função encontrada em Scheme. Seja a declaração da “função Scheme” q (define q (lambda (x) (* x x)) ) que recebe um número inteiro e retorna seu quadrado. Usualmente, pensa-se em q (a) como sendo o mesmo que a função Q (a) do exemplo precedente, embora (q a) expresse um modo de computar quadrado de a e Q seja somente a definição abstrata da operação “elevar ao quadrado”. Ou seja, Q constitui o modelo conceitual da operação “elevar ao quadrado” e (q a) é uma implementação em Scheme dessa operação. Note-se, também, que, na prática, (q a) é sempre uma função parcial, pois existem muitos valores de a para os quais (q a) não retornará um número inteiro em virtude da finitude da aritmética de computadores. A linguagem Scheme permite definir funções com mais de um argumento. Uma “função Scheme” que recebe dois argumentos a e b do tipo inteiro e retorna um número inteiro é uma função de Z × Z para Z. De maneira análoga, se os tipos dos argumentos a e b são tais que a e b pertençam, respectivamente, aos conjuntos A e B e f retorne um membro de tipo C, então f é uma função de A × B para C. Mais geralmente, se f recebe k argumentos por exemplo, dos conjuntos A1, A2, ... , Ak , respectivamente e retorna um membro do conjunto B, então diz-se que f é uma função de A1 × A2 × ... × Ak para B. Por exemplo, sendo L uma lista em cujas posições encontram-se valores do tipo T, pode-se considerar a função (member x L) como uma função de T × LISTA para {TRUE, FALSE}. Aqui, T designa o conjunto de valores desse tipo e LISTA designa o conjunto de listas de itens do tipo T. Escrita em Scheme, essa estrutura não é revelada pela declaração da função (member x L) pois Scheme não é uma linguagem tipada. Relações e Funções B. Maffeo página 16 de 32 Formalmente, uma função de um domínio A1 × A2 × ... × Ak para uma imagem B é um conjunto de pares da forma ( (a1, a2, ... , ak) , b), onde cada ai pertence ao conjunto Ai e b pertence ao conjunto B. Note-se que o primeiro elemento do par é, ele próprio, uma k-tupla. Por exemplo, a função (member x L), acima considerada, pode ser vista como o conjunto de pares ((x, L), y), onde x é um valor do tipo T, L é uma lista de elementos desse tipo e y é ou TRUE ou FALSE, dependendo de x estar ou não contido na lista L. Seja em Scheme, seja a partir da definição formal baseada na Teoria de Conjuntos, é possível pensar em uma função como uma caixa que recebe um valor do conjunto domínio e produz um valor do conjunto imagem, tal como é sugerido, a seguir, para a função (member x L). (x, L) member y CORRESPONDÊNCIA UM - PARA - UM Seja F uma função parcial do domínio A para a imagem B, com as seguintes propriedades: 1. Para cada elemento a em A, existe um elemento b em B tal que F (a) = b. Formalmente: F ⊆ { (a,b) | ∀a ( a ∈ A → ∃b ( b ∈ B ∧ aRb ) ) ∧ ∀a, b1, b2 ( b1 ∈ B ∧ b2 ∈ B ∧ aRb1 ∧ aRb2 → b1 = b2 ) } 2. Para cada elemento b em B, existe algum a em A tal que F (a) = b. Formalmente: F ⊆ { (a,b) | ∀b ( b ∈ B → ∃a ( a ∈ A ∧ aRb ) ) } 3. Para nenhum elemento b em B, existem dois elementos a1 e a2 em A tais que F (a1) = F (a2) = b. Formalmente: F ⊆ { (a,b) | ∀b, a1, a2 ( b ∈ B ∧ a1 ∈ A ∧ a2 ∈ A ∧ a1Rb ∧ a2Rb → a1 = a2 ) } Nessas condições, F é considerada uma correspondência um-para-um de A para B. Também é usado o termo bijeção para designar esse tipo de correspondência. A propriedade 1 estabelece que F é uma função total de A para B. A propriedade 2 estabelece que F é uma função total de A sobre B. Também é usado o termo surjeção para designar esse tipo de correspondência. A propriedade de 3 permite definir una função, inversa de F, de B para A. As propriedades 2 e 3, conjuntamente, estabelecem que essa função comporta-se como uma função total de B para A. Uma função total F que goze da propriedade 3 estabelece uma correspondência que é designada, também, pelo termo injeção. Relações e Funções B. Maffeo página 17 de 32 Uma correspondência um-para-um é basicamente uma função total nas duas direções, mas é importante ressaltar que o fato de ser F uma correspondência um-para-um depende, não só dos pares em F, mas, também, do domínio e da imagem especificados. Por exemplo, é possível, a partir de uma correspondência um-para-um de A para B, alterar o domínio acrescentando a A algum novo elemento x não mencionado em F. Nessas condições, F não seria uma correspondência um-para-um de A ∪ {x} para B. ⇒ exemplos ♦ A função “eleva ao quadrado” Q, de Z para Z, não é uma correspondência um-para-um. Q satisfaz a propriedade 1, pois, para cada número inteiro i, existe algum número inteiro, seja i2, tal que Q (i) = i2. Entretanto, Q não satisfaz a propriedade 2, pois há elementos b em Z em particular, todos os números negativos que não são Q (a) para algum a. Q também não satisfaz a propriedade 3, pois existem muitos exemplos de valores distintos de a para os quais Q (a) é igual ao mesmo b. Por exemplo, Q (3) = 9 e Q (−3) = 9. ♦ Seja a função total P de Z para Z, definida por P (a) = a+1. Ou seja, P adiciona 1 a qualquer número inteiro. Por exemplo, P (5) = 6 e P (−5) = −4. Formas alternativas de representação seriam o conjunto de tuplas {..., (−2, −1), (−1, 0), (0, 1), (1, 2), ...} ou o grafo ... −2 −1 0 1 2 ... Aqui, P é uma correspondência um-para-um, de inteiros para inteiros, pois: • P é uma função parcial, pois quando se adiciona 1 a um inteiro a obtém-se um único inteiro a + 1 • P satisfaz a propriedade 1, pois para cada inteiro a existe algum inteiro a + 1 • P satisfaz a propriedade 2, pois para cada inteiro b existe algum inteiro, seja b − 1, tal que P (b − 1) = b • P satisfaz a propriedade 3, pois para um inteiro qualquer b não existem dois inteiros distintos tais que, somados a 1, resultam b. ♦ P não é uma correspondência um-para-um, de reais para reais, pois não possui pares para reais não inteiros. Uma correspondência um-para-um de A para B é uma forma de estabelecer uma associação única entre os elementos de A e de B, como a que existe entre os “dedos” de uma luva e os dedos da mão que a luva veste. Relações e Funções B. Maffeo página 18 de 32 Analogamente, é possível imaginar essa associação como sendo uma definição da função inversa, ou seja, uma correspondência de A para B pode ser invertida trocando-se a ordem dos componentes em seus pares, obtendo uma correspondência um-para-um de B para A. Uma conseqüência de haver essa correspondência entre “a luva e a mão” é a igualdade do número de dedos na luva e na mão. Isso parece ser uma noção natural e intuitiva: dois conjuntos possuem mesma cardinalidade quando existe uma correspondência um-para-um de um conjunto para o outro. Entretanto, quando os conjuntos possuem um número infinito de elementos, chega-se a algumas conclusões surpreendentes a partir dessa definição de “mesma cardinalidade”. A relevância desse tipo de correspondência para a Ciência da Computação revela-se de diferentes maneiras. Uma delas, bastante importante, relaciona-se à área de bancos de dados e associa-se, na modelagem conceitual, ao conceito de atributo determinante e, nos níveis de design e de implementação, ao conceito de chave. IMPLEMENTANDO FUNÇÕES COMO DADOS Em um programa de computador, funções são, normalmente, implementadas como subprogramas, mas, no caso de funções finitas cujo domínio seja pequeno, elas podem ser implementadas com o uso de técnicas bastante similares às técnicas utilizadas para conjuntos, ou seja, empregando estruturas de dados do tipo lista e arranjo. OPERAÇÕES BÁSICAS SOBRE FUNÇÕES Inserir, Suprimir e Buscar As operações básicas sobre funções são similares àquelas aplicadas a estruturas do tipo dicionário. Seja F uma função do domínio conjunto A para a imagem conjunto B. Pode-se, então: ♦ Inserir um novo par (a, b) tal que F (a) = b. Como F deve ser uma função, se já houver um par (a, c), esse par deve ser substituído por (a, b). ♦ Suprimir o valor associado a F (a). Aqui, é necessário apenas o valor a do domínio. Se houver algum b tal que F (a) = b, então o par (a, b) deve ser removido do conjunto. Não havendo esse par, nada ocorre. ♦ Buscar o valor associado a F (a). Isto é, dado o valor a do domínio, retornar o valor b tal que F (a) = b. Não havendo o par (a, b) no conjunto, retorna-se algum valor especial para avisar que F (a) é indefinido. Relações e Funções B. Maffeo página 19 de 32 ⇒ exemplos Seja F designando o conjunto {(3, 9), (−4, 16), (0, 0)}, isto é, F (3) = 9, F (−4) = 16 e F (0) = 0. Nessas condições, busca (3) retorna 9 e busca (2) retorna um valor, por exemplo −1, indicando que não há valor definido para F (2). A operação suprime (3) retira o par (3, 9), enquanto que suprime (2) nada faz. Executando-se insert (5, 25), o par (5, 25) é adicionado ao conjunto F ou, de maneira equivalente, tem-se, agora, F (5) = 25. Executando-se insere (3, 10), o antigo par (3, 9) é retirado do conjunto F e o novo par (3, 10) é acrescentado, de modo que, agora, F (3) = 10. Funções como Subprogramas e Funções como Dados Precedentemente, foi traçada uma forte analogia entre a noção abstrata de função e o tipo de subprograma função implementado na linguagem de programação Scheme. Convém, entretanto, notar uma diferença importante. Se F é uma “função Scheme” e x é um membro de seu conjunto domínio, então F especifica como deve ser computado o valor F (x). O mesmo subprograma será executado, uniformemente, para qualquer valor de x. Entretanto, quando uma função é representada por meio de dados, supõe-se que: ♦ a função consiste em um conjunto finito de pares ♦ é normal a imprevisibilidade dos pares. Isso significa que não haverá, eventualmente, uma forma conveniente de, dado um x, computar F (x). O melhor que pode ser feito é criar-se uma tabela contendo cada um dos pares (a1, b1), (a2, b2), ..., (an, bn) tais que F (ai) = bi . Nesse caso, a função constitui-se, efetivamente, de dados e não de um subprograma, mesmo que seja criado um algoritmo para armazenar a tabela como parte de um programa e para, nessa tabela interna, dado x, buscar F (x). Entretanto, uma abordagem mais produtiva é armazenar a tabela separadamente, como uma estrutura de dados externa e independente do programa, e buscar valores nela contidos através de um subprograma de propósito geral aplicável a qualquer função representada como dados. Nessas condições, quando uma função é representada por meio de dados, especifica-se o que ela é (modelagem conceitual), sem haver a preocupação de especificar como ela é computada. Relações e Funções B. Maffeo página 20 de 32 BIBLIOGRAFIA UTILIZADA Foundations of Computer Science Alfred V. Aho e Jeffrey D. Ullman ( Computer Science Press, 1992 ) seções: 7.7, 7.8, 7.9 Relações e Funções B. Maffeo página 21 de 32 ÁRVORES BINÁRIAS DEFINIÇÃO Em uma árvore binária, um nodo pode ter, no máximo, dois filhos, denominados filho à esquerda e filho à direita. ⇒ exemplos A figura a seguir mostra duas árvores binárias, ambas enraizadas no nodo n1. n1 A raiz possui o nodo n2 como filho à esquerda e nenhum filho à direita. n2 n1 n2 A raiz possui o nodo n2 como filho à direita e nenhum filho à esquerda. Essas são as únicas árvores binárias de dois nodos, onde n2 não possui filhos, seja à esquerda, seja à direita. É importante entender que, enquanto árvores binárias exigem que seja distinguido se um filho está à esquerda ou à direita, uma árvore “ordinária” não exige tal distinção. Ou seja, uma árvore binária não é somente uma árvore onde cada nodo pode ter no máximo dois filhos; deve também ficar explícita a relação de posição envolvendo os dois filhos. As duas árvores binárias consideradas no exemplo não são apenas distintas mas, também, desprovidas de relação com a árvore “ordinária” formada por um nodo raiz n1, nodo esse possuindo um único filho n2, e representada por n1 n2 Outra diferença é que, no caso de uma árvore “ordinária”, presume-se que a árvore tenha pelo menos um nodo, o nodo raiz. Uma árvore binária, entretanto, pode ser uma árvore vazia. Árvores Binárias B. Maffeo página 22 de 32 TERMINOLOGIA BÁSICA Aplicam-se a árvores binárias os conceitos de filho, irmão, caminho, ancestral, descendente e folha, definidos para árvores “ordinárias”. Os filhos à esquerda e à direita são ambos considerados como filhos. Os dois filhos de um nodo, se existirem, são irmãos. Um caminho de n1 para nk é a seqüência de nodos n1,n2, ... , nk tal que ni+1 é um filho (à esquerda ou à direita) de ni, para i < (k − 1). É permitido o caso k = 1, no qual existe apenas um nodo. Ancestral de um nodo n é qualquer nodo situado no caminho que liga a raiz da árvore a n. Em particular, n é ancestral de si mesmo. Descendente de um nodo n é qualquer nodo do qual n seja ancestral. Em particular, n é descendente de si mesmo. Uma folha é um nodo que não possui filhos ou, de maneira equivalente, é um nodo cujas sub-árvores à esquerda e à direita são ambas vazias. Um nodo interior é aquele que não é uma folha. Os conceitos de comprimento de caminho, altura e profundidade são também idênticos àqueles referentes a árvores “ordinárias”. O comprimento de um caminho é medido por uma unidade a menos que o número de nodos que o caminho engloba, isto é, esse comprimento é igual ao número de arcos pai-filho existentes ao longo do caminho. A altura de um nodo n é o comprimento do caminho mais longo entre n e uma folha descendente. A altura de uma árvore binária é igual à altura de sua raiz. A profundidade de um nodo n é o comprimento do caminho entre a raiz e n. Árvores Binárias B. Maffeo página 23 de 32 TIPOS DE ÁRVORE BINÁRIA Uma árvore é denominada estritamente binária quando cada nodo possui 0 ou 2 filhos. Uma árvore binária completa é aquela que apresenta a seguinte propriedade: se n é um nodo tal que alguma sub-árvore é vazia, então n localiza-se no nível mais profundo ou no penúltimo nível da árvore. Uma árvore binária cheia é aquela em que, se n é um nodo com alguma de suas sub-árvores vazia, então n localiza-se no último nível. Segue-se que toda a árvore binária cheia é completa e estritamente binária. Árvores Binárias B. Maffeo página 24 de 32 ⇒ exemplos n1 n2 n3 São as cinco possíveis árvores binárias formadas por três nodos. Em cada uma, n3 é um descendente de n1 e existe um caminho de n1 para n3. Nas cinco árvores, o nodo n3 é uma folha. O nodo n2 é folha somente na árvore do meio, sendo, nas demais, um nodo interior. A altura de n3 é 0 em cada árvore. A altura de n1 é 2 em todas as árvores salvo na do meio, onde sua altura é 1. A altura de cada árvore é a altura de n1 nessa árvore. A profundidade do nodo n3 é 2 em todas as árvores salvo na do meio, onde sua profundidade é 1. n1 n2 n3 n1 n3 n2 n1 n2 Ou seja, cada árvore binária é invariante sob qualquer operação que, mantida sua estrutura, simplesmente troque a posição dos nodos n1 n2 n3. n3 n1 n2 n3 Árvores Binárias B. Maffeo página 25 de 32 DEFINIÇÃO RECURSIVA EQUIVALENTE Uma árvore binária A é um conjunto finito de elementos interligados, denominados nodos, para o qual é imposta : ♦ uma relação hierárquica, do tipo pai-filho, entre quaisquer dois nodos adjacentes ♦ a seguinte formulação recursiva caso base A = ∅ e a árvore é dita vazia. passo indutivo Se r é um nodo e A1 e A2 são árvores binárias, então há uma árvore binária com raiz r, sub-árvore à esquerda A1 e sub-árvore à direita A2, conforme a ilustração a seguir. A raiz de A1 é o filho à esquerda de r, a menos que A1 seja vazia, caso em que r não possui filho à esquerda. r Da mesma forma, a raiz de A2 é o filho à direita de r, a menos que A2 seja vazia, caso em que r não possui filho à direita. A1 A2 Ou seja, uma árvore binária é um conjunto de elementos submetidos a uma estruturação hierarquizada ternária (um pai tem no máximo dois filhos). Note-se que, se A1 = A2 = ∅, então o nodo r é isolado e { r } é uma árvore binária de um só nodo. Árvores Binárias B. Maffeo página 26 de 32 BIBLIOGRAFIA UTILIZADA Foundations of Computer Science Alfred V. Aho e Jeffrey D. Ullman ( Computer Science Press, 1992 ) seções: 5.2, 5.3, 5.4, 5.6 Árvores Binárias B. Maffeo página 27 de 32 ÁRVORES BINÁRIAS DE BUSCA DEFINIÇÃO Uma árvore binária de busca (BST - binary search tree) é uma árvore binária rotulada na qual vale a seguinte propriedade para cada nodo n: Todos os nodos situados na sub-árvore à esquerda de n possuem rótulos de valor inferior ao valor do rótulo de n e todos os nodos situados na sub-árvore à direita de n possuem rótulos de valor superior ao valor do rótulo de n. ABB é uma estrutura de armazenamento muito favorável à solução de problemas de busca em que, dado um conjunto de elementos onde cada elemento é identificado univocamente por uma chave, o objetivo é localizar no conjunto o elemento correspondente a uma chave específica. Numa ABB, os elementos do conjunto são previamente distribuídos pelos nodos da árvore de forma ordenada conveniente à busca. A localização da chave desejada é, então, obtida por meio de um percurso apropriado na árvore. É importante ressaltar a relevância desse problema na área de computação, especialmente nas aplicações não numéricas. Sem dúvida, a operação de busca é uma das operações realizadas com maior freqüência em sistemas de informação baseados em computador. ⇒ exemplo Seja S = {s1, s2, ... ,sn} um conjunto de chaves satisfazendo s1 < s2 < ... < sn. A figura a seguir apresenta duas ABBs construídas sobre S. s3 s2 s1 s7 s1 s4 Árvores Binárias de Busca s3 s5 s2 s4 s5 s6 s6 B. Maffeo página 28 de 32 s7 DICIONÁRIO O emprego de ABB é uma boa escolha de design no caso de um dicionário. Assume-se que os rótulos dos nodos são escolhidos dentro de um conjunto cujos elementos podem obedecer a uma relação de ordem do tipo “menor do que”, simbolizado pelo caractere < . Exemplos disso são os números inteiros ou reais com a ordenação comparativa usual ou cadeias de caracteres onde é possível estabelecer uma ordem lexicográfica, ou alfabética, representada por < . ⇒ exemplo (para o conjunto {Hairy, Bashful, Grumpy, Sleepy, Sleazy, Happy} onde < é a ordem lexicográfica) Hairy Bashful Grumpy Sleepy Sleazy Note-se que os nomes da sub-árvore à esquerda da raiz são todos lexicograficamente menores do que Hairy, enquanto que os da sub-árvore à direita são todos maiores. Essa propriedade vale para cada nodo da árvore considerada. Happy BUSCANDO UM ELEMENTO NA ABB Deseja-se verificar se um dado elemento x está presente no dicionário representado pela ABB A. Comparando-se x com o elemento na raiz de A, usa-se vantajosamente a propriedade de ordenação da ABB para localizar x com bastante rapidez ou verificar que x não está presente. procedimento informal Se x estiver na raiz, a busca estará concluída. Se não, se x for menor do que o elemento na raiz, x só poderá ser encontrado na sub-árvore à esquerda da raiz (devido à propriedade de ABB s). Se x for maior, então só poderá ser encontrado na sub-árvore à direita da raiz (novamente, devido à propriedade de ABB s). Assim, verifica-se que a operação de busca pode ser expressa formalmente através de um procedimento recursivo. Árvores Binárias de Busca B. Maffeo página 29 de 32 método indutivo base Se a árvore A for vazia, então x não estará presente e a busca está concluída. Se A não for vazia e x encontrar-se na raiz, então pesquisa-se a raiz e a busca está concluída. passo indutivo Se A não for vazia mas x não se encontrar na raiz, seja y o elemento contido na raiz: ♦ se x < y, então x deve ser buscado na sub-árvore à esquerda da raiz ♦ se x > y, então x deve ser buscado na sub-árvore à direita da raiz. A propriedade de ABBs garante que x não pode ser encontrado na sub-árvore que não for verificada. Esse método caracteriza uma alternativa de design da operação de busca definida no nível conceitual e usa uma ABB como modelo de dados. Mais concretamente, ele pode ser implementado por meio de um algoritmo recursivo escrito em Scheme, o qual deve processar listas que implementam ABBs. Vale notar que o método indutivo acima apresentado como solução do problema é uma alternativa de design porque o problema é formulado em termos da estrutura matemática conjunto, a qual caracteriza o nível conceitual da especificação. Outra alternativa de design possível, porém menos eficiente que o emprego de uma ABB, seria utilizar uma seqüência ordenada. Tratando-se de um problema formulado em termos de ABB diretamente, a solução apresentada em termos do método indutivo estaria situada no nível conceitual da especificação. INSERINDO UM ELEMENTO NA ABB método indutivo base Se A for a árvore vazia, substitui-se A por um novo nodo e coloca-se x nesse nodo. Se A não for a árvore vazia e sua raiz contiver o elemento x, então x já se encontra no dicionário e não há nada a ser feito. passo indutivo Se A não for a árvore vazia e sua raiz não contiver o elemento x, então x deve ser inserido na sub-árvore à esquerda quando x < y (y sendo o elemento contido na raiz) ou deve ser inserido na sub-árvore à direita quando x > y. Árvores Binárias de Busca B. Maffeo página 30 de 32 SUPRIMINDO UM ELEMENTO DA ABB Suprimir um elemento de uma ABB é um pouco mais complexo do que inserir ou buscar. procedimento informal Inicialmente, é necessário localizar o nodo que contém x, o elemento a ser retirado. Se não existir esse nodo, nada há a ser feito uma vez que x não está contido no dicionário. Se x estiver contido em uma folha, basta retirar essa folha. Se, entretanto, x estiver contido em um nodo interior n, não será possível retirá-lo, pois a retirada de um nodo interior ocasionaria uma ruptura na árvore. Nesse caso, é necessário rearranjar a ABB de modo que: ♦ seja mantida sua propriedade de ordenação ♦ x deixe de ocorrer em qualquer de seus nodos. Para executar essa reordenação há duas possibilidades a considerar. 1. Se n possuir apenas um filho, é possível substituir n por esse filho, mantendo-se, assim, a propriedade da ABB. 2. Se n possuir os dois filhos, uma estratégia é encontrar o nodo m com rótulo y, sendo esse o menor elemento da sub-árvore à direita de n, e substituir x por y no nodo n, tal como é sugerido na figura a seguir. Remove-se, então, o nodo m da sub-árvore à direita de n. n n x y ⇒ <x >x <y >y A propriedade da ABB continua valendo pelo fato de x ser maior do que qualquer elemento contido na subárvore à esquerda de n. Assim, y, que, por pertencer à sub-árvore à direita de n, é maior do que x, é, também, maior do que qualquer elemento contido na sub-árvore à esquerda de n. Logo, no que concerne à sub-árvore à esquerda de n, y é elemento adequado para ser armazenado em n. Quanto à sub-árvore à direita de n, y é igualmente adequado para ser armazenado em n, pois foi escolhido como sendo o menor elemento dessa sub-árvore. Árvores Binárias de Busca B. Maffeo página 31 de 32 BIBLIOGRAFIA UTILIZADA Foundations of Computer Science Alfred V. Aho e Jeffrey D. Ullman ( Computer Science Press, 1992 ) seção: 5.8, 5.9 Árvores Binárias de Busca B. Maffeo página 32 de 32