Quick Sort Verfahren

Zuviel Werbung?
-> Hier kostenlos registrieren
Was ich dir schon mal sagen kann, ist dass du die Vergleich noch nicht richtig handhabst (Zeilen 22/26). Der Befehl sagt, dass das Programm zwei Lüftermotoren miteinander vergleichen soll, aber spezifiziert nicht, auf welche Eigenschaft. Zu dem Thema hatte ich weiter oben schonmal was geschrieben.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Zumindest TIA V18 meckert es dir an, wenn du in einem nicht-optimierten FB ein Array[*] als InOut deklarierst. HIer sind keine Arrays mit variablen Grenzen zulässig.
Allerdings hat er ja nur den LREAL gegen einen UDT ausgetauscht. Nicht optimiert hätte LREal auch nicht funktioniert. Ich gehe eher davon aus, das TIA wegen einem anderen Codefehler nicht übersetzt und so einfach irrelevante Fehler raushaut.
 
@DeltaMikeAir : Ja ist angehakt.

@vollmi : Verstehe zwar nicht warum, aber das hat jetzt so funktioniert. Musste danach noch zwei Zeilen anpassen.
Quicksort3.png
Allerdings hat der jetzt die Betriebszeiten sortiert, aber die Luefternummer rotiert ständig weiter und zählt durch.
Quicksort4.png

So langsam verstehe ich da echt nur noch Bahnhof.

Das zum Thema: Machste mal eben ne Sortierung. Kann ja nicht so schwer sein 🐒
 
Wenn du zyklisch sortierst, dann sortiert er natürlich die betriebszeiten auch zyklisch mit.

Das Programm macht halt das was du ihm sagst was es tun soll, nicht zwingend das was du willst das es tun soll.
Bei Sortierungen nach Betriebsstunden für Motorstarts. Macht es üblicherweise Sinn diese nur neu zu sortieren wenn wenn Motoren abschalten um beim nächsten Start den mit der niedrigen Betriebszeit anzuschalten. Dazu nimmt man bei der Sortierung die Motoren aus, die gerade laufen.
Gibt viele Herangehensweisen. Wenn man nur zwei oder drei Motoren hat macht man das ja meist von Hand. Aber wenn man deren 20 hat, machen solche Sortieralgorithmen halt schon sinn.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich habe 7 Motoren/Lüfter. Diese sollen anhand der Betriebszeit/Betriebsstunden sortiert werden (können auch abgewählt werden zB defekt). Gegen Abend schalten die Motoren ab (Schichtende). Bei Wiedereinschalten einer Maschine (Unterdruck wird benötigt) soll Lüfterzahl x anlaufen und dabei dann halt die mit den wenigsten Betriebsstunden zuerst. Muss ja dann auch iwie mit einer Einschaltkette realisiert werden.

Das übersteigt einfach meine aktuellen Programmierkenntnisse.

Ich danke euch trotzdem für eure Unterstützung! :)
 
Ich habe 7 Motoren/Lüfter. Diese sollen anhand der Betriebszeit/Betriebsstunden sortiert werden (...)
Das übersteigt einfach meine aktuellen Programmierkenntnisse.
Dafür brauchst du kein Quicksort. Da reicht auch Bubblesort oder irgend ein ähnliches Vergleichsverfahren ("jeder Wert gegen jeden"), was du mit deinen Kenntnissen hinbekommst.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich habe 7 Motoren/Lüfter. Diese sollen anhand der Betriebszeit/Betriebsstunden sortiert werden (können auch abgewählt werden zB defekt). Gegen Abend schalten die Motoren ab (Schichtende). Bei Wiedereinschalten einer Maschine (Unterdruck wird benötigt) soll Lüfterzahl x anlaufen und dabei dann halt die mit den wenigsten Betriebsstunden zuerst. Muss ja dann auch iwie mit einer Einschaltkette realisiert werden.

Das übersteigt einfach meine aktuellen Programmierkenntnisse.
Mach dir da keine Gedanken. Sondern schreibe erstmal für dich nieder was die Kriterien sein sollen und wann es sinn macht umzusortieren.

