Mediana e i-ésimo menor elemento

Este página é inspirada no capítulo 10 de CLR.  Ela trata do problema da mediana e também do problema mais geral do i-ésimo menor elemento de um conjunto.

Mediana

Dado um conjunto S de números, o i-ésimo menor elemento de S é o número x em S tal que o conjunto  {s ∈ S : s ≤ x}  tem exatamente i elementos.  Se s1,s2,…,sn é uma enumeração dos elementos de S tal que s1 < s2 < … < sn, então o i-ésimo menor elemento é si.  Por exemplo, o 1-ésimo menor elemento de S é o mínimo de S e o |S|-ésimo menor elemento é o máximo de S.

A mediana de um conjunto S com n elementos é o  ⌊(n+1)/2⌋-ésimo (veja definição de piso) menor elemento de S.  (Eu poderia ter definido a mediana como o ⌈(n+1)/2⌉-ésimo menor elemento. Isso só faria diferença quando n fosse par.)   (Não confunda mediana com média. Por exemplo, a média de  {1,2,99} é 51, enquanto a mediana é 2.)

Nossos conjuntos serão representados por vetores cujos elementos são distintos dois a dois.  (É bem verdade que quase tudo se aplica igualmente bem a vetores com elementos repetidos, mas a discussão fica mais simples se os elementos forem distintos dois a dois.)  Nesse contexto, as definições podem ser reescritas como segue.

O i-ésimo menor elemento de um vetor estritamente crescente A[1..n] é o número A[i].  De modo um pouco mais geral, o i-ésimo menor elemento de um vetor estritamente crescente A[p..r] é o número A[ip+1].  De modo ainda mais geral, o i-ésimo menor elemento de um vetor A[p..r] sem elementos repetidos é o número x tal que x = A[k] para algum k e  |{ j : A[j] ≤ x}| = i .   Em particular, a mediana de um vetor A[p..r] sem elementos repetidos é o  ⌊½(n+1)⌋-ésimo menor elemento do vetor.

Problema da mediana:  Encontrar a mediana de um vetor A[p..r] sem elementos repetidos.

Problema da mediana generalizada:  Dado um vetor A[p..r] sem elementos repetidos e um número natural i, encontrar o i-ésimo menor elemento do vetor.

É claro que o problema tem solução se e somente se 1 ≤ i ≤ rp+1.

É muito fácil resolver o problema em tempo Ο(n lg n), sendo n o número de elementos do vetor.  O desafio está em obter um algoritmo mais rápido.

33 44 55 77 95 99 22 25 41 66 88 89

O quarto menor elemento do vetor é 41 e a mediana é 55.

Exercícios

  1. Escreva um algoritmo que consuma tempo Ο(n) para determinar o segundo menor elemento de um vetor com n ≥ 2 elementos.  Escreva um algoritmo que consuma tempo Ο(n) para determinar o n−1-ésimo menor elemento de um vetor com n ≥ 2 elementos. 
  2. Encontrar o menor e o segundo menor elemento de um vetor A[1..n] usando apenas n+⌈lg n⌉−2 comparações entre elementos do vetor  (veja a definição de teto).
  3. Prove que ⌊(n+1)/2⌋ = ⌈n/2⌉.
  4. Suponha que os elementos do vetor A[1..n] são distintos dois a dois.  Critique a seguinte definição alternativa de mediana:  "A mediana de A[1..n] é A[⌈n/2⌉]."
  5. Suponha que o vetor A[1..n] é estritamente crescente.  É razoável dizer que a mediana de A[1..n] é A[⌊n/2⌋]?   É razoável dizer que a mediana de A[1..n] é ⌈n/2⌉?
  6. Suponha que caiu do céu um algoritmo que calcula a mediana de um vetor com n elementos em Ο(n) unidades de tempo.  Como esse algoritmo poderia ser usado para melhorar a qualidade do subalgoritmo Separe a ser usado no Quicksort?

Seleção aleatorizada

Existem algoritmos que resolvem o problema da mediana generalizada em tempo Ο(n), mesmo no pior caso.  Nesta página, vamos nos contentar com algo mais fraco mas muito prático: um algoritmo cujo consumo de tempo esperado é Ο(n).  Tal como o Quicksort, o algoritmo usa o paradigma da divisão e conquista.

