Система, которую я создаю, включает в себя набор ползунков пользовательского интерфейса (число варьируется), каждый со шкалой от 0 до 100. Под слайдером я подразумеваю пользовательский интерфейс, в котором вы берете элемент и перетаскиваете его вверх и вниз, как регулятор громкости. Они связаны алгоритмом, который гарантирует, что они всегда составляют 100. Таким образом, когда один ползунок перемещается вверх, все остальные перемещаются вниз, в конечном итоге к нулю. Когда один движется вниз, другие движутся вверх. В любом случае общее количество должно быть 100. Таким образом, здесь ползунки имеют различные значения, но они составляют 100%:
----O------ 40
O---------- 0
--O-------- 20
--O-------- 20
--O-------- 20
Если первый ползунок затем перемещается вверх с 40 до 70, остальные должны сдвинуть значение ВНИЗ (так как ползунок перетаскивается). Обратите внимание, что три ползунка изменились с 20 на 10, и один остался на нуле, поскольку он не может опуститься ниже.
-------O--- 70
O---------- 0
-O--------- 10
-O--------- 10
-O--------- 10
Конечно, когда какой-либо ползунок достигает 0 или 100, он не может двигаться дальше, и моя голова действительно начинает болеть. Таким образом, если ползунок перемещается выше, другие перемещаются ниже, но когда любой из них достигает нуля, только остальные, которые еще не достигли нуля, могут двигаться ниже.
Я спрашиваю это здесь, так как этот вопрос относится к алгоритму, а не реализации. FWIW платформа Android Android, но это не особенно актуально.
Подход, который я применил к своему первому удару, состоял в том, чтобы рассчитать процентное изменение перемещения ползунка. Затем я разделил это изменение и применил его (в другом направлении) к другим значениям ползунка. Проблема, однако, в том, что при использовании процентов и умножения, если какой-либо ползунок достигает нуля, он никогда не может быть снова увеличен с нуля - чистый результат этого заключается в том, что отдельные ползунки застряли в нуле. Я использовал ползунки с диапазоном от 0 до 1 000 000, чтобы избежать проблем с округлением, и это, кажется, полезно, но мне еще предстоит создать алгоритм, который бы хорошо справлялся со всеми сценариями.
источник
Ответы:
Жадный алгоритм
Когда ползунок перемещается вверх (вниз), все остальные должны двигаться вниз (вверх). У каждого есть пространство, которое он может переместить (вниз - их позиция, вверх - 100 позиций).
Поэтому, когда один ползунок перемещается, возьмите другие ползунки, отсортируйте их по пространству, в котором они могут двигаться, и просто переберите их.
На каждой итерации перемещайте ползунок в нужном направлении (общая сумма для перемещения влево / ползунки в очереди) или на расстояние, которое он может переместить, в зависимости от того, что меньше.
Это линейный по сложности (так как вы можете использовать одну и ту же упорядоченную очередь снова и снова, как только она будет отсортирована).
В этом сценарии ползунки не застревают, все пытаются двигаться как можно больше, но только до своей справедливой доли.
Взвешенное движение
Другой подход - взвешивать движение, которое им нужно сделать. Я думаю, что это то, что вы пытались сделать, судя по вашим заявлениям «ползунки застряли в 0». ИМХО, это более естественно, вам просто нужно сделать больше настроек.
Снова рассуждая, я бы сказал, что вы пытаетесь взвесить ходы различных ползунков по их положению (это напрямую перешло бы к вашей задаче на 0). Однако обратите внимание, что вы можете просматривать положение ползунка с разных сторон - с начала или с конца. Если вы весите по положению от начала при уменьшении и от конца до конца при увеличении, вам следует избегать вашей проблемы.
По терминологии это очень похоже на предыдущую часть - не взвешивайте движение, которое необходимо выполнить, с помощью положения ползунков, взвешивайте его по месту, которое они оставили, чтобы двигаться в этом направлении.
источник
Подход, который я выбрал бы, немного отличается и включает в себя использование различного внутреннего представления каждого слайдера.
каждый слайдер может принимать любое значение от 0..100 (X), которое используется в качестве весового коэффициента для этого слайдера (не%)
сложите все значения ползунка, чтобы получить общую цифру (T)
чтобы определить отображаемое значение каждого ползунка, используйте ROUND (X * 100 / T)
когда ползунок перемещается вверх или вниз, вы изменяете только значение одного ползунка ; весовые коэффициенты для этого ползунка будут увеличиваться или уменьшаться относительно всех других ползунков, и приведенный выше расчет будет гарантировать, что изменение для всех других ползунков будет распределено как можно более равномерно.
источник
Я думаю, что вы слишком усложняете вещи, пытаясь отрегулировать текущее значение в процентах от изменения «перемещенного» ползунка, который дает вам проценты в процентах, что приводит к ошибкам округления.
Поскольку вы знаете, что когда-либо имеете дело только с общим значением 100, я бы оставил целые числа и работал бы в обратном порядке от 100, избегая каких-либо серьезных проблем с округлением. (В приведенном ниже примере я обрабатываю любое округление как целые числа в конце)
Моя техника - установить ползунки на 0-100. Вычтите «новое» значение из 100, чтобы выяснить, сколько нужно перераспределить, распределите это между другими ползунками в соответствии с их весом, а затем очистите)
Насколько я знаю, это не правильный код Android: p
Это должно по сути обрабатывать любое значение 0 или 100
источник
Как насчет подхода Round Robin? Создайте транзакцию, гарантирующую, что добавление значения к одному ползунку уменьшится по сравнению с его аналогом. и наоборот.
Затем каждый раз при смене ползунка запускайте транзакцию с другим ползунком равноправия (я бы создал итератор, который по очереди возвращает ползунок равноправия). Если равноправный ползунок равен нулю, переходите к следующему.
источник
Просто чтобы развить великолепный ответ Алгоритма Жадного от @Ordous. Вот разбивка шагов.
источник
Один простой метод заключается в том, чтобы рассчитать проценты значений ползунков относительно суммы значений ползунков, а затем переназначить значения ползунков соответствующим вычисленным процентам. таким образом, значения ползунка будут перенастроены, например
Хотя это приводит к ошибке округления, но это может быть обработано в случае, если нам нужно, чтобы значения ползунков точно и всегда суммировались до 100.
Я настроил скрипку, чтобы продемонстрировать это с помощью angularjs. Пожалуйста, посетите демо
источник