web-dev-qa-db-fra.com

Comment trouver la médiane des nombres en temps linéaire à l'aide de tas?

Wikipedia dit: 

Algorithmes de sélection: Trouver le min, max, les min et max, médian, ou même le k-ème plus grand élément peut être fait en temps linéaire en utilisant des tas.

Tout ce que cela dit, c'est que cela peut être fait, et non comment.

Pouvez-vous m'expliquer comment cela peut être fait en utilisant des tas?

50
Lazer

Vous utiliseriez un segment min-max-médian pour rechercher les valeurs min, max et médiane en temps constant (et prendre un temps linéaire pour construire le segment). Vous pouvez utiliser les arbres de statistiques d'ordre pour trouver la kième valeur la plus petite/la plus grande. Ces deux structures de données sont décrites dans le présent document sur les tas min-max [lien pdf] . Les tas Min-Max sont des tas binaires qui alternent entre tas-tas et max-tas.

Extrait de l'article: Un segment min-max-median est un segment binaire possédant les propriétés suivantes:

1) La médiane de tous les éléments est située à la racine

2) Le sous-arbre gauche de la racine est un tas min-max Hl de taille plafond [((n-1)/2)] contenant des éléments inférieurs ou égaux à la médiane. Le sous-arbre de droite est un segment de mémoire max-min Hr de taille floor [((n-1)/2)] ne contenant que des éléments supérieurs ou égaux à la médiane.

Le papier continue en expliquant comment construire un tel tas.

Edit: Après une lecture plus approfondie du papier, il semble que la construction des tas min-max-médian nécessite que vous trouviez d’abord la médiane (FTA: "Recherchez la médiane de tous les n éléments à l’aide d’un des algorithmes de temps linéaire connus") . Cela dit, une fois que vous avez créé le tas, vous pouvez maintenir la médiane simplement en maintenant l’équilibre entre le tas min-max à gauche et le tas max-min à droite. DeleteMedian remplace la racine par le min du tas max-min ou le max du tas min-max (selon le maintien de l'équilibre).

Donc, si vous prévoyez d'utiliser un segment min-max-médian pour trouver la médiane d'un ensemble de données fixe, vous êtes SOL, mais si vous l'utilisez sur un ensemble de données en évolution, c'est possible.

21
Niki Yoshiuchi

Voir cette page wikipedia sur les algorithmes de sélection . En particulier, regardez l'algorithme BFPRT et l'algorithme Median of Medians. La BFPRT est linéairement probabiliste et est modelée sur le tri rapide; La médiane des médianes est garantie linéaire, mais a un facteur constant important et peut donc prendre plus de temps en pratique, en fonction de la taille de votre jeu de données.

Si vous n'avez que quelques centaines ou mille éléments parmi lesquels sélectionner la médiane, je soupçonne qu'un simple tri rapide suivi d'une indexation directe est le plus simple.

4
Dale Hagglund

Il existe probablement de meilleurs algorithmes, mais voici comment procéder:

Avoir deux seaux et une valeur. La valeur est la médiane, les deux compartiments sont "plus grands que la médiane" et "plus petits que la médiane". Pour chaque élément x du tableau, rééquilibrez les compartiments de sorte que big_bucket et small_bucket ne diffèrent pas plus de 1 dans leur taille. Lorsque vous déplacez des objets d'un grand bac à un autre, ils doivent d'abord passer par la valeur médiane pour y arriver (autrement dit, une différence de 2 réussira à pousser un élément d'un godet à l'autre - une différence de 1 poussera un élément d’un seau à la valeur médiane). À la fin de votre premier passage dans le tableau, la valeur doit être votre médiane.

4
fbrereto

peut-être que la question initiale n’était plus disponible, mais wiki a maintenant un lien vers la source, et le voici: http://ftp.cs.purdue.edu/research/technical_reports/1991/TR%2091- 027.pdf

plus précisément, allez à la page 17 et regardez la description de RSEL4. Ils prouvent dans le théorème 3.2 que la complexité temporelle de cet k-ème algorithme de sélection est O (k). il vous faudrait donc O(n) pour construire le tas, et un O(k) supplémentaire pour trouver le k-ième élément le plus petit.

ce n'est pas vraiment aussi simple que certaines des autres réponses ont suggéré

3
Shlomi

si vous en savez plus sur la structure de données en tas, vous comprendrez facilement que c’est le cas. la structure de tas peut être construite en O(n) temps, il y a min heap et max heap. L'élément racine min. tas vous donnera le plus petit élément. L'élément racine max heap vous donnera l'élément max. Juste en construisant le tas, vous trouvez le min et le max. Même idée pour la médiane et la kième plus grande, tout en construisant votre tas, vous pouvez trouver la médiane et la kième plus grande en regardant la branche gauche ou droite de l'arbre et en gardant une quantité de mémoire constante pour stocker le nombre d'éléments. etc.

0
DarthVader

Stockez le premier entier du tableau et définissez un compteur sur 1. Puis parcourez les entiers restants du vecteur. Si le nombre entier actuel dans le tableau est identique à celui stocké, le compteur est augmenté de un, sinon le compteur est diminué de un. Si le compteur atteint zéro, jetez le nombre entier stocké et remplacez-le par le nombre entier actuel du tableau. Lorsque vous avez enfin parcouru tous les entiers, il ne vous reste plus qu’un candidat. Vous devez ensuite parcourir à nouveau le tableau et compter l'occurrence du candidat pour vérifier qu'il s'agit bien d'un dominateur. 

static int FindDominator(int[] arr)
{
int counter = 1;
int candidate = arr[0];
for(int i = 1; i < n; i++)
{
   if(arr[i] == candidate) counter++
    else 
   {
        counter--;
        if(counter == 0) { candidate = arr[i]; counter = 1; }
    }
}
counter = 0;
for(int i = 0;  i < n; i++)
{
    if(arr[i] == candidate) counter++;
}
if(counter > n / 2) return candidate;
else return -1;
}
0
jaycee