[Enunciado] Eis como D. Gries (The Science of Programming, 1981, pag.345) implementa o algoritmo da separação. A função rearranja o vetor v[p..r] e devolve um elemento j do conjunto p..r tal que v[p..j-1] ≤ v[j] < v[j+1..r] :
int separa_Gries (int v[], int p, int r) { int c = v[p], i = p+1, j = r; // 1 while (true) { // 2 while (i <= r && v[i] <= c) ++i; // 3 while (c < v[j]) --j; // 4 if (i >= j) break; // 5 int t = v[i], v[i] = v[j], v[j] = t; // 6 ++i; --j; // 7 } // 8 v[p] = v[j], v[j] = c; // 9 return j; // 10 }
Algumas perguntas que chamam a atenção para detalhes importantes:
Que acontece se executarmos a função com
p igual a r?
Que acontece se eliminarmos
i <= r
na linha 3?
Por que não há um j >= p
na linha 4?
Que acontece se escrevermos i > j
na linha 5?
Que acontece se trocarmos j
por i
nas linhas 9 e 10?
Para facilitar a análise da correção, convém reescrever assim o código:
int separa_Gries (int v[], int p, int r) { int c = v[p], i = p+1, j = r; while (/*A*/ i <= j) { if (v[i] <= c) ++i; else if (c < v[j]) --j; else { int t = v[i], v[i] = v[j], v[j] = t; ++i; --j; } } // agora i == j+1 v[p] = v[j], v[j] = c; return j; }
No início de cada iteração, ou seja, a cada passagem pelo ponto A, temos a seguinte configuração:
p | i | j | r | ||||||
≤ c | ≤ c | ≤ c | ? | ? | ? | ? | ? | > c | > c |
Na penúltima passagem pelo ponto A, teremos uma das configurações a seguir:
p | i | j | r | ||||||
c | ≤ c | ≤ c | ≤ c | > c | ≤ c | > c | > c | > c | > c |
p | i=j | r | |||||||
c | ≤ c | ≤ c | ≤ c | ≤ c | ? | > c | > c | > c | > c |
Portanto, na última passagem pelo ponto A, valem as seguintes relações:
Assim, v[p..j-1] ≤ v[j] < v[j+1..r] na fim da execução da função, como prometido.