web-dev-qa-db-fra.com

N ° minimum des comparaisons pour trouver la médiane de 3 nombres

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];
}
14
Karan Kalra

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.

4
Joel

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;
}
10
Raghav

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];
}
4
Joel
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;
}
3
codeb34v3r

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.

2
Max

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
}
1
Alok N Singh

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 à:

https://github.com/mckoss/labs/blob/master/qs.py

1
mckoss

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])]];
}
0
user5108360

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.

0
Thomas Ahle