Wie gesagt ich sortiere neu wenn ich Maschinen abschalte. Im UDT kann man dann noch einen Betriebszustand ablegen.
Beim Sortieren sortierst du dann die Maschinen mit der kleineren Betriebsstunde nach vorne oder mit Betriebszustand "läuft".
So mal als Ansatz wo du den Hebel ansetzen kannst.
Die Sortierart ist hier eigentlich völlig nebensächlich. Quicksort funktioniert hier genauso wie Bubble oder Selection etc. Möglicherweise wäre das aber in einem neuen Tread besser abgelegt.
 
Vereinfacht suchen ohne umsortieren: du machst 6 Vergleichsrunden. Zuerst suchst du den kleinsten Wert und merkst dir in einer Liste, bei welchem Motor (Array-Index) der Wert ist. Diesen Motor schließt du bei den nächsten Runden aus. In den nächsten Runden suchst du aus den verbliebenen Motoren wiederum den kleinsten Wert und merkst den Index in der Rangliste und schließt den Motor aus. Nach 6 Runden ist nur noch ein noch nicht ausgeschlossener Motor übrig, das ist der mit dem höchsten Wert, der kommt in die Rangliste auf den letzten Platz. Dann stehen die Motornummern/Indizes nach Betriebsstunden sortiert in der Rangliste.
Für das Programmieren ist ungemein nützlich, wenn die Werte in einem Array vorliegen, also notfalls am Anfang die 7 Betriebsstunden in das Arbeits-Array kopieren.
 
Vereinfacht suchen ohne umsortieren: du machst 6 Vergleichsrunden. Zuerst suchst du den kleinsten Wert und merkst dir in einer Liste, bei welchem Motor (Array-Index) der Wert ist. Diesen Motor schließt du bei den nächsten Runden aus. In den nächsten Runden suchst du aus den verbliebenen Motoren wiederum den kleinsten Wert und merkst den Index in der Rangliste und schließt den Motor aus. Nach 6 Runden ist nur noch ein noch nicht ausgeschlossener Motor übrig, das ist der mit dem höchsten Wert, der kommt in die Rangliste auf den letzten Platz. Dann stehen die Motornummern/Indizes nach Betriebsstunden sortiert in der Rangliste.
Für das Programmieren ist ungemein nützlich, wenn die Werte in einem Array vorliegen, also notfalls am Anfang die 7 Betriebsstunden in das Arbeits-Array kopieren.
Ich verstehe wie du das meinst, aber ich kann es leider nicht so umsetzen. Das klingt auch recht simple und ist es wahrscheinlich auch, wenn man weiß wie. Habe Heute das erste Mal mit Array, UDT & SCL zu tun. Ich wurschtel mich schon seit mehreren Tagen durch Threads. Beschreibungen und Videos. Schulung gibts leider keine. Also learning by doing.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Vereinfacht suchen ohne umsortieren: du machst 6 Vergleichsrunden. Zuerst suchst du den kleinsten Wert und merkst dir in einer Liste, bei welchem Motor (Array-Index) der Wert ist. Diesen Motor schließt du bei den nächsten Runden aus. In den nächsten Runden suchst du aus den verbliebenen Motoren wiederum den kleinsten Wert und merkst den Index in der Rangliste und schließt den Motor aus. Nach 6 Runden ist nur noch ein noch nicht ausgeschlossener Motor übrig, das ist der mit dem höchsten Wert, der kommt in die Rangliste auf den letzten Platz. Dann stehen die Motornummern/Indizes nach Betriebsstunden sortiert in der Rangliste.
Für das Programmieren ist ungemein nützlich, wenn die Werte in einem Array vorliegen, also notfalls am Anfang die 7 Betriebsstunden in das Arbeits-Array kopieren.
Ich nehme mal an du meinst das mit dem MIN Wert?

#Reihenfolge_Platz_1[0]:=MIN(IN1 := "Allgemein".Betriebszeit_Reihenfolge[0].Betriebszeit, IN2 := "Allgemein".Betriebszeit_Reihenfolge[1].Betriebszeit,
IN3 := "Allgemein".Betriebszeit_Reihenfolge[2].Betriebszeit, IN4 := "Allgemein".Betriebszeit_Reihenfolge[3].Betriebszeit,
IN5 := "Allgemein".Betriebszeit_Reihenfolge[4].Betriebszeit, IN6 := "Allgemein".Betriebszeit_Reihenfolge[5].Betriebszeit,
IN7 := "Allgemein".Betriebszeit_Reihenfolge[6].Betriebszeit);

