Calculez la médiane d'un milliard de nombres

127

Si vous avez un milliard de nombres et cent ordinateurs, quelle est la meilleure façon de localiser la médiane de ces nombres?

Une solution que j'ai est:

  • Répartissez l'ensemble de manière égale entre les ordinateurs.
  • Triez-les.
  • Trouvez les médianes pour chaque ensemble.
  • Triez les ensembles sur les médianes.
  • Fusionner deux ensembles à la fois de la médiane la plus basse à la plus élevée.

Si nous avons m1 < m2 < m3 ...alors d'abord fusionné Set1et Set2et dans l'ensemble résultant, nous pouvons rejeter tous les nombres inférieurs à la médiane de Set12(fusionné). Donc, à tout moment, nous avons des ensembles de taille égale. En passant, cela ne peut pas être fait de manière parallèle. Des idées?

anony
la source
3
@John Boker: en fait, le problème consiste en deux sous-problèmes: 1) trier la liste et 2) obtenir un élément d'index 5'000'000'000. Je crois à peine que les chiffres sont triés.
Roman
3
@Roman: le problème ne doit pas nécessairement être constitué des deux sous-problèmes que vous décrivez, par exemple quickselect. Mais quickselect ne se met pas en parallèle, du moins pas de manière triviale. Et bien sûr, vous avez raison, si les nombres sont pré-triés, c'est une question assez inutile.
Steve Jessop
5
@fmsf: Je ne pense pas qu'un pays anglophone utilise le long milliard en anglais à des fins officielles. Par exemple ici au Royaume-Uni, nous avons cessé de l'utiliser en 1974. Je considérerais que l'utilisation de «billion» signifie un million de millions, en anglais comme une question piège perverse, pas du tout un «vrai milliard». Bien sûr, en français, ce serait une question totalement différente, mais la question n'est pas en français.
Steve Jessop
5
Vous n'avez pas besoin de trier! en.wikipedia.org/wiki/…
glebm
2
1 milliard de nombres ne représentent que quelques gigaoctets de données, vous n'avez pas besoin de plusieurs PC ni d'algorithmes complexes pour résoudre cette tâche. Ne vous compliquez pas trop.
user626528

Réponses:

54

Ah, mon cerveau vient de démarrer, j'ai une suggestion sensée maintenant. Probablement trop tard s'il s'agissait d'une interview, mais tant pis:

La machine 1 sera appelée la "machine de contrôle", et pour des raisons d'argumentation soit elle commence avec toutes les données, et les envoie en paquets égaux aux 99 autres machines, soit les données commencent uniformément réparties entre les machines, et il envoie 1/99 de ses données à chacun des autres. Les partitions n'ont pas besoin d'être égales, fermez simplement.

Chaque autre machine trie ses données et le fait d'une manière qui favorise la recherche des valeurs les plus basses en premier. Par exemple, un tri rapide, en triant toujours la partie inférieure de la partition en premier [*]. Il réécrit ses données sur la machine de contrôle dans un ordre croissant dès qu'il le peut (en utilisant des E / S asynchrones pour continuer le tri, et probablement avec Nagle activé: expérimentez un peu).

La machine de contrôle effectue une fusion à 99 voies sur les données à leur arrivée, mais rejette les données fusionnées, en gardant simplement le compte du nombre de valeurs vues. Il calcule la médiane comme la moyenne des 1/2 milliardième et 1/2 milliard plus unième valeurs.

Cela souffre du problème du «plus lent du troupeau». L'algorithme ne peut pas se terminer tant que chaque valeur inférieure à la médiane n'a pas été envoyée par une machine de tri. Il y a une chance raisonnable qu'une telle valeur soit assez élevée dans sa parcelle de données. Ainsi, une fois le partitionnement initial des données terminé, le temps de fonctionnement estimé est la combinaison du temps nécessaire pour trier 1 / 99ème des données et les renvoyer à l'ordinateur de contrôle, et le temps nécessaire au contrôle pour lire la moitié des données. . La "combinaison" se situe quelque part entre le maximum et la somme de ces temps, probablement proche du maximum.

Mon instinct est que pour envoyer des données sur un réseau plus rapide que de les trier (sans parler de la sélection de la médiane), il doit s'agir d'un réseau très rapide. Peut-être une meilleure perspective si le réseau peut être présumé instantané, par exemple si vous avez 100 cœurs avec un accès égal à la RAM contenant les données.

Étant donné que les E / S réseau sont susceptibles d'être la limite, il peut y avoir quelques astuces que vous pouvez jouer, au moins pour les données revenant à la machine de contrôle. Par exemple, au lieu d'envoyer "1,2,3, .. 100", une machine de tri pourrait peut-être envoyer un message signifiant "100 valeurs inférieures à 101". La machine de contrôle pourrait alors effectuer une fusion modifiée, dans laquelle elle trouve la moindre de toutes ces valeurs haut de gamme, puis dit à toutes les machines de tri ce que c'était, afin qu'elles puissent (a) dire à la machine de contrôle comment plusieurs valeurs à «compter» en dessous de cette valeur, et (b) reprendre l'envoi de leurs données triées à partir de ce point.

Plus généralement, il existe probablement un jeu de devinettes astucieux défi-réponse auquel la machine de contrôle peut jouer avec les 99 machines de tri.

Cela implique des allers-retours entre les machines, ce que ma première version plus simple évite. Je ne sais pas vraiment comment estimer à l'aveugle leur performance relative, et comme les compromis sont complexes, j'imagine qu'il existe de bien meilleures solutions que tout ce que je penserai à moi-même, en supposant que ce soit un problème réel.

[*] pile disponible le permet - votre choix de la partie à faire en premier est limité si vous n'avez pas d'espace supplémentaire O (N). Mais si vous avez suffisamment d'espace supplémentaire, vous pouvez faire votre choix, et si vous n'avez pas assez d'espace, vous pouvez au moins utiliser ce que vous avez pour couper certains coins, en faisant d'abord la petite partie pour les premières partitions.

