Forum: PC-Programmierung c#: schneller vergleichalgorythmus gesucht


von Gero (Gast)


Lesenswert?

Hallo,
vlt. kann mir der eine oder andere von Euch auf die Sprünge helfen, ich 
finde hier keine optimale Lösung.

In meinem Programm möchte ich (viele) Werte in einem array nach einem 
vergleichen von einer Vorlage indizieren/markieren.

Das Array ist eine Struktur aus zwei Variablen. im ersten Wert ist der 
Vergleichswert, im zweiten Wert kommt ein Index von 1...16656 rein 
(abhängig vom Vergleichswert).
1
struct MeinWert []
2
{
3
     int Vergleichswert;
4
     int index;
5
}

Nun habe ich ein weiteres Array mit ähnlichem Aufbau das Wertebereiche 
für den Vergleichswert festlegt:
1
struct Gruppen []
2
{
3
     int MinWert;
4
     int MaxWert;
5
     int Index;
6
}

und da ahnt man dann auch schon was ich vor habe: fällt der obere 
Vergleichswert zwischen Min- und Maxwert des zweiten array, so übernehme 
ich den Index des unteren array in den Index des oberen array. Somit 
habe ich die Werte im oberen array klassifiziert.



Mein code sieht derzeit so aus
1
for (int i = 0; i < MeinWert.Length; i++)
2
{
3
   for (int n = 0; n < Gruppen.Length; n++)
4
   {
5
     if ((MeinWert[i].Vergleichswert >= Gruppen[n].MinWert) || (MeinWert[i].Vergleichswert <= Gruppen[n].MaxWert))
6
     {
7
        MeinWert.index = Gruppen.index;
8
        return;
9
     }
10
   }
11
}


so, das ganze funktioniert, aber wirklich erträglich ist das nicht. 
Solange man eine Hand voll Werte hat mag das OK sein, aber MeinWert[] 
und Gruppen[] sind bei mir beides sehr groß, das dauert mehrere Minuten 
bis das Programm den Vergleich durch hat :-(



Sieht jemand eine Lösung das ganze zu beschleunigen? die Werte müssen 
eben irgendwie auf Min-Max geprüft werden und es wäre schön wenn das 
etwas schneller gehen würde. Vlt. gibt es ja auch schon "etwas fertiges" 
in irgendeiner Klassenbibliothek!?

Ich bin um jeden Tipp dankbar, auch wenn ich mir einfach nur bestätigt 
dass es eben doch nicht schneller geht :-(

Danke und Gruß

von Peter II (Gast)


Lesenswert?

1. for ist langsamer als foreach
2. warum oder?
   if ((MeinWert[i].Vergleichswert >= Gruppen[n].MinWert) ||
   (MeinWert[i].Vergleichswert <= Gruppen[n].MaxWert))
3. sortierte die werte in Gruppen, damit du rechtzeitg abbrechen kannst
4. schreibe eine funktion um es besser lesbar zu machen

foreach( w in MeinWert ) {
   w.index = GetIndex( w.Vergleichswert  );
}

(foreach braucht eventuell ein class und kein struct)

von Quips (Gast)


Lesenswert?

Ohne jetzt zu lange nachzudenken:
Dein Aufwand liegt im Moment bei O(n^2)  (mit n = max(MeinWert.Length, 
Gruppen.Length).

Den könntest du recht einfach auf O(n log n) drücken, indem du die Werte 
zuerst sortierst, dann über die Gruppen iterierst und hier per binärer 
suche die passenden Werte suchst.

Ob's noch schneller geht? ka ;-)

von Informatiker (Gast)


Lesenswert?

Hast du mal probiert das mit LINQ zu realisieren?

Vom Gefühl her könnte bei einer großen Menge an Werten durch ein 
Vorsortieren von den Arrays dafür sorgen, dass die Laufzeit gedrückt 
wird

von Gero (Gast)


Lesenswert?

Hi,
vielen dank für Eure Hilfe!

Das mit dem "oder" ist ein Fehler meinerseits, es muss natürlich && 
heißen!

ich sortiere jetzt mal die Daten um und versuche mal das mit der binären 
Suche.

Min LINQ kenne ich mich überhaupt nicht aus, ich weiß zwar dass es das 
gibt, habe da aber nicht etwas damit gemacht, "man" müsste sich eben 
einarbeiten...


Danke!

von Karl H. (kbuchegg)


Lesenswert?

Gero schrieb:
> Hi,
> vielen dank für Eure Hilfe!
>
> Das mit dem "oder" ist ein Fehler meinerseits, es muss natürlich &&
> heißen!
>
> ich sortiere jetzt mal die Daten um und versuche mal das mit der binären
> Suche.

Wenn man es genau nimmt brauchst du gar nicht binär suchen.

Denn wenn du den korrekten Bereich für den Vergleichswert 5 hast, dann 
ist klar, dass der Bereich für den Vergleichswert 7 nur dahinter oder 
der gleiche sein kann. Auf jeden Fall aber kann der korrekte Bereich für 
7 in der Gruppenliste nicht vor dem Bereich für 5 sein.


D.h. durch die Sortierung, brauchst du hier
1
int n = 0;
2
3
for (int i = 0; i < MeinWert.Length; i++)
4
{
5
   for ( ; n < Gruppen.Length; n++)

n nicht jedesmal wieder bei 0 anfangen lassen, sondern kannst mit dem 
für das letzte i gefundene n weitermachen.
1
   {
2
     if ((MeinWert[i].Vergleichswert >= Gruppen[n].MinWert) || (MeinWert[i].Vergleichswert <= Gruppen[n].MaxWert))
3
     {
4
        MeinWert.index = Gruppen.index;
5
        return;

(wieso return? :-)
hier breakst du dich aus der inneren for Schleife raus. Und da deine 
Vergleichswerte sortiert sind wird die korrekte Gruppe für das nächste 
MeinWert[i].Vergleichswert in unmittelbarer Nähe hinter dem zuletzt 
gefundenen n sein.


damit hast du eine O(n+m) + 2*(die O deines Sortierverfahrens).

Sortieren ist eben oft eine extrem gute Idee :-)

Aufpassen: wenn sich deine Gruppen 'überlappen' können, in dem Sinne, 
dass es zu ein und demselben Minimum mehrere Maxima gibt, dann musst du 
in der Sortierbedingung das berücksichtigen, dass du ein primäres 
Sortierkriterium und ein Sekundäres hast.

von D. I. (Gast)


Lesenswert?

Quips schrieb:
> Ob's noch schneller geht? ka ;-)

Wenns der Speicher hergibt, hashen. Dann haste lineare Laufzeit

von Schorsch (Gast)


Lesenswert?

D. I. schrieb:
> Wenns der Speicher hergibt, hashen.

Er soll auf den Dachboden gehen und kiffen?

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.