Forum: Compiler & IDEs Struct Array sortieren


von Durokh (Gast)


Lesenswert?

Hi zusammen,
ich habe ein struct, das bspw. zwei Variablen beinhaltet, x und y.

Nun habe ich ein Array (ca. 100 Elemente lang), das nach und nach mit 
diesen Structs gefüllt wird. Dabei soll in aufsteigender Reihenfolge 
nach x direkt beim Befüllen das neue Struct sortiert/eingeordnet werden.

Nun würde ich es so angehen:
- Herausfinden, an welcher Stelle im Array x größer gleich dem neuen 
Struct-Element ist
- Alle Elemente bis hin zu dieser Stelle um einen Platz im Array 
weiterschieben
- Das neue Struct einfügen.

Gibt es dafür noch einen besseren Weg? Oder kann man sogar automatisch 
ein Struct Array nach einer bestimmten Variable sortieren lassen?
Wenn ja, wie viel Zeit/Rechenaufwand beansprucht diese Aufgabe?


Gruß,
Durokh

von Rolf M. (rmagnus)


Lesenswert?

Durokh schrieb:
> Oder kann man sogar automatisch ein Struct Array nach einer bestimmten
> Variable sortieren lassen?

Ja, mit qsort. Du mußt nur eine kleine Funktion schreiben, die zwei 
Elemente vergleicht und zurückmeldet, welches von beiden nach dem von 
dir gewünschten Kriterium als größer zu betrachten ist.
Ohne das jetzt genauer analysiert zu haben, würde ich erwarten, daß das 
auch schneller geht, als beim Einsortieren jedesmal alle folgenden 
Elemente umkopieren zu müssen.

von Rene H. (Gast)


Lesenswert?

Das kommt schwer auf die Sortierung und der Struktur an. Man kann sich 
da ziemlich unglücklich damit machen.

Du vermischst zwei Dinge. Handhabung der Strukturen in einem Array und 
dessen Sortierung.

Ersteres hängt stark von der Zielplattform ab und der verwendeten 
Sprache (c/c++).

Zweiteres, hängt davon ab wie dein Key aussieht mit dem du sortieren 
willst.

Also lässt sich das mit den Angaben pauschal kaum beantworten.

Grüsse,
René

von Karl H. (kbuchegg)


Lesenswert?

Auch nicht ganz uninteressant:
Was bedeutet 'nach und nach'?
Alle 2 Minuten mal ein Neuzugang oder alle 100 in einem Aufwasch aber 
eben eins nach dem anderen.
Je nachdem ist es schneller ob man sich nur um dieses 1 neue Element 
kümmert oder ob man (gegebenenfalls) erst mal alle einfügt und dann alle 
in einem Aufwasch sortiert.

von Peter II (Gast)


Lesenswert?

oder man verwendet kein Array sondern eine Doppelt-Verkette-Liste. Da 
kann man mal schnell etwas einfügen, ohne die andere Daten zu 
verschieben.

von Durokh (Gast)


Lesenswert?

Rene H. schrieb:
> Du vermischst zwei Dinge. Handhabung der Strukturen in einem Array und
> dessen Sortierung.
>
> Ersteres hängt stark von der Zielplattform ab und der verwendeten
> Sprache (c/c++).

Ich möchte auf einem Atmega644 dieses Array befüllen lassen.

Rene H. schrieb:
> Zweiteres, hängt davon ab wie dein Key aussieht mit dem du sortieren
> willst.

Meinst du mit "Key" die Zielvariable? Wenn ja: Dabei handelt es sich um 
16-Bit Integer.

Karl Heinz Buchegger schrieb:
> Auch nicht ganz uninteressant:
> Was bedeutet 'nach und nach'?
> Alle 2 Minuten mal ein Neuzugang oder alle 100 in einem Aufwasch aber
> eben eins nach dem anderen.
> Je nachdem ist es schneller ob man sich nur um dieses 1 neue Element
> kümmert oder ob man (gegebenenfalls) erst mal alle einfügt und dann alle
> in einem Aufwasch sortiert.

Aus einem Datenstrom über die Serielle Schnittstelle (Baudrate: 115200 
)werden die einzelnen Structs ausgelesen und in das Array geladen. Also 
alle 100 in einem Aufmarsch.
Aus deiner Frage lese ich heraus, dass das Sortieren im Nachhinein 
geeigneter ist, korrekt?