Steve Jessop
la source
Veuillez me corriger si je me trompe, pourquoi effectuez-vous la fusion à 99 voies sur les données car elles arrivent uniquement pour les supprimer plus tard. Au lieu de cela, suffit-il de compter les nombres au fur et à mesure qu'ils arrivent?
sreeprasad
4
@SREEPRASADGOVINDANKUTTY: l'étape répétitive consiste à rejeter la plus petite valeur parmi les 99 candidats et à incrémenter le décompte. Il ne sert à rien de simplement garder un compte de toutes les valeurs entrantes sans cette étape de fusion à 99 voies. Si vous ne les comparez pas au fur et à mesure de leur entrée, vous ne savez pas que la valeur que vous supprimez est inférieure à la médiane.
Steve Jessop
Mais n'y a-t-il pas une petite chance que l'une de ces partitions ne contienne que des nombres supérieurs à la médiane et donc toute partition inférieure qu'elle renvoie sera supérieure à la médiane, mais comme le contrôle ne le sait pas, il les rejettera comme étant inférieure à la valeur médiane et échouer ...?
Gullydwarf
@Gullydwarf: une fusion multi-voies ne supprime que la plus petite des 99 valeurs qu'elle a en main, chacune d'elles étant la plus petite valeur restante de l'une des autres machines. Si l'une des partitions est entièrement supérieure à la médiane, alors elle ne deviendra la moindre de ces 99 valeurs qu'après le dépassement de la médiane (à quel point nous avons terminé). Donc, il ne sera pas rejeté.
Steve Jessop
52
sort -g numbers | head -n 500000001 | tail -n 2 | dc -e "1 k ? ? + 2 / p"
DrPizza
la source
2
LOL. Cela fonctionne-t-il vraiment ou le tueur OOM va-t-il le détruire avant qu'il ne se termine? (sur n'importe quel ordinateur raisonnable)
Isak Savo
5
Devrait faire. sort sait comment faire un tri hors cœur, pour ne pas manquer de mémoire.
DrPizza
6
@Zagfai Je ne pense pas que cela prendrait trop de temps; un milliard de nombres ne représente que 4 Go pour les entiers / flottants 32 bits, 8 Go pour les entiers / doubles 64 bits. Ni l'un ni l'autre ne semble extrêmement éprouvant.
DrPizza
13
Juste essayé sur un Intel i5-4200M à 3,1 GHz (4 cœurs). Selon la timecommande appliquée à l'ensemble du pipeline, il a fallu real=36m24s("wall clock time"), user=113m15s ("parallel time", tous les cœurs ajoutés). La commande la plus longue, loin devant les autres, était sort, même si elle filait à mes quatre cœurs à 100%. La consommation de RAM était très acceptable.
Morgan Touverey Quilling
12
Ensuite, exécutez sur 100 ordinateurs, vous pouvez donc être 100 fois plus sûr que le résultat est correct :)
dos
27

Je déteste être le contrariant ici, mais je ne pense pas que le tri soit nécessaire, et je pense que tout algorithme impliquant le tri d'un milliard / 100 nombres sera lent. Considérons un algorithme sur un ordinateur.

1) Sélectionnez au hasard 1000 valeurs parmi le milliard et utilisez-les pour avoir une idée de la distribution des nombres, en particulier une plage.

2) Au lieu de trier les valeurs, attribuez-les à des compartiments en fonction de la distribution que vous venez de calculer. Le nombre de seaux est choisi de manière à ce que l'ordinateur puisse les gérer efficacement, mais devrait autrement être aussi grand que pratique. Les plages de compartiments doivent être telles qu'un nombre à peu près égal de valeurs entre dans chaque compartiment (ce n'est pas critique pour l'algorithme, mais cela améliore l'efficacité. 100 000 compartiments peuvent être appropriés). Notez le nombre de valeurs dans chaque compartiment. Il s'agit d'un processus O (n).

3) Découvrez dans quelle plage de seaux se situe la médiane. Cela peut être fait en examinant simplement les nombres totaux dans chaque compartiment.

4) Trouvez la médiane réelle en examinant les valeurs de ce compartiment. Vous pouvez utiliser un tri ici si vous le souhaitez, car vous ne triez que 10 000 numéros. Si le nombre de valeurs dans ce compartiment est important, vous pouvez utiliser à nouveau cet algorithme jusqu'à ce que vous ayez un nombre suffisamment petit pour trier.

Cette approche parallélise trivialement en divisant les valeurs entre les ordinateurs. Chaque ordinateur rapporte les totaux de chaque compartiment à un ordinateur de `` contrôle '' qui effectue l'étape 3. Pour l'étape 4, chaque ordinateur envoie les valeurs (triées) dans le compartiment concerné à l'ordinateur de contrôle (vous pouvez également faire ces deux algorithmes en parallèle, mais ça n'en vaut probablement pas la peine).

Le processus total est O (n), car les deux étapes 3 et 4 sont triviales, à condition que le nombre de seaux soit suffisamment grand.

DJClayworth
la source
1
Je pense que c'est quelque chose entre la médiane des médianes et les algorithmes de sélection rapide. en.wikipedia.org/wiki/Selection_algorithm
Dimath
À l'étape 4, les compartiments peuvent ne pas contenir seulement 10 000. Il se peut que la distribution soit biaisée vers le milieu, dans laquelle elle pourrait contenir, par exemple, 80% des données, ce qui est encore énorme.
justhalf
Édité pour en tenir compte.
DJClayworth
4
La performance n'est pas O (n) dans cet algorithme: vous pourriez avoir la plupart des nombres dans le compartiment "médian", et cela pourrait fonctionner aussi mal que tout trier.
Sklivvz
1
@WULF Une excellente question. C'est la clé de l'algorithme et l'étape 1 y remédie. Un échantillon des nombres pour établir une distribution est le meilleur que j'ai trouvé.
DJClayworth il y a
12

Un milliard est en fait une tâche assez ennuyeuse pour un ordinateur moderne. Nous parlons ici de 4 Go de 4 octets entiers ... 4 Go ... c'est la RAM de certains smartphones.

public class Median {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();

        int[] numbers = new int[1_000_000_000];

        System.out.println("created array after " +  (System.currentTimeMillis() - start) + " ms");

        Random rand = new Random();
        for (int i = 0; i < numbers.length; i++) {
            numbers[i] = rand.nextInt();
        }

        System.out.println("initialized array after " + (System.currentTimeMillis() - start) + " ms");

        Arrays.sort(numbers);

        System.out.println("sorted array after " + (System.currentTimeMillis() - start) + " ms");

        if (numbers.length % 2 == 1) {
            System.out.println("median = " + numbers[numbers.length / 2 - 1]);
        } else {
            int m1 = numbers[numbers.length / 2 - 1];
            int m2 = numbers[numbers.length / 2];
            double m = ((long) m1 + m2) / 2.0;
            System.out.println("median = " + new DecimalFormat("#.#").format(m));
        }
}

Sortie sur ma machine:

created array after 518 ms
initialized array after 10177 ms
sorted array after 102936 ms
median = 19196

