Понимание медианы алгоритма медиан

Я хочу понять алгоритм «медианы медиан» на следующем примере:

У нас есть 45 различных чисел, разделенных на 9 групп по 5 элементов в каждой.

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. Первый шаг — сортировка каждой группы (в данном случае они уже отсортированы)
  2. Второй шаг рекурсивно найти "истинную" медиану медиан (50 45 40 35 30 25 20 15 10) т.е. множество будет разделено на 2 группы:

    50 25
    
    45 20 
    
    40 15
    
    35 10
    
    30
    

    сортировка этих 2 групп

    30 10
    
    35 15 
    
    40 20
    
    45 25
    
    50
    

медианы равны 40 и 15 (в случае, если числа четные, мы взяли левую медиану), поэтому возвращаемое значение равно 15, однако «истинная» медиана медиан (50 45 40 35 30 25 20 15 10) равна 30, кроме того, есть 5 элементов меньше 15, которые намного меньше 30% из 45, которые упоминаются в википедия

и поэтому T(n) <= T(n/5) + T(7n/10) + O(n) терпит неудачу.

Кстати, в примере с Википедии я получаю результат рекурсии как 36. Однако истинная медиана равна 47.

Итак, я думаю, что в некоторых случаях эта рекурсия может не возвращать истинную медиану медиан. Я хочу понять, где моя ошибка.


person simon    schedule 28.02.2012    source источник
comment
@kaoD: Политика сообщества сайта. Признайте, что это домашнее задание. См.: meta.stackexchange.com/a/10812.   -  person Orbling    schedule 29.02.2012
comment
@kaoD: Нет ничего плохого в публикации вопроса о домашнем задании, но это влияет на то, как большинство участников отвечают на вопрос. Таким образом, это должно быть заявлено как таковое, и показано, какой прогресс был достигнут. Ответы обычно представляют собой попытки направить, а не решить.   -  person Orbling    schedule 29.02.2012
comment
@Orbling это актуально? Какой бы ни была причина этого вопроса, smnvhn (как и другие) сможет извлечь урок из хорошего ответа. Думаю, сам по себе вопрос уже показывает, что smnvhn уже кое-что обдумал. Таким образом, если это окажется действительно домашним заданием, постер узнает больше из любых опубликованных замечаний или ответов.   -  person Joris    schedule 29.02.2012
comment
@Orbling нет, это не домашнее задание, я только что пришел к этому вопросу, читая эту книгу «Введение в алгоритмы» Томаса Х. Кормена, Чарльза Э. Лейзерсона, Рональда Л. Ривеста и Клиффорда Штейна.   -  person simon    schedule 29.02.2012
comment
@smnvhn: Поскольку это похоже на вопрос из книги, а это и есть интересная книга, вы можете понять, почему я мог подумать, что это домашнее задание. Это стандартная практика, чтобы спросить, просто для ясности в этом случае - без обид, спасибо за разъяснение. :-)   -  person Orbling    schedule 29.02.2012


Ответы (2)


Проблема заключается в шаге, где вы говорите найти истинную медиану медиан. В вашем примере у вас были эти медианы:

50 45 40 35 30 25 20 15 10

Истинная медиана этого набора данных равна 30, а не 15. Вы не найдете эту медиану, разбивая группы на блоки по пять и взяв медиану этих медиан, а вместо этого рекурсивно вызывая алгоритм выбора для этой меньшей группы. Ошибка в вашей логике предполагает, что медиана этой группы находится путем разделения приведенной выше последовательности на два блока.

50 45 40 35 30

и

25 20 15 10

затем найти медиану каждого блока. Вместо этого алгоритм медианы медиан будет рекурсивно вызывать себя на полном наборе данных 50 45 40 35 30 25 20 15 10. Внутренне это разделит группу на блоки из пяти и отсортирует их и т. д., но это делается для определения точки разделения для шага разделения, и именно на этом шаге разделения рекурсивный вызов найдет истинную медиану медиан. , что в данном случае будет равно 30. Если вы используете 30 в качестве медианы в качестве шага разбиения в исходном алгоритме, вы действительно получите очень хорошее разделение, как и требовалось.

Надеюсь это поможет!

