web-dev-qa-db-fra.com

Comprendre l'algorithme «médiane des médianes»

Je veux comprendre l'algorithme "médiane des médianes" sur l'exemple suivant:

Nous avons 45 numéros distincts divisés en 9 groupes de 5 éléments chacun.

48 43 38 33 28 23 18 13 8

49 44 39 34 29 24 19 14 9 

50 45 40 35 30 25 20 15 10

51 46 41 36 31 26 21 16 53

52 47 42 37 32 27 22 17 54
  1. La première étape consiste à trier chaque groupe (dans ce cas, ils sont déjà triés)
  2. Deuxième étape récursivement, trouvez la "vraie" médiane des médianes (50 45 40 35 30 25 20 15 10) C'est-à-dire que l'ensemble sera divisé en 2 groupes:

    50 25
    
    45 20 
    
    40 15
    
    35 10
    
    30
    

    trier ces 2 groupes

    30 10
    
    35 15 
    
    40 20
    
    45 25
    
    50
    

la médiane est de 40 et 15 (dans le cas où les chiffres sont égaux, nous avons pris la médiane de gauche), donc la valeur renvoyée est de 15 cependant la "vraie" médiane de médiane (50 45 40 35 30 25 20 15 10) est de 30, de plus il y a 5 éléments de moins que 15 qui sont beaucoup moins de 30% des 45 qui sont mentionnés dans wikipedia

et donc T(n) <= T(n/5) + T(7n/10) + O(n) échoue.

Soit dit en passant, dans l'exemple de Wikipedia, le résultat de la récursivité est 36. Cependant, la vraie médiane est 47.

Donc, je pense que dans certains cas, cette récursivité peut ne pas retourner la vraie médiane des médianes. Je veux comprendre où est mon erreur.

55
simon

Le problème est dans l'étape où vous dites de trouver la vraie médiane des médianes. Dans votre exemple, vous aviez ces médianes:

50 45 40 35 30 25 20 15 10

La vraie médiane de cet ensemble de données est de 30, pas de 15. Vous ne trouvez pas cette médiane en divisant les groupes en blocs de cinq et en prenant la médiane de ces médianes, mais plutôt en appelant récursivement l'algorithme de sélection sur ce groupe plus petit. L'erreur dans votre logique suppose que la médiane de ce groupe est trouvée en divisant la séquence ci-dessus en deux blocs

50 45 40 35 30

et

25 20 15 10

puis trouver la médiane de chaque bloc. Au lieu de cela, l'algorithme médiane des médianes s'appellera récursivement sur l'ensemble de données complet 50 45 40 35 30 25 20 15 10. En interne, cela divisera le groupe en blocs de cinq et les triera, etc., mais il le fait pour déterminer le point de partition pour l'étape de partitionnement, et c'est dans cette étape de partitionnement que l'appel récursif trouvera la vraie médiane des médianes , qui dans ce cas sera de 30. Si vous utilisez 30 comme médiane comme étape de partitionnement dans l'algorithme d'origine, vous obtenez en effet une très bonne répartition selon les besoins.

J'espère que cela t'aides!

33
templatetypedef

Voici l'algorithme pseudocode pour la médiane des médianes (légèrement modifié en fonction de votre exemple). Le pseudocode dans wikipedia ne décrit pas le fonctionnement interne de l'appel de fonction selectIdx.

J'ai ajouté des commentaires au code pour explication.

// L is the array on which median of medians needs to be found.
// k is the expected median position. E.g. first select call might look like:
// select (array, N/2), where 'array' is an array of numbers of length N

select(L,k)
{

    if (L has 5 or fewer elements) {
        sort L
        return the element in the kth position
    }

    partition L into subsets S[i] of five elements each
        (there will be n/5 subsets total).

    for (i = 1 to n/5) do
        x[i] = select(S[i],3)

    M = select({x[i]}, n/10)

    // The code to follow ensures that even if M turns out to be the
    // smallest/largest value in the array, we'll get the kth smallest
    // element in the array

    // Partition array into three groups based on their value as
    // compared to median M

    partition L into L1<M, L2=M, L3>M

    // Compare the expected median position k with length of first array L1
    // Run recursive select over the array L1 if k is less than length
    // of array L1
    if (k <= length(L1))
        return select(L1,k)

    // Check if k falls in L3 array. Recurse accordingly
    else if (k > length(L1)+length(L2))
        return select(L3,k-length(L1)-length(L2))

    // Simply return M since k falls in L2
    else return M

}

Prenons votre exemple:

La fonction médiane des médianes sera appelée sur l'ensemble du tableau de 45 éléments comme (avec k = 45/2 = 22):

median = select({48 49 50 51 52 43 44 45 46 47 38 39 40 41 42 33 34 35 36 37 28 29 30 31 32 23 24 25 26 27 18 19 20 21 22 13 14 15 16 17 8 9 10 53 54}, 45/2)
  1. La première fois que M = select({x[i]}, n/10) est appelée, le tableau {x[i]} Contiendra les nombres suivants: 50 45 40 35 30 20 15 10. Dans cet appel, n = 45, Et donc l'appel de la fonction de sélection sera M = select({50 45 40 35 30 20 15 10}, 4)

  2. La deuxième fois que M = select({x[i]}, n/10) est appelée, le tableau {x[i]} Contiendra les nombres suivants: 40 20. Dans cet appel, n = 9 Et donc l'appel sera M = select({40 20}, 0). Cet appel de sélection renvoie et attribue la valeur M = 20.

    Maintenant, au point où vous aviez un doute, nous partitionnons maintenant le tableau L autour de M = 20 Avec k = 4.

    N'oubliez pas le tableau L voici: 50 45 40 35 30 20 15 10.

    La baie sera partitionnée en L1, L2 Et L3 Selon les règles L1 < M, L2 = M Et L3 > M. Par conséquent:
    L1: 10 15
    L2: 20
    L3: 30 35 40 45 50

    Puisque k = 4, Il est supérieur à length(L1) + length(L2) = 3. Par conséquent, la recherche se poursuivra avec l'appel récursif suivant maintenant:
    return select(L3,k-length(L1)-length(L2))

    qui se traduit par:
    return select({30 35 40 45 50}, 1)

    qui renverra 30 en conséquence. (puisque L a 5 éléments ou moins, il renverra donc l'élément en kème, c'est-à-dire 1ère position dans le tableau trié, qui est 30).

Maintenant, M = 30 Sera reçu lors du premier appel de fonction select sur l'ensemble du tableau de 45 éléments, et la même logique de partitionnement qui sépare le tableau L autour de M = 30 s'appliquera pour obtenir enfin la médiane des médianes.

Phew! J'espère avoir été assez verbeux et assez clair pour expliquer l'algorithme de la médiane des médianes.

26
sultan.of.swing