Rolf Magnus schrieb:
> Ja, mit qsort. Du mußt nur eine kleine Funktion schreiben, die zwei
> Elemente vergleicht und zurückmeldet, welches von beiden nach dem von
> dir gewünschten Kriterium als größer zu betrachten ist.
> Ohne das jetzt genauer analysiert zu haben, würde ich erwarten, daß das
> auch schneller geht, als beim Einsortieren jedesmal alle folgenden
> Elemente umkopieren zu müssen.

Ist qsort immer noch sinnvoll, wenn ich nachträglich alles sortieren 
lassen?
Und: Wie kann ich die Zeit, die für das Sortieren benötigt wird, 
berechnen? Das müsste ich nämlich wissen.

von Karl H. (kbuchegg)


Lesenswert?

Durokh schrieb:

> Aus einem Datenstrom über die Serielle Schnittstelle (Baudrate: 115200
> )werden die einzelnen Structs ausgelesen und in das Array geladen. Also
> alle 100 in einem Aufmarsch.
> Aus deiner Frage lese ich heraus, dass das Sortieren im Nachhinein
> geeigneter ist, korrekt?

korrekt.
Vergleichsfunktion schreiben - qsort anwerfen und die Sache ist geritzt.
Details findest du in deinem C-Buch

> Ist qsort immer noch sinnvoll, wenn ich nachträglich alles sortieren
> lassen?

Gerade WEIL du nachträglich sortierst, ist ein ordentliches 
Sortierverfahren das Mittel der Wahl.

> Und: Wie kann ich die Zeit, die für das Sortieren benötigt wird,
> berechnen? Das müsste ich nämlich wissen.

Dazu gibts theoretisce Untersuchungen, wie sich die Sortierzeit im 
Mittel verhält und mit der Anzahl der zu sortierenden Elemente 
entwickelt. Hängt ja auch nicht ganz unwesentlich von den Daten selber 
ab.
Also: im einfachsten Fall messen! Mit ein paar typischen Stichproben 
kriegst du aussagekräftige Zahlen.

Du kannst natürlich auch erst mal dich ein bischen einlesen. Das Thema 
Sortieren und was damit zusammenhängt 'Suchen' ist ja in der EDV nicht 
ganz unwichtig. Da wurden auch schon Bücher darüber geschrieben. Da 
empfehle ich mal den Band (ich glaube es war) 3 der Reihe "The Art of 
Computer Programming" von Donald Knuth mit dem Subtitel "Sorting and 
Searching". Hat ja nur so um die 300 Seiten. (wenn man mit 300 überhaupt 
auskommt)


Edit und PS: Das 'q' in 'qsort' steht für 'quick'.

von Rosa-Kleidchen (Gast)


Lesenswert?

Wenn nur beim Einfügen sortiert eingefügt werden soll, bietet sich - bei 
selber machen - eine verkettet Liste geradezu an. Ob sie doppelt 
verkettet sein muß, ist noch die Frage. Die Implementierung ist 
sicherlich recht überschaubar und sehr kompakt. Bei einigen 
Sotieralgorithmen spielen Rekursionen eine Rolle, die auf einem AVR 
nicht unbedingt zu empfehlen sind.
Rosa

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Rosa-Kleidchen schrieb:
> Wenn nur beim Einfügen sortiert eingefügt werden soll, bietet sich - bei
> selber machen - eine verkettet Liste geradezu an.

Alternative wäre ein simples zusätzliches Array A, welches mit den 
Indices des zu sortierenden Arrays S gefüllt ist. Dann lässt man per 
qsort einfach das Array A sortieren.

Der Vorteil: Die Originaldaten werden gar nicht sortiert (also 
umfangreich im Speicher hin- und hergeschoben), sondern nur die Indices 
darauf.

Nachteil: Der sortierte Zugriff erfolgt indirekt auf das Array S - unter 
Zuhilfenahme von A.

Wenn die Daten sowieso im RAM stehen, ist diese Art von "umständlicher" 
Sortierung ziemlich unsinnig. Sind sie aber größer (als das verfügbare 
RAM) und stehen sie zum Beispiel auf einem externen Datenträger oder in 
einem EEPROM, dann kann diese Art und Weise der Sortierung sehr 
effizient sein.

von Karl H. (kbuchegg)


Lesenswert?

Rosa-Kleidchen schrieb:

> sicherlich recht überschaubar und sehr kompakt. Bei einigen
> Sotieralgorithmen spielen Rekursionen eine Rolle, die auf einem AVR
> nicht unbedingt zu empfehlen sind.