O algoritmo recebe um vetor A[p..r] sem elementos repetidos e um índice t no conjunto {p,…,r} e usa o Separe-Aleatorizado para encontrar o (tp+1)-ésmo menor elemento do vetor:

Selecione-Aleat (A, p, t, r)
o se p = r
oooo então  devolva A[p]
oooo senão  qSepare-Aleatorizado (A, p, r)
oooo senão  se qt
oooo senão  ooo então  devolva Selecione-Aleat (A, p, t, q)
oooo senão  ooo senão  devolva Selecione-Aleat (A, q+1, t, r)

(Observe que na linha 6 as condições para a invocação de Selecione-Aleat estão satisfeitas. De fato,  A[p..q] tem menos elementos que A[p..r]  e  t pertence ao conjunto {p,…,q}.  Algo análogo acontece na linha 7.)

Prova da correção do algoritmo:  Seja n = rp+1.  Se n = 1 então temos t = p e portanto o algoritmo devolve a resposta correta na linha 2.  Agora suponha que n > 1. Depois da linha 3 temos A[p..q] ≤ A[q+1..r].

Exercícios

  1. [Versão Iterativa]  Escreva uma versão não recursiva do algoritmo Selecione-Aleat.
  2. Suponha dado um algoritmo Separ que faça o seguinte: ao receber um vetor A[p..r], devolve um índice q no intervalo p..r depois de rearranjar o vetor de tal modo que A[p..q−1] ≤ A[q] < A[q+1..r].  Escreva uma versão do Selecione-Aleat que use o algoritmo Separ no lugar de Separe

Consumo de tempo da seleção aleatorizada

Suponha que Selecione-Aleat é aplicado a um vetor com n elementos distintos dois a dois. Seja E(n) o consumo de tempo do esperado do algoritmo.  Então

E(n)  está em  Ο(n) .

A prova deste fato é semelhante ao cálculo do consumo de tempo esperado do Quicksort-Aleatorizado.  Se Separe-Aleatorizado consome n unidades de tempo e as demais operações consomem 1 unidade de tempo, E satisfaz a recorrência

E(n)  =  1 + n  +   E(max(1,n−1))  +  ∑0<i<n E(max(i,ni))
n

e portanto temos  E(n)  ≤  1+n  +  (E(n−1) + 2 ∑i E(i)) / n ,  com soma indo de i = ⌈n/2⌉ a i = n−1.  Segue daí que E(n) = Ο(n) .

Exercícios

  1. Troque Separe-Aleatorizado por Separe no algoritmo acima.  Quanto tempo o algoritmo resultante consome no pior caso? 
  2. Seja T(n) o consumo de tempo do algoritmo Separe-Aleatorizado no pior caso. Supondo que cada uma das linhas 1, 2, 4 e 5 consome 1 unidade de tempo e que linha 3 consome n unidades de tempo, escreva a recorrência que T satisfaz.  Em seguida, prove que T(n) está em Ο(n2).
  3. Suponha que o algoritmo Separe-Aleatorizado recebe vetores arbitrários (possivelmente com elementos repetidos).  O consumo de tempo esperado do algoritmo está em Ο(n) nesse caso?
  4. [CLRS 9.3-5]  Suponha dado um algoritmo Mediana, com parâmetros (A,p,r), que rearranja os elementos de um vetor A[p..r] de números inteiros e devolve um índice q tal que p ≤ q ≤ r e A[p..q−1] ≤ A[q] ≤ A[q+1..r] e A[q] é a mediana de A[p..r].  Suponha ainda que o consumo de tempo do algoritmo é linear, ou seja, Θ(n), sendo n = rp+1.  Escreva um algoritmo que receba um vetor A[p..r] de inteiros e um índice i no conjunto {1,…,n} e devolva o valor do i-ésimo menor elemento de A[p..r].  O seu algoritmo deve utilizar Mediana como subrotina e deve consumir tempo Ο(n).

Um algoritmo assintoticamente melhor, mesmo no pior caso

Existe um algoritmo que resolve o problema da mediana generalizada em tempo Ο(n), mesmo no pior caso.  Mas o algoritmo é um tanto complexo.

Exercícios

  1. [CLRS 9.3-7]  Dado um vetor A[1..n] de números naturais e um número natural k ≤ n, determinar os k elementos do vetor que estão mais próximos da mediana do vetor.  Escreva um algoritmo que resolva o problema em tempo Ο(n).

Valid HTML 4.01 Strict Valid CSS!