Ich verstehe nicht wie ich das jetzt quasi dem Motor zuordnen kann und dann auch noch diesen beim nächsten Durchlauf ausschließen kann?
 
Ich nehme mal an du meinst das mit dem MIN Wert?

#Reihenfolge_Platz_1[0]:=MIN(IN1 := "Allgemein".Betriebszeit_Reihenfolge[0].Betriebszeit, IN2 := "Allgemein".Betriebszeit_Reihenfolge[1].Betriebszeit,
IN3 := "Allgemein".Betriebszeit_Reihenfolge[2].Betriebszeit, IN4 := "Allgemein".Betriebszeit_Reihenfolge[3].Betriebszeit,
IN5 := "Allgemein".Betriebszeit_Reihenfolge[4].Betriebszeit, IN6 := "Allgemein".Betriebszeit_Reihenfolge[5].Betriebszeit,
IN7 := "Allgemein".Betriebszeit_Reihenfolge[6].Betriebszeit);

Ich verstehe nicht wie ich das jetzt quasi dem Motor zuordnen kann und dann auch noch diesen beim nächsten Durchlauf ausschließen kann?

Code:
If wert[#i] < wert[#i+] then
   ...
End_if;

Hab gerade nur ein Handy zur Hand...
 
Ich nehme mal an du meinst das mit dem MIN Wert?

#Reihenfolge_Platz_1[0]:=MIN(IN1 := "Allgemein".Betriebszeit_Reihenfolge[0].Betriebszeit, IN2 := "Allgemein".Betriebszeit_Reihenfolge[1].Betriebszeit,
IN3 := "Allgemein".Betriebszeit_Reihenfolge[2].Betriebszeit, IN4 := "Allgemein".Betriebszeit_Reihenfolge[3].Betriebszeit,
IN5 := "Allgemein".Betriebszeit_Reihenfolge[4].Betriebszeit, IN6 := "Allgemein".Betriebszeit_Reihenfolge[5].Betriebszeit,
IN7 := "Allgemein".Betriebszeit_Reihenfolge[6].Betriebszeit);

Ich verstehe nicht wie ich das jetzt quasi dem Motor zuordnen kann und dann auch noch diesen beim nächsten Durchlauf ausschließen kann?
Ich kann nicht mit Sicherheit ausschliessen, dass Harald (auch?) an die MIN-Funktion gedacht hat, aber ich denke, er hat an eine (bzw. mehrere) ProgrammSchleife[n] und an einen (bzw. mehrere) selbst programmierte Vergleiche z.B. unter Verwendung des VergleichsOperators '<' gedacht.
Die von Dir erwähnte MIN-Funktion ist auf maximal 32 Operanden beschränkt und nicht so super geeignet, wenn man ein Array sortieren will.
Aber wie heisst es in der Werbung so schön? "Nichts ist unmöglich!" ;)
Harald hat einfach beschrieben, wie man eine Liste sortieren kann, indem man wiederholt die benachbarten Einträge vergleicht und ggfs tauscht.
Ferner, dass man das Verfahren "abkürzen" kann, indem man von Wiederholung zu Wiederholung einen Vergleich einsparen kann, weil es dafür keinen KlärungsBedarf mehr gibt: hat man den kleinsten Eintrag ermittellt, so braucht man nur noch die restlichen Einträge zu untersuchen. Hat man dann den zweit kleinsten ermittelt, dann muss man nur noch den jetzt wieder um 1 kleiner gewordenen Rest untersuchen u.s.w..
Harald hat Dir ferner erklärt, dass man zum sortieren der Liste die Reihenfolge der Einträge in der Liste gar nicht ändern muss, wenn man eine weitere Liste anlegt und "ersatzweise" diese zusätzliche Liste sortiert. Diese zusätzliche Liste kann eine Kopie der eigentlichen Liste sein, muss aber nicht! Es geht einfacher und zielführender verwendbar, wenn die zweite Liste nur zu jedem Eintrag in der ersten Liste die Information enthält, auf welchem Platz der Eintrag in der sortiert gedachten ersten Liste stehen würde. Das klingt vielleicht furchtbar umständlich und nach unnötigen Umwegen.
Besonders interessant wird dieses Verfahren, wenn man eine Tabelle wahlweise nach unterschiedlichen Kriterien/Spalten sortiert haben will.
Benötigt man diese unterschiedlichen Sortierungen nicht gleichzeitig, so kann man die eine "zusätzliche Liste" nacheinander in verschiedenen Bedeutungen benutzen, muss man aber auch nicht.
Man kann auch für jede SortierungsArt eine eigene weitere Liste verwenden. Das klingt schon wieder furchtbar umständlich und unübersichtlich
Man kann, wie man sich denken kann, die zusätzlich[n] Listen in zusätzlichen Arrays unterbringen, aber auch das muss man nicht.
Man kann nämlich alternativ die "eigentliche" Tabelle um weitere Spalten erweitern und diese Spalten eigens für den Zweck der Sortierung benutzen.