Übertreib mal nicht.
Bei einer Datengröße von 100 hast du eine rekursive Schachtelungstiefe 
von ca. 7 bis 9, je nachdem an welcher Stelle der Quicksort seinen 
Sentinel einsetzt. Alles noch überschaubar.

Man kann natürlich auch einen Shell-Sort oder Heap-Sort selber 
schreiben, wenn man der vorhandenen Quicksort-Lösung nicht über den Weg 
traut.

Wenns auf Laufzeit ankommt und man damit leben kann, dass man eine 
Obergrenze für die Anzahl verarbeitbarer Daten festlegen muss, ist das 
alles um Größenordnungen besser als eine verkettete Liste mit direktem 
Einfügen. Zumal ja die Verkettung der Liste auch Speicher braucht, den 
man ja aber angeblich für die paar Rekursionsstufen nicht hat.

von Andreas B. (andreas_b77)


Lesenswert?

Rosa-Kleidchen schrieb:
> Wenn nur beim Einfügen sortiert eingefügt werden soll, bietet sich - bei
> selber machen - eine verkettet Liste geradezu an.

Suchen/Zugriff und sortiertes Einfügen sind da recht ineffizient. Das 
sollte man daher auch nur bei kleinen Datensätzen machen (wobei in einen 
AVR auch nichts wirklich Großes passt).

von Peter II (Gast)


Lesenswert?

Andreas B. schrieb:
> Suchen/Zugriff und sortiertes Einfügen sind da recht ineffizient.

ich den zugriff bei einer verkettet Liste eigentlich sehr ineffizient. 
Man geht einfach der reihe nach durch und wenn das das nächste elemen 
kleiner als das einzufügende ist, dann wird einfach die Kette an dieser 
stelle verlängert.

von Rolf M. (rmagnus)


Lesenswert?

Peter II schrieb:
> Andreas B. schrieb:
>> Suchen/Zugriff und sortiertes Einfügen sind da recht ineffizient.
>
> ich den zugriff bei einer verkettet Liste eigentlich sehr ineffizient.
> Man geht einfach der reihe nach durch

Ja, eine lineare Suche eben. Die ist nicht besonders effizient. Besser 
wäre ein binärer Baum.

> und wenn das das nächste elemen kleiner als das einzufügende ist, dann
> wird einfach die Kette an dieser stelle verlängert.

Das einzige, was da effizienter ist als beim Array ist das eigentiche 
Einfügen. Die Suche nach der Stelle zum Einfügen ist eher langsamer, da 
man jedesmal erst den Pointer auf's nächste Element aus dem Speicher 
lesen muss. Beim Array kann ich einen Pointer oder einen Index in einem 
Register halten und jedesmal einfach inkrementieren.

