thedeemon: (office)
Dmitry Popov ([personal profile] thedeemon) wrote2015-02-23 01:24 pm

back to basics

А вот кто не поленился дочитать книжки про построение алгоритмов, вас там научили их строить? Вот есть такая простейшая задачка: дан массив из 8 чисел, нужно найти "почти самое маленькое" и "почти самое большое", т.е.
sort(xs); return (xs[1], xs[6]);

Надо это сделать за минимальное число действий. Под действиями подразумеваются сравнения, ну и копирования с перестановками, хотя сравнения важнее. На особенности современного железа и его наборов инструкций пока положим, интересует классический теоретический подход. Как положено подходить к решению? Массив можно менять на месте, можно использовать дополнительную память. Я знаю, как это сделать за 14 сравнений. Можно ли за меньшее число? Можно ли доказать, что за меньшее нельзя?

[identity profile] diam-2003.livejournal.com 2015-02-23 06:30 am (UTC)(link)
Sorting network, поиск k-й порядковой статистики.

[identity profile] thedeemon.livejournal.com 2015-02-23 07:12 am (UTC)(link)
Sorting network делает 19 сравнений. Собсно, я от нее и плясал, дойдя до 14.

Поиск k-й порядковой статистики есть двусторонний сразу? А то если искать сначала в одну сторону, потом в другую, это слишком долго.

[identity profile] diam-2003.livejournal.com 2015-02-23 12:53 pm (UTC)(link)
Поиск порядковой статистики обычно делается на основе частичной сортировки.
Берём какую-нибудь достаточно хорошую сортирующую сеть и отрезаем лишнее.
Дальше получается задача комбинаторной оптимизации, чем-то похожая на построение оптимального умножителя на набор констант (c1, ..., cN) с использованием сложений-вычитаний и двоичного сдвига.

P.S. Не исключено, что можно проще. Это первое, что пришло в голову.
Edited 2015-02-23 12:57 (UTC)

[identity profile] macrop.livejournal.com 2015-02-23 06:36 am (UTC)(link)
найти - самое маленькое?
или отсортировать? разные вещи

[identity profile] theiced.livejournal.com 2015-02-23 06:40 am (UTC)(link)
sort(xs); return (xs[1], xs[6]);

чётко же всё сформулированно.

[identity profile] thedeemon.livejournal.com 2015-02-23 07:14 am (UTC)(link)
Целиком сортировать не нужно, только два числа найти.

[identity profile] chaource.livejournal.com 2015-02-23 06:51 am (UTC)(link)
Строить-то алгоримты нельзя научить, но данная задача поставлена иначе - не просто построить, а минимизировать количество сравненiй.

Я бы минимизировалъ съ помощью перебора между различными алгоритмами.
Edited 2015-02-23 06:52 (UTC)

[identity profile] worm-ii.livejournal.com 2015-02-23 07:38 pm (UTC)(link)
По грубым подсчётам, для перебора всех алгоритмов, использующих 13 сравнений, надо будет перебрать 26!/(15!) алгоритмов (учёл некоторые симметрии между алгоритмами, но не все), и каждый из них прогнать для 8! вариантов расположения чисел. Итого порядка 10^18 вариантов. Ну, если более вдумчиво использовать симметрии между алгоритмами, наверное, несколько порядков можно будет ещё скинуть. Вполне подъёмная задача для суперкомпьютера, или кластера из множества персоналок. Зато будет получено строгое доказательство, что за 13 сравнений решить задачу нельзя. Ну, или будет найдено решение из 13 сравнений.

[identity profile] sim0nsays.livejournal.com 2015-02-23 07:06 am (UTC)(link)
Т.е. интересует не асимптотическая сложность, а конкретная? Тут да, теория может только подсказать, что имплементировать, но не заменить ебическую силу имплементациии.

[identity profile] sleepy-drago.livejournal.com 2015-02-23 07:24 am (UTC)(link)
понятно что все кто читал старые книги начнут с https://en.wikipedia.org/wiki/Sorting_network и вспомнят чтото про Batcher =)
Почему, "интересует классический теоретический подход"?
задачка может и интересная но непонятно зачем.

