Je mettais en œuvre quicksort et je voulais définir le pivot pour être la médiane ou trois chiffres. Les trois nombres étant le premier élément, le milieu et le dernier.
Pourrais-je trouver la médiane en moins non. de comparaisons?
median(int a[], int p, int r)
{
int m = (p+r)/2;
if(a[p] < a[m])
{
if(a[p] >= a[r])
return a[p];
else if(a[m] < a[r])
return a[m];
}
else
{
if(a[p] < a[r])
return a[p];
else if(a[m] >= a[r])
return a[m];
}
return a[r];
}
Vous ne pouvez pas le faire en un, et vous n'en utilisez que deux ou trois, alors je dirais que vous avez déjà le nombre minimum de comparaisons.
Si le problème concerne uniquement les comparaisons, il convient de l’utiliser.
int getMedian(int a, int b , int c) {
int x = a-b;
int y = b-c;
int z = a-c;
if(x*y > 0) return b;
if(x*z > 0) return c;
return a;
}
Plutôt que de simplement calculer la médiane, vous pourriez aussi bien les mettre en place. Ensuite, vous pouvez vous contenter de 3 comparaisons tout le temps, et votre pivot est sur le point d'être en place.
T median(T a[], int low, int high)
{
int middle = ( low + high ) / 2;
if( a[ middle ].compareTo( a[ low ] ) < 0 )
swap( a, low, middle );
if( a[ high ].compareTo( a[ low ] ) < 0 )
swap( a, low, high );
if( a[ high ].compareTo( a[ middle ] ) < 0 )
swap( a, middle, high );
return a[middle];
}
int32_t FindMedian(const int n1, const int n2, const int n3) {
auto _min = min(n1, min(n2, n3));
auto _max = max(n1, max(n2, n3));
return (n1 + n2 + n3) - _min - _max;
}
Si vous n'avez pas peur de vous salir les mains avec les éléments intrinsèques du compilateur, vous pouvez le faire avec exactement 0 branche.
La même question a été discutée auparavant sur:
Le moyen le plus rapide de trouver la valeur moyenne d'un triple?
Cependant, je dois ajouter que dans le contexte de la mise en œuvre naïve de quicksort, avec beaucoup d'éléments, réduire le nombre de branches lorsque la médiane est trouvée n'est pas très important, car le prédicteur de branche s'étouffera de toute façon lorsque vous commencerez à lancer des éléments autour du pivot. Des implémentations plus sophistiquées (qui ne se ramifient pas sur l'opération de partition et évitent les risques WAW) en tireront grandement profit.
supprimer la valeur maximale et minimale de la somme totale
int med3(int a, int b, int c)
{
int tot_v = a + b + c ;
int max_v = max(a, max(b, c));
int min_v = min(a, min(b, c));
return tot_v - max_v - min_v
}
Il existe en fait un moyen astucieux d’isoler l’élément médian de trois en utilisant une analyse minutieuse des 6 permutations possibles (faible, médiane, élevée). En python:
def med(a, start, mid, last):
# put the median of a[start], a[mid], a[last] in the a[start] position
SM = a[start] < a[mid]
SL = a[start] < a[last]
if SM != SL:
return
ML = a[mid] < a[last]
m = mid if SM == ML else last
a[start], a[m] = a[m], a[start]
La moitié du temps, vous avez deux comparaisons, sinon vous en avez 3 (avg 2.5). Et vous n'échangez l'élément médian qu'une seule fois lorsque vous en avez besoin (2/3 du temps).
Full Python Quicksort en utilisant ceci à:
Je sais que c’est un vieux fil, mais j’ai dû résoudre exactement ce problème sur un microcontrôleur qui a très peu de RAM et ne dispose pas d’une unité de multiplication h/w (:)). Finalement, j'ai trouvé que ça marche bien:
static char medianIndex[] = { 1, 1, 2, 0, 0, 2, 1, 1 };
signed short getMedian(const signed short num[])
{
return num[medianIndex[(num[0] > num[1]) << 2 | (num[1] > num[2]) << 1 | (num[0] > num[2])]];
}
Vous pouvez écrire toutes les permutations:
1 0 2
1 2 0
0 1 2
2 1 0
0 2 1
2 0 1
Ensuite, nous voulons trouver la position du 1
. Nous pourrions le faire avec deux comparaisons, si notre première comparaison pouvait scinder un groupe de positions égales, telles que les deux premières lignes.
Le problème semble être que les deux premières lignes sont différentes pour chaque comparaison disponible: a<b
, a<c
, b<c
. Par conséquent, nous devons identifier complètement la permutation, ce qui nécessite 3 comparaisons dans le pire des cas.