web-dev-qa-db-fra.com

Recherche de la médiane d'un tableau non trié

Pour trouver la médiane d'un tableau non trié, nous pouvons créer un min-tas en O(nlogn) temps pour n éléments, puis extraire un à un n/2 éléments pour obtenir la médiane. Mais cette approche prendrait O(nlogn) temps.

Pouvons-nous faire la même chose par une méthode quelconque dans O(n) temps? Si nous pouvons, alors s'il vous plaît dites ou suggérez une méthode.

41
Luv

Vous pouvez utiliser l'algorithme Médiane des médianes pour trouver la médiane d'un tableau non trié en temps linéaire.

35
dasblinkenlight

J'ai déjà voté pour la réponse @dasblinkenlight puisque l'algorithme Median of Medians résout en fait ce problème en O(n) temps. Je veux seulement ajouter que ce problème pourrait être résolu dans O(n) temps en utilisant également des tas. Construire un tas peut être fait en O(n) en utilisant la méthode ascendante. Jetez un oeil à l'article suivant pour une explication détaillée Tri par tas

En supposant que votre tableau ait N éléments, vous devez créer deux tas: un MaxHeap contenant les N/2 premiers éléments (ou (N/2) +1 si N est impair) et un MinHeap contenant les éléments restants. Si N est impair, votre médiane est l’élément maximum de MaxHeap (O (1) en obtenant le maximum). Si N est pair, alors votre médiane est (MaxHeap.max () + MinHeap.min ())/2, cela prend également O(1). Ainsi, le coût réel de l’ensemble de l’opération correspond à l’opération de construction des tas, qui est O (n).

BTW cet algorithme MaxHeap/MinHeap fonctionne également lorsque vous ne connaissez pas à l’avance le nombre d’éléments du tableau (si vous devez résoudre le même problème pour un flux d’entiers, par exemple). Vous pouvez voir plus de détails sur la façon de résoudre ce problème dans l'article suivant Médiane de flux entiers

14
rkachach

Quickselect fonctionne dans O (n), ceci est également utilisé dans l'étape de partition de Quicksort.

10
BrokenGlass

L'algorithme de sélection rapide peut trouver le k-ème plus petit élément d'un tableau en temps d'exécution linéaire (O(n)). Voici une implémentation en python:

import random

def partition(L, v):
    smaller = []
    bigger = []
    for val in L:
        if val < v: smaller += [val]
        if val > v: bigger += [val]
    return (smaller, [v], bigger)

def top_k(L, k):
    v = L[random.randrange(len(L))]
    (left, middle, right) = partition(L, v)
    # middle used below (in place of [v]) for clarity
    if len(left) == k:   return left
    if len(left)+1 == k: return left + middle
    if len(left) > k:    return top_k(left, k)
    return left + middle + top_k(right, k - len(left) - len(middle))

def median(L):
    n = len(L)
    l = top_k(L, n / 2 + 1)
    return max(l)
9
doizuc

Comme le dit wikipedia, Median-of-Medians est théoriquement o (N), mais il n’est pas utilisé dans la pratique car il est trop lent pour trouver de "bons" pivots.
http://en.wikipedia.org/wiki/Selection_algorithm

Voici le code source Java d'un algorithme Quickselect permettant de trouver l'élément k'th dans un tableau:

/**
 * Returns position of k'th largest element of sub-list.
 * 
 * @param list list to search, whose sub-list may be shuffled before
 *            returning
 * @param lo first element of sub-list in list
 * @param hi just after last element of sub-list in list
 * @param k
 * @return position of k'th largest element of (possibly shuffled) sub-list.
 */
static int select(double[] list, int lo, int hi, int k) {
    int n = hi - lo;
    if (n < 2)
        return lo;

    double pivot = list[lo + (k * 7919) % n]; // Pick a random pivot

    // Triage list to [<pivot][=pivot][>pivot]
    int nLess = 0, nSame = 0, nMore = 0;
    int lo3 = lo;
    int hi3 = hi;
    while (lo3 < hi3) {
        double e = list[lo3];
        int cmp = compare(e, pivot);
        if (cmp < 0) {
            nLess++;
            lo3++;
        } else if (cmp > 0) {
            swap(list, lo3, --hi3);
            if (nSame > 0)
                swap(list, hi3, hi3 + nSame);
            nMore++;
        } else {
            nSame++;
            swap(list, lo3, --hi3);
        }
    }
    assert (nSame > 0);
    assert (nLess + nSame + nMore == n);
    assert (list[lo + nLess] == pivot);
    assert (list[hi - nMore - 1] == pivot);
    if (k >= n - nMore)
        return select(list, hi - nMore, hi, k - nLess - nSame);
    else if (k < nLess)
        return select(list, lo, lo + nLess, k);
    return lo + k;
}

Je n'ai pas inclus le source des méthodes de comparaison et d'échange. Il est donc facile de modifier le code pour qu'il fonctionne avec Object [] au lieu de double [].

En pratique, vous pouvez vous attendre à ce que le code ci-dessus soit o (N).

0
Adam Gawne-Cain

Cela peut être fait en utilisant l'algorithme Quickselect dans O (n), référez-vous aux statistiques d'ordre K (algorithmes aléatoires). 

0
Imposter