person templatetypedef    schedule 28.02.2012
comment
Я не мог понять из той части, где вы пытаетесь определить разницу между ошибкой smnvhn и внутренним разделением на блоки по пять. Насколько они разные? Не могли бы вы продолжить пример smnvhn после описания его ошибки? Я понимаю, что после рекурсии в новом массиве массив снова будет разделен на группы по пять, как говорит smnvhn, и, таким образом, он снова пройдет [40, 15] в следующей рекурсии, поэтому снова будет возвращено 15. - person ; 08.12.2013
comment
более того, в этом примере поиск раздела не поможет, так как массив уже отсортирован, и поэтому какой бы из 9 элементов вы ни выбрали, ваш массив останется неизменным. - person ; 08.12.2013
comment
@templatetypedef, не могли бы вы рассказать об этом подробнее. Похоже, что рекурсивный подход неверен, потому что он делает то же самое, что автор пробовал в вопросе. - person Oleg Yaroshevych; 12.01.2015
comment
@templatetypedef Я случайно проголосовал за ваш ответ. Переполнение стека не позволяет мне вернуться сейчас с сообщением, что ваш голос теперь заблокирован, если этот ответ не отредактирован. Можете ли вы сделать небольшую правку, чтобы я мог проголосовать? - person sultan.of.swing; 22.01.2015

Вот псевдокод для медианного алгоритма медиан (слегка измененный для вашего примера). Псевдокод в википедии не отражает внутреннюю работу вызова функции selectIdx.

Я добавил комментарии к коду для объяснения.

// 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

}

Взяв ваш пример:

Функция медианы медиан будет вызываться по всему массиву из 45 элементов, например (с 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. При первом вызове M = select({x[i]}, n/10) массив {x[i]} будет содержать следующие числа: 50 45 40 35 30 20 15 10. В этом вызове n = 45, и, следовательно, вызов функции select будет M = select({50 45 40 35 30 20 15 10}, 4)

  2. При втором вызове M = select({x[i]}, n/10) массив {x[i]} будет содержать следующие числа: 40 20. В этом вызове n = 9 и, следовательно, вызов будет M = select({40 20}, 0). Этот вызов выбора вернется и присвоит значение M = 20.

    Теперь, переходя к тому моменту, когда у вас возникли сомнения, теперь мы разделим массив L вокруг M = 20 с k = 4.

    Запомни массив L вот: 50 45 40 35 30 20 15 10.

    Массив будет разбит на L1, L2 и L3 по правилам L1 < M, L2 = M и L3 > M. Следовательно:
    L1: 10 15
    L2: 20
    L3: 30 35 40 45 50

    Поскольку k = 4 больше length(L1) + length(L2) = 3. Таким образом, теперь поиск будет продолжен со следующим рекурсивным вызовом:
    return select(L3,k-length(L1)-length(L2))

    что переводится как:
    return select({30 35 40 45 50}, 1)

    который в результате вернет 30. (поскольку L имеет 5 или меньше элементов, следовательно, он вернет элемент в k-й, т.е. 1-й позиции в отсортированном массиве, что равно 30).

Теперь M = 30 будет получено при первом вызове функции select по всему массиву из 45 элементов, и та же логика разбиения, которая разделяет массив L вокруг M = 30, будет применена для окончательного получения медианы медиан.

Фу! Надеюсь, я был достаточно подробным и ясным, чтобы объяснить алгоритм медианы медианы.

person sultan.of.swing    schedule 22.01.2015
comment
Я думаю, что этот ответ заслуживает, по крайней мере, повышения голосов. - person Milad Naseri; 13.07.2015
comment
Я искал медиану расчета медианы и нашел эту тему. Я попытался перестроить псевдокод в java, но получаю исключение из-за длины массива во втором вызове select... Может кто-нибудь объяснить, что означают x[i] и {x[i]}? и какой размер должен быть? Спасибо! - person D. Müller; 11.09.2015
comment
Проголосовали против, поскольку все переменные состоят из одной буквы, что значительно усложняет понимание кода. - person Rick Mac Gillis; 17.10.2015
comment
@RickMacGillis Я бы посчитал, что однобуквенные переменные здесь хороши. Конечно, комментарий в начале должен объяснять переменные M и x, но в остальном это похоже на любую книгу по математике. Вы никогда не увидите 1 + an_unknown_value = 3 вместо 1 + x = 3 ни в одном учебнике по математике. - person Mikko Rantalainen; 22.09.2016
comment
не могу поверить, что этот алгоритм O (n)! - person Varun Garg; 15.10.2016
comment
Если мы пишем такой массивный код для нахождения медианы, мы также должны отсортировать эти 5 чисел с минимальными сравнениями: -5-отличных-ключей-в-меньшем-чем-8-сравнении" title="разработайте эффективный алгоритм для сортировки 5 различных ключей менее чем за 8 сравнений"> stackoverflow.com/questions/1534748/ - person Varun Garg; 15.10.2016