Donc, cela se termine sur ma machine en moins de deux minutes (1:43 dont 0:10 pour générer des nombres aléatoires) en utilisant un seul cœur et il fait même un tri complet. Rien d'extraordinaire vraiment.

C'est certainement une tâche intéressante pour des ensembles de nombres plus importants. Je veux juste faire une remarque ici: un milliard, c'est des arachides. Alors réfléchissez à deux fois avant de commencer à lancer des solutions complexes à des tâches étonnamment simples;)

sfussenegger
la source
c'est ce que j'ai dit dans ma réponse ici :-) stackoverflow.com/a/31819222/363437
vidstige
1
@vidstige Honnêtement, je ne l'ai pas lu, mais vous avez raison. ma réponse est certainement plus pratique, ce que les gens semblent apprécier un peu plus;)
sfussenegger
Ce n'est pas la médiane cependant, la médiane est (numbers[numbers.length / 2]+numbers[numbers.length / 2+1])/2si numbers.lengthest pair et numbers[numbers.length / 2]seulement si numbers.lengthest impair.
Sklivvz
@Sklivvz est correct, mais cela ne devrait pas affecter le temps nécessaire pour calculer la médiane.
vidstige
1
@Sklivvz vous avez bien sûr raison. Je viens de mettre à jour le calcul médian. Cela ne change cependant pas le reste de la réponse.
sfussenegger
10

L' estimation des statistiques d'ordre telles que la médiane et le 99e centile peut être efficacement distribuée avec des algorithmes tels que t-digest ou Q-digest .

En utilisant l'un ou l'autre algorithme, chaque nœud produit un condensé, qui représente la distribution des valeurs stockées localement. Les résumés sont collectés en un seul nœud, fusionnés (additionnant effectivement les distributions), et la médiane ou tout autre percentile peut alors être recherchée.

Cette approche est utilisée par elasticsearch et, vraisemblablement, BigQuery (en passant par la description de la fonction QUANTILES).

Richard Poole
la source
5

La médiane de cet ensemble de nombres

2, 3, 5, 7, 11, 13, 67, 71, 73, 79, 83, 89, 97

est 67.

La médiane de cet ensemble de nombres

2, 3, 5, 7, 11, 13, 67, 71, 73, 79, 83, 89

est 40.

En supposant que la question était d'environ 1 000 000 000 d'entiers (x) où 0> = x <= 2 147 483 647 et que l'OP recherchait (élément (499 999 999) + élément (500 000 000)) / 2 (si les nombres ont été triés). En supposant également que les 100 ordinateurs étaient tous égaux.

en utilisant mon ordinateur portable et GigE ...

Ce que j'ai trouvé, c'est que mon ordinateur portable peut trier 10 000 000 Int32 en 1,3 seconde. Donc, une estimation approximative serait qu'un tri d'un milliard de nombres prendrait 100 x 1,3 secondes (2 minutes 10 secondes);).

Une estimation d'un transfert de fichier unidirectionnel d'un fichier de 40 Mo sur un Gigabit Ethernet est de 0,32 seconde. Cela signifie que les résultats triés de tous les ordinateurs seront renvoyés dans environ 32 secondes (l'ordinateur 99 n'a reçu son fichier que 30 secondes après le démarrage). À partir de là, il ne devrait pas falloir longtemps pour supprimer les 499 999 998 nombres les plus bas, ajouter les 2 suivants et diviser par 2.

