Ein System, das ich baue, enthält eine Reihe von UI-Schiebereglern (die Anzahl variiert) mit einer Skala von 0 bis 100. Mit Schieberegler meine ich eine Benutzeroberfläche, in der Sie ein Element greifen und es wie einen Lautstärkeregler nach oben und unten ziehen. Sie sind durch einen Algorithmus verbunden, der sicherstellt, dass sie immer 100 betragen. Wenn also ein Schieberegler nach oben bewegt wird, bewegen sich alle anderen nach unten und schließlich auf Null. Wenn einer nach unten bewegt wird, bewegen sich die anderen nach oben. Zu jeder Zeit muss die Summe 100 sein. Hier haben Schieberegler also verschiedene Werte, aber sie summieren sich zu 100%:
----O------ 40
O---------- 0
--O-------- 20
--O-------- 20
--O-------- 20
Wenn sich der erste Schieberegler dann von 40 auf 70 nach OBEN bewegt, müssen sich die anderen im Wert nach UNTEN bewegen (wenn der Schieberegler gezogen wird). Beachten Sie, dass drei Schieberegler von 20 auf 10 geändert wurden und einer bei Null blieb, da er nicht tiefer gehen kann.
-------O--- 70
O---------- 0
-O--------- 10
-O--------- 10
-O--------- 10
Wenn ein Schieberegler 0 oder 100 erreicht, kann er sich natürlich nicht weiter bewegen. Hier beginnt mein Kopf wirklich zu schmerzen. Wenn sich ein Schieberegler nach oben bewegt, bewegen sich die anderen nach unten, aber wenn einer von ihnen Null erreicht, können sich nur die verbleibenden, die noch nicht Null erreicht haben, nach unten bewegen.
Ich stelle dies hier, da diese Frage spezifisch für den Algorithmus und nicht für die Implementierung ist. FWIW die Plattform ist Android Java, aber das ist nicht besonders relevant.
Der Ansatz, den ich bei meinem ersten Stich gewählt habe, bestand darin, die prozentuale Änderung des sich bewegenden Schiebereglers zu berechnen. Ich habe diese Änderung dann aufgeteilt und (in die andere Richtung) auf die anderen Schiebereglerwerte angewendet. Das Problem ist jedoch, dass durch Verwendung von Prozentsätzen und Multiplikation, wenn ein Schieberegler auf Null kommt, dieser nie wieder von Null erhöht werden kann - das Nettoergebnis davon ist, dass einzelne Schieberegler bei Null stecken bleiben. Ich habe Schieberegler mit einem Bereich von 0 bis 1.000.000 verwendet, um Rundungsprobleme zu vermeiden, und das scheint hilfreich zu sein, aber ich habe noch keinen Algorithmus erstellt, der alle Szenarien gut handhabt.
quelle
Antworten:
Gieriger Algorithmus
Wenn sich ein Schieberegler nach oben (unten) bewegt, müssen sich alle anderen nach unten (oben) bewegen. Jeder hat etwas Platz, den er bewegen kann (für unten - ihre Position, für oben: 100-Position).
Wenn sich also ein Schieberegler bewegt, nehmen Sie die anderen Schieberegler, sortieren Sie sie nach dem Raum, den sie bewegen können, und durchlaufen Sie sie einfach.
Bewegen Sie den Schieberegler bei jeder Iteration in die gewünschte Richtung um (insgesamt nach links / Schieberegler nach links in der Warteschlange) oder um die Entfernung, um die er sich bewegen kann, je nachdem, welcher Wert kleiner ist.
Dies ist in seiner Komplexität linear (da Sie dieselbe geordnete Warteschlange nach dem Sortieren immer wieder verwenden können).
In diesem Szenario bleiben keine Schieberegler hängen, alle versuchen, sich so weit wie möglich zu bewegen, aber nur bis zu ihrem gerechten Anteil.
Gewichteter Zug
Ein anderer Ansatz wäre, die Bewegung zu gewichten, die sie tun müssen. Ich denke, das haben Sie versucht, gemessen an Ihrer Aussage "Schieberegler bleiben bei 0 hängen". IMHO ist dies natürlicher, Sie müssen nur mehr Optimierungen vornehmen.
Wenn Sie noch einmal spekulieren, würde ich sagen, dass Sie versuchen, die Bewegungen verschiedener Schieberegler nach ihrer Position zu gewichten (dies würde sich direkt auf Ihr Problem mit 0 auswirken). Beachten Sie jedoch, dass Sie die Position des Schiebereglers aus verschiedenen Richtungen anzeigen können - vom Anfang oder vom Ende. Wenn Sie beim Abnehmen von Anfang an nach Position und beim Erhöhen von Ende nach Gewicht wiegen, sollten Sie Ihr Problem vermeiden.
Dies ist in der Terminologie dem vorherigen Teil ziemlich ähnlich - gewichten Sie die Bewegung nicht nach der Position der Schieberegler, sondern nach dem Raum, den sie noch haben , um sich in diese Richtung zu bewegen.
quelle
Der Ansatz, den ich wählen würde, ist etwas anders und beinhaltet die Verwendung einer anderen internen Darstellung jedes Schiebereglers.
Jeder Schieberegler kann einen beliebigen Wert von 0..100 (X) annehmen, der als Gewichtungsfaktor für diesen Schieberegler verwendet wird (kein%).
Addiere alle Schiebereglerwerte, um die Gesamtzahl (T) zu erhalten.
Verwenden Sie RUND (X * 100 / T), um den angezeigten Wert jedes Schiebereglers zu bestimmen.
Wenn ein Schieberegler nach oben oder unten bewegt wird, ändern Sie nur den Wert des einen Schiebereglers . Die Gewichtung für diesen Schieberegler wird im Vergleich zu allen anderen Schiebereglern erhöht oder verringert, und die obige Berechnung stellt sicher, dass die Änderung auf alle anderen Schieberegler so gleichmäßig wie möglich verteilt wird.
quelle
Ich denke, Sie machen die Dinge zu kompliziert, indem Sie versuchen, den aktuellen Wert um einen Prozentsatz der Änderung des Schiebereglers "Verschoben" anzupassen, wodurch Sie Prozentsätze der Prozentsätze erhalten, was zu Rundungsfehlern führt.
Da Sie wissen, dass Sie immer nur mit einem Gesamtwert von 100 zu tun haben, würde ich die Dinge als Ganzzahlen beibehalten und von den 100 rückwärts arbeiten, um ernsthafte Probleme beim Runden zu vermeiden. (Im folgenden Beispiel behandle ich jede Rundung als ganze Ganzzahlen am Ende.)
Meine Technik wäre, die Schieberegler auf einfach 0-100 einzustellen. Subtrahieren Sie den 'neuen' Wert von 100, um herauszufinden, wie viel neu verteilt werden soll, verteilen Sie diesen Wert entsprechend ihrem Gewicht auf die anderen Schieberegler und räumen Sie ihn auf.
Dies ist meines Wissens kein gültiger Android-Code: p
Dies sollte grundsätzlich jeden 0- oder 100-Wert behandeln
quelle
Was ist mit Round Robin Ansatz? Erstellen Sie eine Transaktion, die sicherstellt, dass der Mehrwert eines Schiebereglers gegenüber dem Peer verringert wird. und umgekehrt.
Führen Sie dann jedes Mal, wenn ein Schieberegler wechselt, die Transaktion mit einem anderen Peer-Schieberegler aus (ich würde einen Iterator erstellen, der den Peer-Schieberegler abwechselnd zurückgibt). Wenn der Peer-Schieberegler Null ist, fahren Sie mit dem nächsten fort.
quelle
Nur um auf die großartige Antwort des Greedy-Algorithmus von @Ordous einzugehen. Hier ist eine Aufschlüsselung der Schritte.
quelle
Eine einfache Technik besteht darin, Prozentsätze der Schiebereglerwerte relativ zur Summe der Schiebereglerwerte zu berechnen und die Schiebereglerwerte dann den jeweils berechneten Prozentsätzen neu zuzuweisen. Auf diese Weise werden die Schiebereglerwerte neu eingestellt, z
Es führt zwar zu Rundungsfehlern, kann aber behandelt werden, wenn die Schiebereglerwerte genau und immer auf 100 summiert werden müssen.
Ich habe eine Geige eingerichtet, um dies mit anglejs zu demonstrieren. Bitte besuchen Sie die Demo
quelle