Amerikanische Flagge sortieren


Um das Funktionsprinzip dieser "Multiband" -Sortierung zu verstehen, ist es einfacher, mit einem Beispiel einer Flagge mit drei Streifen zu beginnen. Und um die Dreifarben-Flagge leichter handhaben zu können, ist es besser, zuerst zu sehen, wie sie mit dem Zweifarben-Beispiel funktioniert. Und mit zwei Farben umgehen ...
EDISON Software - Webentwicklung
Dieser Artikel wurde mit der UnterstĂŒtzung von EDISON verfasst.

Wir befassen uns mit der Portierung und Migration von Software sowie der Entwicklung mobiler Anwendungen fĂŒr Android und iOS .

Wir lieben die Theorie der Algorithmen! ;-)

Zweifarbige Flagge



Betrachten Sie zunÀchst den Fall, in dem die Zahlen im sortierten Array in nur zwei Bits verteilt sind. Der Einfachheit halber nehmen wir an, dass wir ein Array von Nullen (niedriger Ordnung) und Einsen (hoher Ordnung) haben.

Wir haben also nur zwei "BÀnder": In einem werden wir die niedrigstwertigen Bits (Nullen) und in dem anderen die höchsten Bits (Einheiten) verschieben. Jede zweifarbige Flagge dient zur Demonstration. Zum Beispiel die Flagge der Ukraine.



Was ist hier los? Da in der ersten Phase nicht bekannt ist, wie viele Nullen und wie viele Einheiten wir haben, ist unklar, in welcher GrĂ¶ĂŸe die einzelnen „BĂ€nder“ enden werden. Daher setzen wir zwei Zeiger auf die Tasten des Arrays. Bei niedriger Ordnung wird der Zeiger an den Anfang des Arrays gesetzt, bei hoher Ordnung an das Ende. Dann durchlaufen wir das Array einmal von links nach rechts und betrachten jedes Bitelement.

Wenn wĂ€hrend der Passage ein Element der höchsten Ordnung entspricht, teilt uns der zweite Zeiger mit, wohin dieses Element ĂŒbertragen werden soll (wir fĂŒhren einen Austausch durch). Der Zeiger zum EinfĂŒgen des nĂ€chsten Elements bewegt sich nach links, der "Streifen" fĂŒr die ĂŒbergeordnete Ziffer hat sich erweitert.

Wenn es gleich der niedrigstwertigen Ziffer ist, bewegen wir den Zeiger dafĂŒr um ein Element nach rechts. Da wir nur zwei Ziffern haben, muss das Element nicht ĂŒbertragen werden, es ist bereits an seiner Stelle. Der „Streifen“ fĂŒr die jĂŒngere Kategorie wurde natĂŒrlich breiter.

Infolgedessen kollidieren zwei aufeinander zu bewegende Zeiger an einem Punkt, und die Entladungen werden in ihren "BĂ€ndern" angeordnet. Gleichzeitig mĂŒssen Sie nicht das gesamte Array durchlaufen - wenn sich die Zeiger irgendwo in der Mitte treffen, erledigt der Algorithmus seine Aufgabe.

Das Problem der niederlÀndischen Nationalflagge :: Das Problem der niederlÀndischen Nationalflagge



Wir erschweren die Aufgabe ein wenig und berĂŒcksichtigen nicht zwei, sondern drei Ziffern. Lassen Sie uns die Elemente des Arrays zu den niedrigsten (Nullen), mittleren (Einheiten) und höheren (zwei) Ziffern gehören.

Zur Demonstration nehmen wir die dreifache rot-weiß-blaue Flagge von Frankreich, Luxemburg von Russland und Schleswig-Goldstein von den Niederlanden. Warum genau die Flagge der Niederlande? Denn Edsger Dijkstra hat in seinen Vorlesungen am Beispiel dieser Flagge den entsprechenden Algorithmus untersucht, der als "Aufgabe der niederlĂ€ndischen Nationalflagge" bezeichnet wurde.



Wie Sie sehen, gibt es nichts besonders Neues. Jede Kategorie hat einen eigenen Zeiger. Anfangs nehmen die Beschriftungen fĂŒr Junior und Middle die Startpositionen am Anfang des Arrays ein und bewegen sich nach rechts, wenn das entsprechende Element angetroffen wird. Der Zeiger fĂŒr die höhere Ordnung befindet sich zuerst am Ende des Arrays und bewegt sich nach links.