dbasnett
la source
3
Commentaire des électeurs? Cela m'aiderait à comprendre comment je peux faire mieux.
dbasnett
5
Je ne suis pas l'électeur vers le bas, mais trier un milliard de nombres ne prendra pas 100 fois plus de temps que trier 10 millions, parce que la complexité du pire des cas pour trier une liste est O (n log n). Le tri est également beaucoup plus lent lorsque vous manquez de mémoire et que vous devez commencer le tri sur disque.
Richard Poole
Je pense que vous êtes sur la bonne voie; Si l'objectif est de répondre une fois le plus rapidement possible, le tri sur plusieurs machines peut être une bonne idée. Mais si l'objectif est le temps moyen le plus bas, chaque machine effectuant sa propre recherche a plus de sens.
Charlie
En supposant qu'ils ont le même facteur (ce qu'ils n'ont probablement pas en raison de problèmes de mémoire), alors a*(1e7)log(1e7) = 1.3sec=> a = 1.6e-9sec => a*(1e9)log(1e9) ~ 167sec, donc votre estimation n'était pas si mauvaise.
bcorso
Vos estimations sont bien trop grossières. Premièrement, certains algorithmes de tri vont comme o (n ^ 2) dans le pire des cas (par exemple du tri rapide couramment utilisé). Deuxièmement, vous avez choisi un jeu de données de test qui correspond à peu près à la taille de votre cache L2. Cela fausse les résultats. Troisièmement, vous (comme beaucoup d'autres répondants) supposez que "nombre" signifie "entier". Cela pourrait signifier flottant, double ou décimal, qui ont des caractéristiques de performance très différentes.
Sklivvz
5

Cela peut surprendre les gens, mais si les nombres sont des nombres entiers suffisamment petits pour tenir à l'intérieur de 32 bits (ou moins) - Faites simplement un tri par seau! N'a besoin que de 16 Go de RAM pour un nombre quelconque d'entiers 32 bits et s'exécute en O (n), ce qui devrait surpasser tous les systèmes distribués pour un n raisonnable, par exemple un milliard.

Une fois que vous avez la liste triée, il est trivial de choisir la médiane. En fait, vous n'avez pas besoin de construire la liste triée, mais il suffit de regarder les buckets.

Une implémentation simple est illustrée ci-dessous. Ne fonctionne que pour les entiers 16 bits, mais l'extension à 32 bits devrait être facile.

#include <stdio.h>
#include <string.h>

int main()
{
    unsigned short buckets[65536];
    int input, n=0, count=0, i;

    // calculate buckets
    memset(buckets, 0, sizeof(buckets));
    while (scanf("%d", &input) != EOF)
    {
        buckets[input & 0xffff]++;
        n++;
    }

    // find median 
    while (count <= n/2)
    {
        count += buckets[i++];
    }

    printf("median: %d\n", i-1);

    return 0;
}

Utiliser un fichier texte avec un milliard (10 9 ) nombres et fonctionner avec timecomme ça

time ./median < billion

donne un temps d'exécution sur ma machine 1m49.293s. La plupart du temps d'exécution est probablement également IO disque.

vidstige
la source
Cela ne répond pas vraiment à la question et repose sur des hypothèses. Par exemple, vous ne savez même pas qu'il s'agit de nombres entiers.
Sklivvz
En quoi ne répond-il pas à la question? Et oui, ma réponse suppose que les nombres sont des nombres entiers. J'ai essayé d'exposer clairement mes hypothèses.
vidstige
Vous ne semblez pas dire que le fait d'avoir des nombres entiers est une hypothèse, ni comment utiliser les 100 ordinateurs sur lesquels l'OP demande. Vous pouvez calculer la médiane sur un nœud mais ce n'est pas la «meilleure» solution à moins que vous ne montriez pourquoi. De plus, le tri radix n'est pas o (n) si le nombre de chiffres varie, ce qui dans ce cas le fait certainement, selon en.wikipedia.org/wiki/Radix_sort#Efficiency , c'est o (n log n)
Sklivvz
Je commence par dire "si les nombres entiers sont assez petits pour tenir dans un entier 32 bits " ... Le tri Radix est O (n) pour une taille de mot constante w comme décrit avec une grande clarté dans le lien que vous avez posté. Ici, je suppose une taille de mot constante de 32.
vidstige
1
Ce que vous faites avec les 99 autres ordinateurs n'est pas pertinent dans cette réponse. Vous pouvez les empiler les uns sur les autres pour former une pyramide ou les brûler. Ou tout simplement les ignorer.
vidstige
3

Curieusement, je pense que si vous avez suffisamment d'ordinateurs, vous feriez mieux de trier que d'utiliser O(n)des algorithmes de recherche de médiane. (À moins que vos cœurs ne soient très, très lents, j'en utiliserais simplement un et utiliserais un O(n)algorithme de recherche de médiane pour seulement 1e9 nombres; si vous aviez 1e12, cependant, cela pourrait être moins pratique.)

Quoi qu'il en soit, supposons que nous ayons plus de cœurs log n pour résoudre ce problème, et que nous ne nous soucions pas de la consommation d'énergie, nous obtenons simplement la réponse rapidement. Supposons en outre qu'il s'agit d'une machine SMP avec toutes les données déjà chargées en mémoire. (Les machines à 32 cœurs de Sun sont de ce type, par exemple.)

Un thread coupe la liste aveuglément en morceaux de taille égale et dit aux autres threads M de les trier. Ces fils le font avec diligence, à (n/M) log (n/M)temps. Ils renvoient ensuite non seulement leurs médianes, mais, disons, leurs 25e et 75e centiles également (les pires cas pervers sont meilleurs si vous choisissez des nombres légèrement différents). Vous disposez désormais de 4 millions de plages de données. Vous triez ensuite ces plages et travaillez vers le haut dans la liste jusqu'à ce que vous trouviez un nombre tel que, si vous supprimez chaque plage qui est plus petite ou contient le nombre, vous aurez jeté la moitié de vos données. C'est votre limite inférieure pour la médiane. Faites de même pour la limite supérieure. Cela prend quelque chose comme du M log Mtemps, et tous les cœurs doivent attendre, donc c'est vraiment gaspillageM^2 log Mtemps potentiel. Maintenant, votre thread unique dit aux autres de jeter toutes les données en dehors de la plage (vous devriez en jeter environ la moitié à chaque passage) et de répéter - c'est une opération trivialement rapide car les données sont déjà triées. Vous ne devriez pas avoir à répéter cela plus de log(n/M)fois avant qu'il ne soit plus rapide de simplement saisir les données restantes et d'utiliser un O(n)chercheur de médiane standard dessus.

Donc, la complexité totale est quelque chose comme O((n/M) log (n/M) + M^2 log M log (n/M)). Ainsi, c'est plus rapide que le O(n)tri médian sur un noyau si M >> log(n/M)et M^3 log M < n, ce qui est vrai pour le scénario que vous avez décrit.

Je pense que c'est une très mauvaise idée compte tenu de son inefficacité, mais c'est plus rapide.

Rex Kerr
la source
o (n / M log (n / M)) est, littéralement, o (n log n), car o (n / M log (n / M)) = 1 / M o (n (log n - log M) ) = o (n log n). Vous ne pouvez pas vraiment le comparer avec o (n) comme ça, car le "o" signifie essentiellement "proportionnel à pour un grand très n avec une constante non spécifiée". Sauf si vous connaissez ces constantes, vous ne pouvez pas comparer, mais pour un N assez grand, les constantes ne sont pas dominantes. Pour les nombres inférieurs, tous les paris sont ouverts, o (1) peut facilement être plus lent que o (n!).
Sklivvz
@Sklivvz - net Msont les variables qui peuvent évoluer de manière arbitraire, donc on inclut les deux. En particulier, j'ai postulé que M> log n, ce qui signifie que si vous vous souciez que ce soit n log nplutôt que juste n, vous devez aussi vous en soucier M.
Rex Kerr
3

Cela peut être fait plus rapidement que l'algorithme voté (n log n)

- Algorithme de sélection distribuée des statistiques d'ordre - O (n)
Simplifie le problème au problème d'origine de trouver le kème nombre dans un tableau non trié.
- Comptage de l'histogramme de tri O (n)
Vous devez supposer certaines propriétés concernant la plage des nombres - la plage peut-elle tenir dans la mémoire? - Tri par fusion externe - O (n log n) - décrit ci-dessus
Vous triez essentiellement les nombres sur le premier passage, puis trouvez la médiane sur le second.
- Si l'on sait quelque chose sur la distribution des nombres, d'autres algorithmes peuvent être produits.

Pour plus de détails et la mise en œuvre, voir:
http://www.fusu.us/2013/07/median-in-large-set-across-1000-servers.html

utilisateur1712376
la source
2

Un ordinateur suffit amplement pour résoudre le problème.

Mais supposons qu'il y ait 100 ordinateurs. La seule chose complexe à faire est de trier la liste. Divisez-le en 100 parties, envoyez une partie à chaque ordinateur, laissez-les y être triées et fusionnez les parties après cela.

Ensuite, prenez le numéro du milieu de la liste triée (c'est-à-dire avec un index 5 000 000 000).

romain
la source
3
Quoi qu'il en soit maintenant mon représentant est assez rond :)
Roman
La fusion est au mieux O (n), et vous pouvez trouver la médiane sur un seul noyau en O (n), donc cela semble créer beaucoup de travail supplémentaire sans gain.
Rex Kerr
2

Cela dépend de vos données. Le pire des cas est qu'il s'agit de nombres uniformément distribués.

Dans ce cas, vous pouvez trouver la médiane en temps O (N) comme dans cet exemple:

Supposons que vos nombres soient 2,7,5,10,1,6,4,4,6,10,4,7,1,8,4,9,9,3,4,3 (la plage est 1-10) .

Nous créons 3 seaux: 1-3, 4-7, 8-10. Notez que le haut et le bas ont la même taille.

Nous remplissons les seaux avec les nombres, comptons combien tombent dans chacun, le max et le min

  • faible (5): 2,1,1,3,3, min 1, max 3
  • milieu (10): 7,5,6,4,4,6,4,7,4,4, min 4, max 7
  • haut (5): 10, 10, 8, 9, 9, min 8, max 10

La moyenne tombe dans le seau du milieu, on ne tient pas compte du reste

Nous créons 3 seaux: 4, 5-6, 7. Low commencera avec un nombre de 5 et avec un maximum de 3 et un maximum avec un minimum de 8 et un compte de 5.

Pour chaque nombre, nous comptons combien tombent dans le seau bas et haut, le max et le min, et gardons le seau du milieu.

  • vieux bas (5)
  • faible (5): 4, 4, 4, 4, 4, max 4
  • milieu (3): 5,6,6
  • haut (2): 7, 7, min 7
  • vieux haut (5)

Maintenant, nous pouvons calculer la médiane directement: nous avons une situation comme celle-ci

old low    low          middle  high  old high
x x x x x  4 4 4 4 4 4   5 6 6  7 7   x x x x x

donc la médiane est de 4,5.

En supposant que vous en savez un peu plus sur la distribution, vous pouvez affiner comment définir les plages pour optimiser la vitesse. Dans tous les cas, la performance doit aller avec O (N), car 1 + 1/3 + 1/9 ... = 1,5

Vous avez besoin de min et max à cause des cas extrêmes (par exemple, si la médiane est la moyenne entre le max de l'ancien bas et de l'élément suivant).

Toutes ces opérations peuvent être parallélisées, vous pouvez donner 1/100 des données à chaque ordinateur et calculer les 3 buckets dans chaque nœud, puis distribuer le bucket que vous conservez. Cela vous permet à nouveau d'utiliser le réseau efficacement car chaque numéro est passé en moyenne 1,5 fois (donc O (N)). Vous pouvez même battre cela si vous ne passez que les nombres minimaux entre les nœuds (par exemple, si le nœud 1 a 100 numéros et le nœud 2 a 150 numéros, alors le nœud 2 peut donner 25 numéros au nœud 1).

Sauf si vous en savez plus sur la distribution, je doute que vous puissiez faire mieux que O (N) ici, car vous devez en fait compter les éléments au moins une fois.

Sklivvz
la source
1
N'est-ce pas le pire des cas (pour votre algorithme) lorsque tous les nombres sont égaux? Si j'ai raison, aucun de vos seaux ne sera jamais rempli à part celui du milieu, avec tous les éléments. Ainsi, vous devrez parcourir tous les éléments à chaque fois, en progressant de façon exponentielle rapide jusqu'au milieu de l'intervalle. Je crois que ce serait un O(n log n)dans ce cas. Est-ce que ça fait du sens ? Au fait, j'aime votre idée
Dici
1
@Dici pas vraiment: premièrement, vous pouvez facilement raccourcir le scénario «tout de même» car vous connaissez le min et le max. Comme je l'ai dit dans la réponse, connaître la distribution pourrait guider vos choix de seau; deuxièmement, il faudrait encore o(n)+o(n/3)+o(n/9)+...ce qui est toujours o(n)et non o(n log n).
Sklivvz
D'un autre côté, il existe probablement un scénario différent du pire des cas, une distribution en forme de U. Je dois y réfléchir un peu, formaliser le pire des cas, mais cela pourrait peut-être faire pire que o(n)dans ce cas, avec le partitionnement naïf.
Sklivvz
Mmm ouais, le min et le max aideraient à gérer le cas "tout de même" assez facilement
Dici
2

Une méthode plus simple consiste à avoir des nombres pondérés.

  • Diviser le grand ensemble entre les ordinateurs
  • Trier chaque ensemble
  • parcourir le petit ensemble et calculer les poids des éléments répétés
  • fusionner chaque 2 ensembles en 1 (chacun est déjà trié) en mettant à jour les poids
  • continuez à fusionner des ensembles jusqu'à ce que vous n'obteniez qu'un seul ensemble
  • Parcourez cet ensemble en accumulant des poids jusqu'à atteindre OneBillion / 2
Ziad Nasser
la source
1

Divisez les nombres 10 ^ 9, 10 ^ 7 sur chaque ordinateur ~ 80 Mo sur chacun. Chaque ordinateur trie ses numéros. Ensuite, l'ordinateur 1 fusionne-trie ses propres nombres avec ceux de l'ordinateur 2, de l'ordinateur 3 et 4, etc ... Puis l'ordinateur 1 écrit la moitié des nombres en 2, 3 à 4, etc. Puis 1 fusion trie les nombres d'ordinateurs 1,2,3,4, les écrit en retour. Etc. En fonction de la taille de la RAM sur les ordinateurs, vous pouvez vous en sortir en ne réécrivant pas tous les nombres sur les ordinateurs individuels à chaque étape, vous pourrez peut-être accumuler les nombres sur l'ordinateur 1 pendant plusieurs étapes, mais vous faites le calcul.

Oh, obtenez enfin la moyenne des valeurs 500000000th et 500000001st (mais vérifiez qu'il y a suffisamment de 00 là-dedans, je ne l'ai pas fait).

EDIT: @Roman - eh bien, si vous ne pouvez pas le croire même si c'est vrai, il est inutile de révéler la vérité ou le mensonge de la proposition. Ce que je voulais dire, c'est que la force brute bat parfois l'intelligence dans une course. Il m'a fallu environ 15 secondes pour concevoir un algorithme que je suis sûr de pouvoir mettre en œuvre, qui fonctionnera, et qui sera adaptable à une large gamme de tailles d'entrées et de nombres d'ordinateurs, et adaptable aux caractéristiques des ordinateurs et arrangements de réseautage. Si cela vous prend, ou à quelqu'un d'autre, disons 15 minutes pour concevoir un algorithme plus sophistiqué, j'ai un avantage de 14 min 45 s pour coder ma solution et la démarrer.

Mais j'admets volontiers que tout cela est une affirmation, je n'ai rien mesuré.

Marque haute performance
la source
ici, nous ne faisons que fusionner tous les nombres. Pouvons-nous le faire d'une meilleure manière en utilisant: - "nous pouvons trouver la médiane de deux listes triées en temps de connexion. N est la longueur de chaque liste."
anony
1
@anony - pendant que vous répondez à votre propre question, je vais faire coder, tester et faire ma solution. Je m'attends à ce qu'il y ait de meilleures façons, mais parfois la mise en parallèle d'une méthode simple me laisse libre de me gratter la tête sur les problèmes vraiment difficiles.
High Performance Mark
l'avez-vous vraiment fait en 7 minutes? Je ne peux pas croire ça même si c'est vrai. J'ai fait la tâche similaire (c'était une mission universitaire) et il a fallu environ 2 heures pour implémenter et tester tous les trucs à distance (j'ai utilisé java RMI).
Roman
Je vois ce que vous dites, mais du même coup, DrPizza a une solution encore plus rapide à penser, qui consiste à trier toutes les données sur un seul nœud et à ignorer les 99 autres. Aucun de nous ne sait à quel point les données sont chères. le transfert doit être envisagé, nous ne faisons donc que choisir un compromis qui semble vaguement plausible. Votre solution transfère toutes les données plusieurs fois, donc je m'en méfie un peu, mais c'est certainement une solution.
Steve Jessop
'vaguement plausible' - c'est assez bien pour moi @Steve! Surtout en réponse à une question vaguement invraisemblable.
High Performance Mark
1

Cela pourrait être fait sur des nœuds en utilisant des données qui ne sont pas triées entre les nœuds (par exemple à partir de fichiers journaux) de la manière suivante.

Il y a 1 nœud parent et 99 nœuds enfants. Les nœuds enfants ont deux appels API:

  • stats (): renvoie min, max et count
  • compare (median_guess): renvoie la valeur de correspondance du nombre, le nombre inférieur à la valeur et le nombre supérieur à la valeur

Le nœud parent appelle stats () sur tous les nœuds enfants, en notant le minimum et le maximum de tous les nœuds.

Une recherche binaire peut maintenant être effectuée de la manière suivante:

  1. Bisectez les arrondis minimum et maximum vers le bas - il s'agit de la `` supposition '' médiane
  2. Si le nombre supérieur à est supérieur au nombre inférieur à, définissez le minimum sur l'estimation
  3. Si le nombre supérieur à est inférieur au nombre inférieur à, définissez le maximum sur la valeur
  4. Si le nombre est impair, terminer lorsque le minimum et le maximum sont égaux
  5. Si le nombre est même fini lorsque maximum <= minimum + guess.match_count Cela pourrait être fait sur les nœuds utilisant des données non triées (par exemple à partir de fichiers journaux) de la manière suivante.

Il y a 1 nœud parent et 99 nœuds enfants. Les nœuds enfants ont deux appels API:

  • stats (): renvoie min, max et count
  • compare (median_guess): renvoie la valeur de correspondance du nombre, le nombre inférieur à la valeur et le nombre supérieur à la valeur

Le nœud parent appelle stats () sur tous les nœuds enfants, en notant le minimum et le maximum de tous les nœuds.

Une recherche binaire peut maintenant être effectuée de la manière suivante:

  1. Bisectez les arrondis minimum et maximum vers le bas - il s'agit de la `` supposition '' médiane
  2. Si le nombre supérieur à est supérieur au nombre inférieur à, définissez le minimum sur l'estimation
  3. Si le nombre supérieur à est inférieur au nombre inférieur à, définissez le maximum sur la valeur
  4. Si le nombre est impair, terminer lorsque le minimum et le maximum sont égaux
  5. Si le nombre est pair, lorsque maximum <= minimum + guess.match_count

Si les stats () et compare () peuvent être pré-calculées avec un tri O (N / Mlogn / M), alors un pré-calcul O (N / M) avec une complexité mémoire de O (N) pour le pré- calcul. Ensuite, vous pouvez faire compare () en temps constant, de sorte que le tout (y compris le pré-calcul) s'exécute en O (N / MlogN / M) + O (logN)

Faites-moi savoir si j'ai fait une erreur!

théière
la source
ouais je ferais juste une recherche binaire. Économiserait la bande passante du réseau en n'appelant chaque ordinateur que quelques fois. De plus, chaque machine pourrait avoir un «pivot» où elle permute les numéros de chaque côté du pivot pour gagner du temps. (le pivot serait l'estimation précédente de la médiane, donc la prochaine fois, il suffit de parcourir tous les nombres d'un côté du pivot)
robert king
0

Que diriez-vous de ceci: - chaque nœud peut prendre 1 milliard / 100 numéros. À chaque nœud, les éléments peuvent être triés et la médiane peut être trouvée. Trouvez la médiane des médianes. nous pouvons, en agrégeant les nombres de nombres inférieurs à la médiane de la médiane sur tous les nœuds, trouver la division x%: y% que fait la médiane des médianes. Maintenant, demandez à tous les nœuds de supprimer les éléments inférieurs à la médiane des médianes (en prenant un exemple de 30%: 70% de fractionnement). 70% de 1 milliard équivaut à 700 millions. Désormais, tous les nœuds qui ont supprimé moins de 3 millions de nœuds peuvent renvoyer ces nœuds supplémentaires à un ordinateur principal. L'ordinateur principal se redistribue de telle manière que désormais tous les nœuds auront un nombre presque égal de nœuds (7 millions). Maintenant que le problème est réduit à 700 millions de nombres ... continue jusqu'à ce que nous ayons un ensemble plus petit qui peut être calculé sur un ordinateur.

anony
la source
En substance, nous réduisons toujours le problème posé d'au moins 30% et nous réalisons beaucoup de calcul parallèle grâce à cela. Chaque nœud commence par 10 millions et réduit son ensemble de données de 30% à chaque itération.
anony
Dans la première itération, nous recherchons le nombre 500Millionième. Dans la deuxième itération - si le nombre de numéros supprimés est de 300 millions, nous recherchons le 200 millionième numéro et ainsi de suite ...
Anony le
2
Cela semble être sur la bonne voie, mais vous n'expliquez pas très clairement comment éviter de gaspiller la médiane par accident avec votre partage 30% / 70%. Prenons le contre-exemple suivant: supposons que vos premiers 29% sont tous des zéros, et que tous les autres blocs comptent jusqu'à 1000, et que chaque ensemble de blocs est un de plus que le dernier. La médiane du 30e centile rejettera la totalité de 29% des données et un peu moins de la moitié de 61% des données, soit 29 + 30% = 59% des données. Oups, nous venons de jeter la vraie médiane! Donc, apparemment, vous ne le pensez pas, ou du moins vous le pensez plus intelligemment que je ne l'ai interprété.
Rex Kerr
0

Voyons d'abord comment trouver une médiane de n nombres sur une seule machine: j'utilise essentiellement une stratégie de partitionnement.

Problème: sélection (n, n / 2): Trouver le n / 2 ème nombre du plus petit nombre.

Vous choisissez par exemple l'élément central k et partitionnez les données en 2 sous-tableaux. le 1er contient tous les éléments <k et le 2ème contient tous les éléments> = k.

si sizeof (1er sous-tableau)> = n / 2, vous savez que ce sous-tableau contient la médiane. Vous pouvez ensuite jeter le 2ème sous-tableau. Résolvez ce problème de sélection (taille du 1er sous-tableau, n / 2) .

Dans le cas contraire, supprimez ce 1er sous-tableau et résolvez la sélection (2e sous-tableau, n / 2 - sizeof (1er sous-tableau))

Faites-le de manière récursive.

la complexité temporelle est le temps attendu O (n).

Maintenant, si nous avons beaucoup de machines, à chaque itération, nous devons traiter un tableau à diviser, nous distribuons le tableau en machines de diff. Chaque machine traite son morceau de tableau et renvoie le résumé à la machine de contrôle du concentrateur, c'est-à-dire la taille du premier sous-tableau et la taille du deuxième sous-tableau. Les machines à moyeu additionnent les résumés et décident quel sous-tableau (1er ou 2ème) traiter plus loin et 2ème paramètre de sélection et le renvoie à chaque machine. etc.

Cet algorithme peut être mis en œuvre très proprement à l'aide de la réduction de carte?

De quoi ça a l'air?

xyz
la source
0

Je pense que la réponse de Steve Jessop sera la plus rapide.

Si la taille du transfert de données réseau est le goulot d'étranglement, voici une autre approche.

Divide the numbers into 100 computers (10 MB each). 
Loop until we have one element in each list     
    Find the meadian in each of them with quickselect which is O(N) and we are processing in parallel. The lists will be partitioned at the end wrt median.
    Send the medians to a central computer and find the median of medians. Then send the median back to each computer. 
    For each computer, if the overall median that we just computed is smaller than its median, continue in the lower part of the list (it is already partitioned), and if larger in the upper part.
When we have one number in each list, send them to the central computer and find and return the median.
Cem
la source
32 Mo chacun, vous voulez dire?
Dici
Qu'entendez-vous par continuer dans la partie inférieure de la liste?
Ruthvik Vaila
0

Je le ferais comme ceci:

au début, tous les 100 travaillent pour trouver le nombre le plus élevé et le plus petit; chacun des ordinateurs a sa part de la base de données / du fichier qu'il interroge;

lorsque les nombres les plus élevés et les plus bas sont trouvés, un ordinateur lit les données et distribue chaque nombre, également, au reste des 99; les nombres sont distribués par intervalles égaux; (l'un peut prendre de -100 millions à 0, un autre - de 0 à 100 millions, etc.);

Lors de la réception des numéros, chacun des 99 ordinateurs les trie déjà;

Ensuite, il est facile de trouver la médiane ... Voyez combien de nombres a chaque ordinateur, ajoutez-les tous (la somme de combien de nombres il y a, pas les nombres eux-mêmes), divisez par 2; calculer dans quel ordinateur se trouve le nombre et à quel index;

:) voilla

PS On dirait qu'il y a beaucoup de confusion ici; le MEDIAN - est le NOMBRE AU MILIEU D'UNE LISTE DE NOMBRES TRIÉE!

Johny
la source
0

Vous pouvez utiliser la méthode de l'arborescence des tournois pour trouver la médiane. Nous pouvons créer un arbre avec 1000 nœuds de sortie de sorte que chaque nœud de feuille soit un tableau. Nous menons ensuite n / 2 tournois entre les différents tableaux. La valeur à la racine après les n / 2 tournois est le résultat.

http://www.geeksforgeeks.org/tournament-tree-and-binary-heap/

Karan Kapoor
la source
0

Si les nombres ne sont pas distincts et n'appartiennent qu'à une certaine gamme, c'est-à-dire qu'ils sont répétés, alors une solution simple qui me vient à l'esprit est de répartir les nombres entre 99 machines de manière égale et de garder une machine comme maître. Maintenant, chaque machine itère sur ses nombres donnés et stocke le nombre de chaque nombre dans un ensemble de hachage. Chaque fois que le nombre est répété dans l'ensemble de nombres attribués à cet ordinateur particulier, il met à jour son décompte dans l'ensemble de hachage.

Toutes les machines renvoient ensuite leur jeu de hachage à la machine maître. La machine maître combine les ensembles de hachage, additionnant le nombre de la même clé trouvée dans un ensemble de hachage. Par exemple, le jeu de hachage de la machine n ° 1 avait une entrée de ("1", 7) et le jeu de hachage de la machine n ° 2 avait une entrée de ("1", 9). ("1", 16), et ainsi de suite.

Une fois que les ensembles de hachage ont été fusionnés, triez simplement les clés, et maintenant vous pouvez facilement trouver le (n / 2) ème élément et le (n + 2/2) ème élément, à partir du jeu de hachage trié.

Cette méthode ne sera pas bénéfique si les milliards de nombres sont distincts.

Éric B.
la source
0

Eh bien, supposons que vous sachiez que le nombre d'entiers distincts est (disons) de 4 milliards, alors vous pouvez les regrouper dans 64k buckets et obtenir un décompte distribué pour chaque bucket de chaque machine du cluster (100 ordinateurs). Combinez tous ces facteurs. Maintenant, recherchez le compartiment qui a la médiane, et cette fois ne demandez que des compartiments pour les 64 000 éléments qui se trouveraient dans votre compartiment cible. Cela nécessite des requêtes O (1) (spécifiquement 2) sur votre "cluster". :RÉ

gandharv garg
la source
0

Mon centime, après tout ce qui a déjà été soulevé par d'autres:

Trouver la médiane sur une seule machine est O (N): https://en.wikipedia.org/wiki/Selection_algorithm .

L'envoi de numéros N à 100 machines est également O (N). Donc, pour rendre l'utilisation de 100 machines intéressante, soit la communication doit être relativement rapide, soit N est si grand qu'une seule machine ne peut pas le gérer alors que N / 100 est faisable, soit nous voulons simplement considérer le problème mathématique sans nous soucier de communication de données.

Pour couper court, je suppose donc que, dans des limites raisonnables, nous pouvons envoyer / distribuer les chiffres sans affecter l'analyse d'efficacité.

Considérons alors l'approche suivante, où une machine est assignée pour être le "maître" pour un traitement général. Ce sera relativement rapide, de sorte que le «maître» participe également aux tâches courantes que chaque machine effectue.

  1. Chaque machine reçoit N / 100 des nombres, calcule sa propre médiane et envoie cette information au maître.
  2. Le maître compile une liste triée de toutes les médianes distinctes et la renvoie à chaque machine, définissant une séquence ordonnée de compartiments (sur chaque machine de la même manière), un pour chaque valeur médiane (un compartiment à valeur unique) et un pour chaque intervalle entre médianes adjacentes. Bien sûr, il existe également les compartiments inférieur et supérieur pour les valeurs inférieures à la médiane la plus basse et supérieures à la plus élevée.
  3. Chaque machine calcule le nombre de nombres compris dans chaque compartiment et communique ces informations au maître.
  4. Le maître détermine quel compartiment contient la médiane, combien de valeurs inférieures (au total) tombent en dessous de ce compartiment et combien au-dessus.
  5. Si le compartiment sélectionné est un compartiment à valeur unique (l'une des médianes) ou si le compartiment sélectionné ne contient que 1 (N impair) ou 2 (N pair) valeurs, nous avons terminé. Sinon, nous répétons les étapes ci-dessus avec les modifications (évidentes) suivantes:
  6. Seuls les numéros du bucket sélectionné sont (re) distribués du maître aux 100 machines, et de plus
  7. Nous n'allons pas calculer (sur chaque machine) la médiane, mais la valeur k-ème, où nous prenons en compte le nombre de nombres plus élevés qui ont été écartés du total et le nombre de nombres inférieurs. Conceptuellement, chaque machine a également sa part des nombres faibles / élevés rejetés et en tient compte lors du calcul de la nouvelle médiane dans l'ensemble qui (conceptuellement) comprend (sa part) des nombres rejetés.

Complexité temporelle:

  1. Un peu de réflexion vous convaincra qu'à chaque étape, le nombre total de valeurs à analyser est réduit d'un facteur au moins deux (2 serait un cas plutôt malade; vous pouvez vous attendre à une réduction nettement meilleure). De cela, nous obtenons:
  2. En supposant que trouver la médiane (ou k-ème valeur), qui est O (N), prend c * N temps où le préfacteur c ne varie pas trop fortement avec N pour que nous puissions le prendre comme constante pour le moment, nous Nous obtiendrons notre résultat final dans au plus 2 * c * N / 100 fois. L'utilisation de 100 machines nous donne donc un facteur d'accélération de 100/2 (au moins).
  3. Comme remarqué initialement: le temps nécessaire pour communiquer les numéros entre les machines peut rendre plus attrayant de simplement tout faire sur une seule machine. Cependant, SI nous optons pour l'approche distribuée, le nombre total de nombres à communiquer dans toutes les étapes ne dépassera pas 2 * N (N pour la première fois, <= N / 2 la deuxième fois, <= la moitié de celui troisième, et ainsi de suite).
Bert te Velde
la source
-1
  1. Divisez le milliard de nombres en 100 machines. Chaque machine aura 10 ^ 7 numéros.

  2. Pour chaque numéro entrant sur une machine, enregistrez le numéro dans une carte de fréquences, nombre -> compte. Enregistrez également le nombre minimum dans chaque machine.

  3. Trouvez la médiane dans chaque machine: à partir du nombre minimum de chaque machine, additionnez les comptages jusqu'à ce que l'indice médian soit atteint. La médiane dans chaque machine, sera le env. inférieur et supérieur à 5 * 10 ^ 6 nombres.

  4. Trouvez la médiane de toutes les médianes, qui sera inférieure et supérieure à env. 50 * 10 ^ 7 nombres, qui est la médiane de 1 milliard de nombres.

Maintenant une certaine optimisation de la 2ème étape: au lieu de stocker dans une carte de fréquence, stockez les comptes dans un tableau de bits variable. Par exemple: disons à partir du nombre minimum dans une machine, ce sont des comptages de fréquence:

[min number] - 8 count
[min+1 number] - 7 count
[min+2 number] - 5 count

Ce qui précède peut être stocké dans un tableau de bits comme:

[min number] - 10000000
[min+1 number] - 1000000
[min+2 number] - 10000

Notez qu'au total, cela coûtera environ 10 ^ 7 bits pour chaque machine, puisque chaque machine ne gère que 10 ^ 7 nombres. 10 ^ 7bits = 1,25 * 10 ^ 6 octets, soit 1,25 Mo

Ainsi, avec l'approche ci-dessus, chaque machine aura besoin de 1,25 Mo d'espace pour calculer la médiane locale. Et la médiane des médianes peut être calculée à partir de ces 100 médianes locales, ce qui donne une médiane de 1 milliard de nombres.

Shiv
la source
Et si les nombres sont des flottants?
Sklivvz
-1

Je suggère une méthode pour calculer approximativement la médiane. :) Si ces un milliard de nombres sont dans un ordre aléatoire, je pense que je peux choisir au hasard 1/100 ou 1/10 d'un milliard de nombres, les trier avec 100 machines, puis choisir la médiane d'entre eux. Ou divisons un milliard de nombres en 100 parties, laissez chaque machine choisir au hasard 1/10 de chaque partie, calculez la médiane d'entre eux. Après cela, nous avons 100 nombres et nous pouvons calculer la médiane du nombre 100 plus facilement. Juste une suggestion, je ne sais pas si c'est mathématiquement correct. Mais je pense que vous pouvez montrer le résultat à un gestionnaire pas très doué en mathématiques.

garçon paresseux
la source
Ce n'est évidemment pas correct, et je vous recommande fortement de ne jamais supposer que votre intervieweur est un cochon stupide que vous pouvez tromper
Dici
Haha ok, bien que cela ne change pas le fait que votre réponse est incorrecte. C'est très facile de le prouver
Dici
OK, après avoir lu une conférence sur les statistiques, je pense que l'idée de ramasser au hasard 1/100 ou même 1/1000 d'un milliard et calculer leur médiane n'est pas si mauvaise. C'est juste un calcul approximatif.
lazyboy
-3

La réponse de Steve Jessop est fausse:

prendre en compte les quatre groupes suivants:

{2, 4, 6, 8, 10}

{21, 21, 24, 26, 28}

{12, 14, 30, 32, 34}

{16, 18, 36, 38, 40}

La médiane est de 21, qui fait partie du deuxième groupe.

La médiane des quatre groupes est 6, 24, 30, 36, la médiane totale est de 27.

Ainsi, après la première boucle, les quatre groupes deviendront:

{6, 8, 10}

{24, 26, 28}

{12, 14, 30}

{16, 18, 36}

Le 21 est déjà jeté à tort.

Cet algorithme ne prend en charge le cas que lorsqu'il y a deux groupes.

Seigneur des Ténèbres
la source