[identity profile] thedeemon.livejournal.com 2015-02-23 07:50 am (UTC)(link)
Ну это я просто пробел в образовании ощущаю.
Скажем, можно же по теории информации тут вывести требуемое число бит и стало быть минимальное число сравнений. Для сортировок довольно несложно выводилось (логарифм числа перестановок или около того).

[identity profile] sleepy-drago.livejournal.com 2015-02-23 10:35 am (UTC)(link)
ну лобовое решение взять сеть Batcher'а и убрать из орграфа все что не соединено с выбранными вершинами. Для сетей Batcher'а вроде чтото доказательное было. Вопрос в том что доказательство по асимптотике на малых значениях имеет тот же смысл как и вся классическая модель =)

[identity profile] kgeorgiy.livejournal.com 2015-02-23 08:23 am (UTC)(link)
Как придумать решение «на пальцах».

Пусть мы как-нибудь нашли минимум. В процессе были просмотрены все элементы, по одному разу каждый. То есть мы имеем двоичное дерево поиска минимума. Где может быть второй минимум? Только в той ветке, из которой пришел минимум. Следовательно, ее требуется укоротить. Следовательно строим сбалансированное дерево поиска минимума.

таким образом, на поиск второго минимума будет потрачено (n-1) сравнение при нахождении минимума плюс (log(n)-1) сравнение для поиска второго минимума.

Теперь заметим, что на первом уровне дерева поиска максимума мы можем сравнивать те же пары элементов, что и в дереве поиска минимума. Таким образом, мы сэкономим n/2 сравнений.

Итого, общее время работы (n+log(n)-2)*2-n/2. Подставляя n=8 получим 14.

Про оценку надо думать. Сейчас я умею доказывать, что менее чем 11 сравнениями не обойтись.

[identity profile] gineer.livejournal.com 2015-02-23 09:38 am (UTC)(link)
\\Сейчас я умею доказывать, что менее чем 11 сравнениями не обойтись.

И есть реализация на 11 сравнений?
А то, это как бы известный эффект -- минимальная оценка есть, но как построить алгоритм её реализующий? ;)

[identity profile] kgeorgiy.livejournal.com 2015-02-23 11:25 am (UTC)(link)
Конечно, нет -- эта оценка почти наверняка занижена.