Das Durchlaufen des Arrays ist auch in der Tat unvollstĂ€ndig. Wenn die Bits mehr oder weniger gleichmĂ€ĂŸig verteilt sind, durchlĂ€uft der Algorithmus 2/3 des Arrays, bevor alle Elemente in seinen "BĂ€ndern" gestreut werden.

Amerikanische Flagge sortieren :: Amerikanische Flagge sortieren



Nun können wir in unseren ErlĂ€uterungen zur amerikanischen Multiband-Flagge ĂŒbergehen.

Wenn wir nicht zwei, nicht drei, sondern eine beliebige Anzahl von Ziffern haben, legen wir fest, wo jede Ziffer beginnen soll (ihr "Band") und zeichnen die Elemente in ihren "BĂ€ndern" neu.

In diesem Algorithmus werden Zahlen normalerweise nicht als Dezimalzahl, sondern in einer anderen Bittiefe betrachtet, wobei es sich meistens um eine Zweierpotenz handelt. HĂ€ufig wird die Zahl 256 als Grundlage fĂŒr die Bittiefe verwendet (etwas seltener als 128), sodass Sie die Sortierung effizient anpassen können, um Zeichenfolgen anzuordnen. Bei Zahlen fĂŒr die Bittiefe ist es zweckmĂ€ĂŸiger, kleine 2 n (2, 4, 16 usw.) zu verwenden, um den Vergleich durch Verschieben um Bits zu ermöglichen, anstatt beim Vergleich von Dezimalzahlen zu einer Potenz zu werden.

Die Animation zeigt ein Beispiel fĂŒr die Bittiefe mit Basis 16:



  1. Suchen Sie beim ersten Durchgang nach dem Maximum, um die maximale Anzahl von Bits unter den Elementen im Array zu bestimmen (um die vom Konto bestimmten Bits korrekt aus den Elementen zu extrahieren).
  2. Dann erfolgt eine rekursive Verarbeitung. Beim Aufruf werden die Grenzen des Subarrays und das aktuell verarbeitete Bit angezeigt. Beim ersten Aufruf ist das gesamte Array ein Subarray, das erste Bit links wird genommen.
  3. Unter den Elementen des Subarrays wird eine anfĂ€ngliche Berechnung durchgefĂŒhrt - wie oft kommt jede Ziffer in der aktuellen Kategorie vor. Mit dieser Anzahl können Sie die Lokalisierung fĂŒr diese Ziffern der Ziffern bestimmen (dh, die Grenzen und die Position des "Bandes", in das Sie die Elemente verschieben möchten, die die nĂ€chste Ziffer in einer bestimmten Ziffer haben, sind bekannt). TatsĂ€chlich sind Lokalisierungen Zeiger auf „BĂ€nder“, in denen die entsprechenden Elemente verschoben werden mĂŒssen.
  4. Entsprechend den Lokalisierungszeigern findet ein Umtausch vor Ort statt - die Ziffer in der Kategorie zeigt an, wohin Sie den Artikel senden möchten, an dessen Stelle kommt ein weiterer Artikel, mit dem der Umtausch stattgefunden hat. Diese Klausel wird ausgefĂŒhrt, bis beim nĂ€chsten Austausch ein Element, das von einer anderen Stelle ankommt, nicht an seiner Stelle ist (dann können Sie zum nĂ€chsten Element des Subarrays ĂŒbergehen und diese Klausel auf Ă€hnliche Weise fĂŒr dieses Element ausfĂŒhren).
  5. Nachdem durch den Austausch die Elemente in der nĂ€chsten Ziffer durch Zahlen in Blöcke umverteilt wurden, findet eine Rekursion statt - fĂŒr jeden Block wird derselbe Algorithmus als Subarray angewendet, der nĂ€chste als aktuelle Ziffer.

In dem Artikel ĂŒber das ZĂ€hlen von Sortierungen mit einer ungefĂ€hren Verteilung gibt es einen visuell sehr Ă€hnlichen Algorithmus - die AnnĂ€herungssortierung . Dort haben wir gezĂ€hlt, wie oft jede Zahl im Array vorgekommen ist - und die Elemente entsprechend den erhaltenen Lokalisierungen neu verteilt. Hier zĂ€hlen wir, wie oft jede Ziffer in der Kategorie fĂŒr Subarray-Elemente vorkommt - und verteilen die Elemente in dem Subarray entsprechend den erhaltenen Lokalisierungen. Wenn AnnĂ€herung eine Art ZĂ€hlsortierung ist, dann ist "amerikanisch" eine ZĂ€hlbit-Sortierung.