Bezogen auf die Überschrift mit dem Stichwort QuickSort sind meine Anmerkungen scheinbar reichlich off topic.
Sie lassen sich natürlich mit QuickSort umsetzen, gelten aber genauso für andere SortierVerfahren.
Was ich eigentlich sagen möchte, ist, bevor Du Dich auf das Thema QuickSort stürzt, kümmer Dich bitte erstmal um die o.g. Aspekte.

QuickSort ist in einer SPS umsetzbar, aber eher behelfsmässig, wegen des rekursiven Algorithmus.
Als Einstieg für einen Neuling ist es m.E. wenig geeignet.
QuickSort hat Vorteile beim Sortieren von Listen und Tabellen mit seeehr vielen Zeilen. Bei sooo langen Listen oder Tabellen sollte man sich aber sowieso überlegen, ob sie überhaupt in der SPS verarbeitet werden müssen.

Da fällt mir gerade noch ein Thema ein: die zusätzliche[n] Liste[n] ist/sind vom DatenTyp INT oder UINT oder DINT oder UDINT, je nach Anzahl Zeilen der Liste/Tabelle. Der DatenTyp REAL oder LREAL hat hier gar nichts zu suchen, da nur ganzzahlige Indizes auf ArrayElemente drin stehen.

PS:
Was machst Du, wenn in der Spalte, nach der sortiert werden soll, mehrere gleiche Einträge vorkommen?
Man kann sich sagen: ist egal, ob ich die Einträge tausche oder nicht. Muss bzw. sollte man aber nicht. "Unnötige" PlatzWechsel in einer Tabelle sollte man tunlichst vermeiden.
Denn: es kommt schon mal vor, dass man nacheinander nach verschiedenen Spalten sortieren will/muss und dann wundert man sich u.U. über unerwartete, unterschiedliche SortierErgebnisse.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich verstehe nicht wie ich das jetzt quasi dem Motor zuordnen kann
also notfalls am Anfang die 7 Betriebsstunden in das Arbeits-Array kopieren.
ein lokales Arbeits-Array: Betriebsstunden : Array [1..7] of DINT
Code:
#Betriebsstunden[1] := "Motor1".Betriebszeit;
...
#Betriebsstunden[7] := "Motor7".Betriebszeit;
Wenn die Motor-Objekte schon in Arrays liegen, kann man das umkopieren der 7 Werte auch in einer Schleife machen.
Index 1 entspricht Motor 1 ... Index 7 entspricht Motor 7

Dazu noch ein lokales Array Rangliste : Array [1..7] of INT
(das Array braucht nicht initialisiert werden, weil später im Code jedem Array-Member ein Wert zugewiesen wird)