На самом деле, описанный алгоритм нахождения второго минимума является оптимальным, что доказано, например, здесь (http://web.engr.illinois.edu/~jeffe/teaching/497/02-selection.pdf).
Если мы построим два отдельных дерева для минимума и максимума, то легко построить пример, когда они делают только независимые (то есть с непредсказуемым результатам) сравнения на всех уровнях, начиная со второго. При этом, 14 -- точная оценка.
Однако, потенциально, мы можем сделать смесь двух этих деревьев, и как их оценить в этом случае -- совершенно не понятно.

[identity profile] kgeorgiy.livejournal.com 2015-02-23 12:26 pm (UTC)(link)
Придумал, как поднять нижнюю границу до 13.
Пусть нам заранее известно, где находятся минимальный и максимальный элемент (это log(n)+log(n-1) бит). Тогда нам осталось найти минимум и максимум среди оставшихся n-2 чисел.
Найти минимум и максимум среди k чисел можно за 3k/2-2 сравнения. При k=n-2 получим 3n/2-5 сравнений.
В сумме получим 3n/2-5+log(n)+log(n-1) сравнений.

Итого имеем зазор в 1 (часто) или 2 (для специально подобранных n) сравнения.

[identity profile] thedeemon.livejournal.com 2015-02-23 02:42 pm (UTC)(link)
>Где может быть второй минимум? Только в той ветке, из которой пришел минимум.

Почему?

[identity profile] kgeorgiy.livejournal.com 2015-02-23 08:37 pm (UTC)(link)
Посмотрим на элементы, с которым сравнивался найденный минимальный элемент. Каждый из них минимален в своем поддереве. Поэтому для любого другого элемента мы можем указать два небольших его элемента: минимум и вершина соответствующего поддерева. Следовательно искать второй минимум имеет смысл только среди тех элементов, с которыми мы сравнивали уже найденный минимум.

[identity profile] thedeemon.livejournal.com 2015-02-24 03:23 am (UTC)(link)
Точно, спасибо!

а вот ещё задача

[identity profile] urod.livejournal.com 2015-02-23 08:39 am (UTC)(link)
Даны М отсортированных массивов, их суммарная длина N. Найти медиану всех их элементов, вместе взятых.

[identity profile] sassa-nf.livejournal.com 2015-02-23 09:21 am (UTC)(link)
Если у вас цикл, то 14 сравнений никак не получится. А если не цикл, то много копипасты.

Это коммент о корректности вопроса. Можно было бы понять какую-то формулировку типа "нельзя быстрее, чем (n-1)*(n/4)", но тогда в последнее тоже много чего подходит; например, поиск максимума и минимума одновременно - (n-2); тогда поиск максимума и минимума в оставшемся - ещё (n-4); хотя самих сравнений может быть в 2 раза больше.
Edited 2015-02-23 09:52 (UTC)

[identity profile] thedeemon.livejournal.com 2015-02-23 02:40 pm (UTC)(link)
Не цикл, копипаста ок.

[identity profile] sassa-nf.livejournal.com 2015-02-23 11:12 pm (UTC)(link)
14 - это максимум? у меня среднее выходит 13. Хотя, нужно пересчитать; из-за ленивости может быть меньше.
Edited 2015-02-23 23:14 (UTC)

[identity profile] thedeemon.livejournal.com 2015-02-24 01:09 am (UTC)(link)
Нет, у меня 14 всегда. А как с 13?

[identity profile] sassa-nf.livejournal.com 2015-02-24 08:02 am (UTC)(link)
sort8 (s,t,u,v,w,x,y,z) = (if k < o then min l o else min k p, -- 2 comparisons
                           if n > r then max m r else max n q) where -- 2 comparisons
  ((a,b),(c,d)) = sort4 (s,t,u,v) -- 2 comparisons
  ((e,f),(g,h)) = sort4 (w,x,y,z) -- 2 comparisons
  ((k,l),(m,n)) = if a < c then -- 1 cmp
                    sort3 (a,b) (c,d) -- 1 or 2 cmps
                  else
                    sort3 (c,d) (a,b) -- 1 or 2 cmps
  ((o,p),(q,r)) = if e < g then -- 1 cmp
                    sort3 (e,f) (g,h) -- 1 or 2 cmps
                  else
                    sort3 (g,h) (e,f) -- 1 or 2 cmps

  sort3 (a,b) (c,d) = if b < c then ((a,b),(c,d))
                      else ((a,c), sort2 (b,d)) -- sorts the last 3 numbers
                      -- assuming a < b, a < c, c < d; 1 or 2 cmps
  sort2 (a,b) = if a < b then (a,b) else (b,a)
  sort4 (a,b,c,d) = (sort2 (a,b), sort2 (c,d))


видимо, есть ветвление, где может быть 2, а может быть 3 сравнения. Тогда есть 4 исхода: 4, 5, 5 и 6 сравнений в совокупности, а в среднем 5. Добавляем к остальным и получаем от 12 до 14, в среднем 13.
Edited 2015-02-24 09:59 (UTC)

[identity profile] thedeemon.livejournal.com 2015-02-24 04:37 pm (UTC)(link)
Спасибо, попробую в свой интерпретатор засунуть для проверки...

[identity profile] sassa-nf.livejournal.com 2015-02-24 04:50 pm (UTC)(link)
проверка такая: [k,l,m,n] == sort [s,t,u,v]

[identity profile] thedeemon.livejournal.com 2015-02-26 03:59 pm (UTC)(link)
Перевел, работает, действительно от 12 до 14 сравнений делает.
if stats: min=12 max=14 avg=13.3333
swap stats: min=0 max=12 avg=6
copy stats: min=0 max=2 avg=1.57143
all stats: min=12 max=28 avg=20.9048
score=842922 ok=true


До этого у меня было:
if stats: min=14 max=14 avg=14
swap stats: min=0 max=10 avg=5.33333
copy stats: min=0 max=2 avg=1.57143
all stats: min=14 max=26 avg=20.9048
score=842912 ok=true
Edited 2015-02-26 18:12 (UTC)

[identity profile] sassa-nf.livejournal.com 2015-02-26 09:52 pm (UTC)(link)
Интересно, что if stats avg больше 13. Я думал, что ветки по 1 и 2 сравнений будут равновероятны. Это, что ли, случай с a==b влияет так? Тогда нужно исправить условие, чтобы уходило по ветке с 1 сравнением, если равны.

sort3 (a,b) (c,d) = if b <= c then ((a,b),(c,d))
                      else ((a,c), sort2 (b,d))
Edited 2015-02-26 21:53 (UTC)

[identity profile] thedeemon.livejournal.com 2015-02-27 03:13 am (UTC)(link)
Это все зависит от того, как среднее считать, по каким данным. В моем случае прогонялось на всех перестановках [1..8], там a==b не бывает.

[identity profile] sassa-nf.livejournal.com 2015-02-27 07:52 am (UTC)(link)
странно. каким тогда образом получаются ветви не равновероятны?

[identity profile] dmitryall.livejournal.com 2015-02-23 10:17 am (UTC)(link)
А точно постановка задачи корректна? "Надо это сделать за минимальное число действий" - на каких входных данных? От этого очень много зависит. Варианты:

1. Если известно, что исходные массивы уже отсортированы, то можно найти за 0 действий.
2. Если известно, что уже отсортированы в прямом или обратном порядке, то за 1 действие (проверка, в прямом или обратном).
3. Если дано множество из всех возможных восьмерок 32-битный чисел (такое нехилое множество размером 2^32^8) и, запуская разные алгоритмы, надо выбрать из них такой, который в сумме по всем элементам этого множества даст минимальное число действий. (Это будет выбор алгоритма, оптимального "в среднем" по всем наборам входных данных.)
4. Если дано множество всех возможных алгоритмов и для каждого из них выбран наихудший массив, заставляем алгоритм работать - и выбираем из них тот, который будет давать наименьшее число сравнений для своего наихудшего варианта. Но такой способ на практике может быть малопригоден, т.к. вполне может существовать алгоритм, который дает в своем наихудшем случае миллион сравнений, но этот наихудший случай, положим, всего один, а для остальных случаев он в среднем оказывается неплох.
5. Если нет ограничения по памяти, то трактуем 8-элементный массив в качестве 64-битного целого числа (в случае, если у нас элементы массива - байты), предзаполняем в памяти огромный массив ответами по соответствующим огромным индексам и извлекаем ответ по индексу за 0 сравнений. Конечно, на практике это нереальный способ решения, но раз уж запрашивается теоретически оптимальный алгоритм и теоретическое доказательство того, можно меньше или нет, то вот оно, доказательство - можно за 0 действий решить в теории.
Edited 2015-02-23 10:22 (UTC)

12 сравнений

[identity profile] urod.livejournal.com 2015-02-23 10:29 am (UTC)(link)
Находим максимум и минимум - 7 сравнений.
Выбрасываем их и находим максимум и минимум оставшихся - 5 сравнений.

Re: 12 сравнений

[identity profile] sassa-nf.livejournal.com 2015-02-23 11:22 am (UTC)(link)
Вот и я о том же. Только нужно умножить на два.

Re: 12 сравнений

[identity profile] thedeemon.livejournal.com 2015-02-23 02:36 pm (UTC)(link)
А как выглядит операция "выбрасываем их" и сколько в ней сравнений?

Re: 12 сравнений

[identity profile] sassa-nf.livejournal.com 2015-02-23 02:47 pm (UTC)(link)
да хотя бы и своп с первым и последним элементом массива - ни единого сравнения. Тут интереснее как он собирается за 7 сравнений найти и минимум, и максимум.

[identity profile] juan-gandhi.livejournal.com 2015-02-23 04:06 pm (UTC)(link)
Я не читал ни одной такой книжки.
И не верю в них.

Насчет же доказательств - это Кнут, второй том.