American Flag Sort - Python-Implementierung
#           def get_radix_val(x, digit, radix) -> int: return int(floor(x / radix**digit)) % radix #             def compute_offsets(a_list, start: int, end: int, digit, radix) -> list: #          counts = [0 for _ in range(radix)] for i in range(start, end): #        #         val = get_radix_val(a_list[i], digit, radix) counts[val] += 1 #       #          offsets = [0 for _ in range(radix)] sum = 0 #         for i in range(radix): offsets[i] = sum sum += counts[i] return offsets #      def swap(a_list, offsets, start: int, end: int, digit, radix) -> None: i = start #          next_free = copy(offsets) #        #   (       ) cur_block = 0 while cur_block < radix-1: # if i >= start + offsets[cur_block+1]: cur_block += 1 continue radix_val = get_radix_val(a_list[i], digit, radix) if radix_val == cur_block: i += 1 continue swap_to = next_free[radix_val] a_list[i], a_list[swap_to] = a_list[swap_to], a_list[i] next_free[radix_val] += 1 #   def american_flag_sort_helper(a_list, start: int, end: int, digit, radix) -> None: #          offsets = compute_offsets(a_list, start, end, digit, radix) #      swap(a_list, offsets, start, end, digit, radix) if digit == 0: #     ? return #   #       for i in range(len(offsets)-1): #      #         american_flag_sort_helper(a_list, offsets[i], offsets[i+1], digit-1, radix) #   def american_flag_sort(a_list, radix) -> None: #,         for x in a_list: assert(type(x) == int) #    max_val = max(a_list) #    (  ) max_digit = int(floor(log(max_val, radix))) #   -     american_flag_sort_helper(a_list, 0, len(a_list), max_digit, radix) 

Ska sort :: Ska sort


Der deutsche Programmierer Malte Skarupke gab bekannt, dass er einen neuen Sortieralgorithmus entwickelt hat, der eine radikal verbesserte „amerikanische Flagge“ darstellt und std :: sort durchschnittlich zweimal ĂŒbertrifft (std :: sort - ein Algorithmus, der auch als introspektives Sortieren bezeichnet wird) - Ein Hybrid aus schnellem Sortieren und Sortieren nach Haufen .

  1. Das Array wird rekursiv sortiert. Auf der ersten Rekursionsebene wird das gesamte Array als Subarray betrachtet.
  2. Wenn das Subarray weniger als 128 Elemente enthĂ€lt, wird std :: sort dafĂŒr aufgerufen.
  3. Wenn das Subarray 128 bis 1024 Elemente enthĂ€lt, wird die amerikanische Flaggensortierung dafĂŒr aufgerufen.
  4. Wenn ein Subarray mehr als 1024 Elemente enthĂ€lt, wird die Ska-Sortierung dafĂŒr aufgerufen.
  5. Um den schlimmsten Fall zu vermeiden, wechselt der Algorithmus auch dann zu std :: sort , wenn die rekursive Verschachtelung zu groß ist (mehr als 16 Ebenen), selbst wenn das Subarray mehr als 128 Elemente enthĂ€lt.

Anscheinend ist es ein sehr effektiver und gleichzeitig Ă€ußerst komplexer Algorithmus - die Implementierung des Autors dauert fast anderthalbtausend Zeilen. Vielleicht werden wir diese Sortierung eines Tages in Betracht ziehen, jetzt werden wir nicht mehr darauf eingehen. Interessenten können auf die unten stehenden Links klicken.

Referenzen


Problem der niederlÀndischen Nationalflagge , Art der amerikanischen Flagge

Ska Art: Ich habe einen schnelleren Sortieralgorithmus geschrieben ( Teil 1 , Teil 2 ) Github-Code

Serienartikel:


In der AlgoLab Excel-Anwendung wurde die Sortierung nach einem zweifarbigen Flag (sortiert Nullen und Einsen), einem dreifarbigen Flag (sortiert Nullen, Einsen und Zweien) und der amerikanischen Flagge angezeigt. Um die „amerikanische Flagge“ zu sortieren, können Sie (in einem Kommentar zu der Zelle mit dem Namen des Algorithmus) das zu verteilende Zahlensystem angeben - der Standardwert ist hexadezimal.

Source: https://habr.com/ru/post/de481304/


All Articles