und dann auch noch diesen beim nächsten Durchlauf ausschließen kann?
nach Finden durch Vergleiche und Eintragen des Index des kleinsten Wertes in die Rangliste den größtmöglichen DINT-Wert 2.147.483.647 (DW#16#7FFF_FFFF) in #Betriebsstunden[x] eintragen. Dadurch ist er extrem benachteiligt und wird er nie mehr kleinster. :cool:
Am einfachsten 7x nacheinander den kleinsten Wert aus #Betriebsstunden[1] bis #Betriebsstunden[7] suchen und den Index des jeweils kleinsten wertes in die Rangliste eintragen.

(Code ungetestet, enthält evtl. Syntaxfehler)
Code:
//*** Rangliste[1]
#Rangliste[1] := 1;
#kleinster := #Betriebsstunden[1];
FOR #i := 2 TO 7 DO
  IF #Betriebsstunden[#i] < #kleinster THEN
    #Rangliste[1] := #i;
    #kleinster := #Betriebsstunden[#i];
  END_IF;
END_FOR;
#Betriebsstunden[#Rangliste[1]] := 2_147_483_647; //den gefundenen kleinsten Wert "ausschliessen"

//*** Rangliste[2]
#Rangliste[2] := 1;
#kleinster := #Betriebsstunden[1];
...
Wenn du gut bist, kannst du den 7x Suchcode auch in eine "äußere" Schleife FOR #Platz := 1 TO 7 DO packen. (ist kein großer Akt, das siehst du schon, das schaffst du)
Der Algorithmus kann optimiert werden. Irgendwann landet man beim Bubble Sort.

Der Code wird zwar relativ uneffizient, dafür aber selbst erarbeitet und leicht verstehbar. Hauptsache du verstehst, was dabei "bildlich" abgeht.
 
Ich kann nicht mit Sicherheit ausschliessen, dass Harald (auch?) an die MIN-Funktion gedacht hat, aber ich denke, er hat an eine (bzw. mehrere) ProgrammSchleife[n] und an einen (bzw. mehrere) selbst programmierte Vergleiche z.B. unter Verwendung des VergleichsOperators '<' gedacht.
Richtig. Die MIN-Funktion liefert zwar den kleinsten Wert, aber der Wert interessiert gar nicht, sondern es interessiert die Motornummer (Array-Index), in dem der kleinste Wert steht! :cool: Dafür ist es hilfreich, wenn man das Array nicht umsortiert, weil das macht das Problem noch eine Stufe komplexer und unverständlicher.

Quicksort und Bubble Sort sind für die Sortierung groooßer Arrays gedacht. Die Rangfolge von nur 7 Werten kann man aber ruhig uneffizient ermitten, das bremst die SPS nicht.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Eine weitere Möglichkeit zu den genannten, die ich bei so Systemen gerne verwende ist im UDT des Gerätes noch eine Priorität einzufügen.
Das heisst man sortiert nicht mehr die Geräte sondern durchsucht das Array nach Kriterien und vergibt dann Prioritäten.

Die Sortierprogramme dienen oft eher dazu den Programmierern zu zeigen was man mit Arrays so alles machen kann und wie man effizient Schleifen programmiert und in Schleifen denkt.
 
Der Nachteil von Sortieralgorithmen ist, das die bei nur wenigen Elementen fast alle relativ uneffizient sind. Man sollte bedenken, dass es hier um nur 7 Elemente geht, die auch eigentlich gar nicht sortiert werden müssen, sondern es soll eine nach Betriebsstunden sortierte Liste der Motornummern erstellt werden. Man möge doch bitte von der Präsentationen von weiteren cleveren, aber ungeeigneten Sortieralgorithmen absehen, die verwirren den Fragesteller nur.
Meine in #35 gezeigte Codevariante erfüllt die Aufgabe mit gleichbleibend immer genau 42 Vergleichen. (Der Fragesteller muss den Code allerdings noch selber fertigstellen)
Im Vergleich dazu ein Bubblesort benötigt nur zwischen 6 und 21 Vergleiche, bewegt dafür aber eine Menge Daten (jeweils Tauschen von 2 Elementen über Hilfsvariablen). Weil am Ende nicht die sortierten Betriebsstunden interessieren, sondern die Motornummen (Indize), müssen Strukturen/UDT sortiert werden, die die Betriebsstunden und die Motornummer enhalten.

Da hatte ich vorher nach gesucht. Habe aber nur ältere Beiträge die nichts mit TIA zu tun haben gefunden und da gings dann auch wieder in Richtung Bahnhof.
Ein ausführlich Schritt für Schritt erklärtes Code-Beispiel für Bubblesort in TIA SCL kann man hier finden:
Bubblesort in TIA SCL (mit Verschiebung von 0-Werten ans Ende)
 
Zurück
Oben