von Peter II (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Ja, eine lineare Suche eben. Die ist nicht besonders effizient. Besser
> wäre ein binärer Baum.

wobei dann das sortierte aulesen wieder schwerer ist.

von Ralf S. (durokh)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Also: im einfachsten Fall messen! Mit ein paar typischen Stichproben
> kriegst du aussagekräftige Zahlen.

Messen, indem ich am Atmega einfach einen Pin direkt vor und nach dem 
Sortieren einen Pin high/low setze? Oszi hätte ich dafür hier stehen.

Die Sache mit der verketteten Liste lasse ich mir nochmal durch den Kopf 
gehen.

Auf jeden Fall vielen Dank! Das gibt mir auf jeden Fall die Sicherheit, 
dass ich nun zwei Wege habe, die in Ordnung sind. Ich glaube, bei der 
Wahl ist es dann letztendlich "Geschmackssache" bzw. Erfahrung, womit 
man in der Vergangenheit am meisten gearbeitet hat. Bei mir ist beides 
nicht der Fall, daher schaue ich mir beides mal an.

Danke nochmal!
Gruß,
Durokh

PS: Ich schreib nachher aber nochmal einen Thread zu einem anderen 
Thema, das hiermit aber auch zu tun hat.

von Rosa-Kleidchen (Gast)


Lesenswert?

>Übertreib mal nicht.
>Bei einer Datengröße von 100 hast du eine rekursive Schachtelungstiefe
>von ca. 7 bis 9, je nachdem an welcher Stelle der Quicksort seinen
>Sentinel einsetzt. Alles noch überschaubar.
Meine Erfahrungen sagen mir, dass aus 100 schnell mal 1000 und mehr 
werden können. Die Begehrlichkeiten sind dann schnell da.
Rosa

von Rosa-Kleidchen (Gast)


Lesenswert?

>Ja, eine lineare Suche eben. Die ist nicht besonders effizient. Besser
>wäre ein binärer Baum.
Immer noch effizienter als Sortieren! Aber gute Idee! Einen binären Baum 
benutzen zum Suchen der Stelle, in der das Element eingefügt werden soll 
und eine verkettete Liste hält die sortierten Elemente.
Rosa

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:
> Rolf Magnus schrieb:
>> Ja, eine lineare Suche eben. Die ist nicht besonders effizient. Besser
>> wäre ein binärer Baum.
>
> wobei dann das sortierte aulesen wieder schwerer ist.

Geht so. Ist auch nur eine rekursive Funktion. Wobei, da gibt es auch 
eine clevere Strategie den Baum aufzufädeln, indem man die Verpointerung 
manipuliert und so die Rekursion vermeidet.
Wobei die Sache mit dem Binärbaum auch wieder ihre Tücken hat. Mit den 
richtigen Daten degeneriert das dann schon wieder schnell in die Nähe 
einer linearen Liste. D.h. Besser wäre ein balanzierter binärer Baum.
Aber jetzt steigt der Aufwand schon beträchtlich.
Was sich auch lohnen kann, wenn wesentlich mehr Abfragen als Einfügungen 
gemacht werden.

Aber ich denke wir sind uns soweit einig, dass auf einem kleinen AVR 
schon rein technisch die Datenmenge nicht zustande kommen wird, so dass 
sich da etwas großartig gefinkeltes lohnt. Bei beispielsweise 10 
angenommenen Datensätzen lohnt sich binäres Suchen nicht gegenüber 
simplen linearen Suchen. Mit dem von TO genannten Mengengeräst von 100 
Datensätzen ist man da zwar schon über der Grenze drüber, wo die 
programmtechnische gegen gefinkelte Strategien verlieren wird, aber auch 
nur eher sehr knapp. In einem Array halten, sortieren und dann binär 
suchen sollte bei diesem Mengen eigentlich ein guter Kompromiss aus 
Aufwand und Nutzen darstellen. Zumal ja beide 'komplizierte' Operationen 
von der Standard-Lib in Form von Funktionen abgedeckt sind, so dass sich 
auch der programmiertechnische Aufwand dafür in Grenzen hält.
NB ist ja von Suchen im Originalposting überhaupt nicht die Rede.

von Karl H. (kbuchegg)


Lesenswert?

Rosa-Kleidchen schrieb:
>>Übertreib mal nicht.
>>Bei einer Datengröße von 100 hast du eine rekursive Schachtelungstiefe
>>von ca. 7 bis 9, je nachdem an welcher Stelle der Quicksort seinen
>>Sentinel einsetzt. Alles noch überschaubar.
> Meine Erfahrungen sagen mir, dass aus 100 schnell mal 1000 und mehr
> werden können.

Der TO hat es zwar nicht explizit geschrieben, ich sags aber trotzdem: 
Auf einem  kleinen AVR mit vielleicht 2kB SRAM?

> Einen binären Baum benutzen zum Suchen der Stelle, in der das Element
> eingefügt werden soll und eine verkettete Liste hält die sortierten
> Elemente.

Dein Enthusiasmus in allen Ehren. Aber wieviel Speicher willst du 
eigentlich noch sinnlos verbrutzeln?

von Rolf M. (rmagnus)


Lesenswert?

Rosa-Kleidchen schrieb:
>>Ja, eine lineare Suche eben. Die ist nicht besonders effizient. Besser
>>wäre ein binärer Baum.
> Immer noch effizienter als Sortieren!

Naja, kommt drauf an. Wenn man nur eine Liste füllen und dann einmalig 
sortieren muss, ist das die einfachere Möglichkeit. Wenn die Daten aber 
tröpfchenweise reinkommen und zwischendurch auch immer sortiert sein 
müssen, siehts natürlich anders aus. Du musst auch bedenken, daß jedes 
Element aus gerade mal zwei 16-Bit-Integern besteht. Wenn man statt 
eines Arrays eine doppelt verkettete Liste draus macht, verdoppelt sich 
der Speicherverbrauch dadurch (16-Bit-Zeiger angenommen). Und die Zeiger 
umzubiegen ist auch nicht weniger Aufwand als beim Array zwei Elemente 
einfach durch umkopieren auszutauschen.

> Aber gute Idee! Einen binären Baum benutzen zum Suchen der Stelle, in der
> das Element eingefügt werden soll und eine verkettete Liste hält die
> sortierten Elemente.

Wozu soll da die verkettete Liste gut sein?

von W.S. (Gast)


Lesenswert?

Durokh schrieb:
> - Alle Elemente bis hin zu dieser Stelle um einen Platz im Array
> weiterschieben
> - Das neue Struct einfügen.
>
> Gibt es dafür noch einen besseren Weg?

Wohl nicht. Abgesehen davon, daß du nicht die Elemente bis zu dieser 
Stelle, sondern die bereits gespeicherten Elemente ab dieser Stelle 
verschieben mußt.

Ich sehe auch keinen Vorteil darin, alles erstmal wild zu speichern und 
dann einen Sortieralgo drauf loszulassen. Das ist nicht produktiver, 
denn man muß in jedem Falle alle Elemente anfassen, und das gleich 
zweimal: einmal alle beim einstapeln und dann nochmal alle beim 
Sortieren (vergleichen und ggf. vertauschen).

Das Suchen der richtigen Stelle ist in einem Array immer einfacher als 
in einer verlinkten Kette, weil man nicht alle Einträge durchkämmen muß. 
Stattdessen kann man darauf zurückgreifen, daß ja alles dort schon 
vorhandene bereits sortiert ist, man kann also dort binär suchen.

Naja, und das stupide Verschieben eines Blockes von Einträgen ist meist 
ne Angelegenheit, die wenige Befehle pro Zyklus braucht, weil man 
einfach byteweise oder wordweise oder dwordweise verschieben kann ohne 
Rücksicht auf die interne Struktur der Elemente.

Also stapele deine Werte lieber gleich sortiert ein, das dürfte das 
Beste sein - insbesondere dann, wenn dein X eine Gleitkommazahl ist. 
Dann sehen nämlich alle Sortieralgorithmen eher alt aus, weil sie immer 
auf der vollen Anzahl von Elementen herumsortieren müssen. Beim 
sortierten Einstapeln hingegen hat man durchweg deutlich weniger 
Vergleiche.

W.S.

von Karl H. (kbuchegg)


Lesenswert?

W.S. schrieb:

> Wohl nicht. Abgesehen davon, daß du nicht die Elemente bis zu dieser
> Stelle, sondern die bereits gespeicherten Elemente ab dieser Stelle
> verschieben mußt.
>
> Ich sehe auch keinen Vorteil darin, alles erstmal wild zu speichern und
> dann einen Sortieralgo drauf loszulassen. Das ist nicht produktiver,
> denn man muß in jedem Falle alle Elemente anfassen, und das gleich
> zweimal: einmal alle beim einstapeln und dann nochmal alle beim
> Sortieren (vergleichen und ggf. vertauschen).

Dann würde ich dir mal ein paar Versuche mit realen Programmen 
empfehlen, ehe du hier aus dem Bauch heraus argumentierst.
Denn die gemessene Realität spricht gegen deine Argumentation.
Was du vorschlägst ist unter dem Namen 'Insertion Sort' bekannt. Lies 
mal darüber nach.
https://de.wikipedia.org/wiki/Insertionsort

von (prx) A. K. (prx)


Lesenswert?

Eine doppelt verkettete Liste ist beim sortierten Einfügen nicht besser 
als eine einfach verkettete Liste. Eine doppelt verkettete Liste ist nur 
dann besser, wenn man von einem Element ausgehend in beide Richtungen 
gehen will.

Man kann bei der Verkettung auch den Index an Stelle des Pointers 
verwenden, wozu in diesem Fall ein Byte bereits ausreicht.

Ob aber hier Verkettung besser oder schlechter als ein normales Array 
ist hängt von den übrigen Umständen ab. Ist die Zeit knapp? Ist der 
Speicher knapp? Wird später indiziert darauf zugegriffen, oder nur 
sequentiell?

von (prx) A. K. (prx)


Lesenswert?

A. K. schrieb:
> Eine doppelt verkettete Liste ist nur
> dann besser, wenn man von einem Element ausgehend in beide Richtungen
> gehen will.

PS: Das bezieht sich auf den hier betrachteten Kontext, nicht auf Listen 
allgemein.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.