Seite 1 von 2

sortieren Arrays über Pointer

Verfasst: 19.07.2009 08:50
von PeterJ
Ich habe ein kleines Verständnisproblem mit Arrays und deren Verwendung mittels Pointern.
Als Ausgangslage habe ich mehrere (viele) Arrays, die wie folgt definiert sind:

Code: Alles auswählen

Global Dim ArrayString00.s(1)
Global  Dim ArrayString01.s(1)
...
diese Arrays werden dynamische verwaltet und ggf. mit REDIM erweitert/verkürzt. Im Programm spreche ich sie mit Pointern und einer Struktur an:

Code: Alles auswählen

Structure StringArray 
  text.s[0] 
EndStructure 
Verwendet werden sie z.B. wie folgt Einlesen Datei in Array:

Code: Alles auswählen

*toArray.StringArray=ArrayDef(toArray)\ArrayAddress 
While Eof(0)=0   ; Read until EOF
      i+1 
     *toArray\text[i]=ReadString(0)  
Wend
Das funktioniert alles ganz perfekt. Nun will ich noch eine SORT Funktion einbauen. und habe keine Idee wie ich den Sortaufruf machen soll:
Syntaktisch muß es ja so sein:

Code: Alles auswählen

SortArray(ArrayString00(), Optionen [, Start, Ende]) 
Wie mache ich das aber wenn ich nur die Adresse kenne und nur über Pointer und Struktur zugreifen kann?
sowas wie:

Code: Alles auswählen

SortArray( *toArray\text[], Optionen [, Start, Ende]) 
geht leider nicht. Wie mache ich es richtig?
... und weil wir dabei sind, kann mir jemand zeigen wo die Dokumentation über die Array Adressierung mit (in *pointer\variable) steht. Ich verwende sie, weil ich sie mir jemand in einem früheren Posting gezeigt hat. Der eigentliche Unterschied zur "(i)" Notation ist mir aber nicht klar.

Peter

Verfasst: 19.07.2009 10:17
von Kaeru Gaman
wenn du ReDim benutzt um sie zu verlängern/verkürzen, warum benutzt du dann nicht auch den klassischen Aufruf im Sort?

... mir ist sowieso nicht einleuchtend, warum du pointer für deinen zugriff benutzt...

wegen der unterschiedlichen namen?

warum benutzt du nicht ArrayString.s(0,1), ArrayString.s(1,1) statt ArrayString00.s(1), ArrayString01.s(1) ?

Verfasst: 19.07.2009 10:30
von cxAlex
Wenn du es unbedingt mit Pointern machen willst musst du dir selbst einen Sortieralgorythmus basteln. Ich hab hier mal nen angepassten Counting Sort für dich.

Ist besonders schnell wen der Bereich der zu sortierenden Zahlen klein ist:

Du musst ihn nur noch so anpassen das er nach Characters sortiert.

Code: Alles auswählen

Structure IntArray
  i.i[0]
EndStructure

Procedure CountingSort(*Array.IntArray, ArraySize)
  Protected *sortedArray.IntArray
  Protected i, j, fillheight, cnt, MaxSize, MinSize
  MaxSize = *Array\i[0]
  MinSize = MaxSize
  For i = 1 To ArraySize-1
    If *Array\i[i]>MaxSize
      MaxSize = *Array\i[i]
    EndIf
    If *Array\i[i]<MinSize
      MinSize = *Array\i[i]
    EndIf
  Next
  *sortedArray = AllocateMemory(((MaxSize-MinSize) + 1)*SizeOf(Integer))
  For i = 0 To ArraySize-1
    *sortedArray\i[*Array\i[i]-MinSize] + 1
  Next
  For i = MinSize To MaxSize
    cnt = *sortedArray\i[i-MinSize]-1
    For j = 0 To cnt
      *Array\i[fillheight] = i
      fillheight + 1
    Next
  Next
  FreeMemory(*sortedArray)
EndProcedure

#AnzEintrys = 20000000
#Min = 100
#Max = 355

Define *tArray.IntArray = AllocateMemory(#AnzEintrys*SizeOf(Integer))

For i = 0 To #AnzEintrys-1
  *tArray\i[i] = Random(#Max-#Min) + #Min
  ;Debug *tArray\i[i]
Next

t = ElapsedMilliseconds()
CountingSort(*tArray, #AnzEintrys)
t1 = ElapsedMilliseconds()-t
MessageRequester("", Str(t1) + " ms")

For i = 0 To #AnzEintrys-1
  Debug *tArray\i[i]
Next
Gruß, Alex

Verfasst: 19.07.2009 10:48
von PeterJ
Kaeru Gaman hat geschrieben:wenn du ReDim benutzt um sie zu verlängern/verkürzen, warum benutzt du dann nicht auch den klassischen Aufruf im Sort?
... mir ist sowieso nicht einleuchtend, warum du pointer für deinen zugriff benutzt...
wegen der unterschiedlichen namen?
warum benutzt du nicht ArrayString.s(0,1), ArrayString.s(1,1) statt ArrayString00.s(1), ArrayString01.s(1) ?
Ist etwas kompliziert, zu erklären: Ich steuere von Außen die Operationen die mit dem Array ausgeführt werden sollen. Als Beispiel ich habe Float Arrays, mit denen ich Matrix Operationen ausführe. Ich sage also:
1. ReadFloat(array-nummer-1,File1)
2. ReadFloat(array-nummer-2,File2)
3. Multiply(array-nummer-1,array-nummer-2)
(Die 2. Dimension der Matrix simuliere ich)

Das heißt die Verarbeitungsanweisung wird über eine Eingabedatei angestoßen. Das bedeutet konkret, ich kenne nur die relative array-nummer und ordne intern die Array Addresse zu.

Für String- und Numeric Arrays verfahre ich entsprechend.

Die 2. Dimension geht deshalb nicht weil die Arrays unterschiedlich lang sind und ich dann nicht die Möglichkeit habe mit REDIM individuell zu dimensionieren.

@cxAlex: Danke, das wird dann wohl der Weg sein, den ich beschreiten muß.

Verfasst: 19.07.2009 11:03
von cxAlex
Ich hab den Algo nochmal schnell verbessert, wie man den noch schneller machen könnte seh ich im Moment nicht:

Code: Alles auswählen

Structure IntArray
  i.i[0]
EndStructure

Procedure CountingSort(*Array.IntArray, ArraySize, MaxSize = -1)
  Protected *sortedArray.IntArray
  Protected i, j, fillheight, cnt
  ArraySize-1
  If MaxSize = -1
    MaxSize = *Array\i[0]
    For i = 1 To ArraySize
      If *Array\i[i]>MaxSize
        MaxSize = *Array\i[i]
      EndIf
    Next
  EndIf
  *sortedArray = AllocateMemory((MaxSize + 1)*SizeOf(Integer))
  For i = 0 To ArraySize
    *sortedArray\i[*Array\i[i]] + 1
  Next
  For i = 0 To MaxSize
    cnt = *sortedArray\i[i]
    For j = 1 To cnt
      *Array\i[fillheight] = i
      fillheight + 1
    Next
  Next
  FreeMemory(*sortedArray)
EndProcedure

#AnzEintrys = 20000000
#Min = 100
#Max = 355

Define *tArray.IntArray = AllocateMemory(#AnzEintrys*SizeOf(Integer))

For i = 0 To #AnzEintrys-1
  *tArray\i[i] = Random(#Max-#Min) + #Min
  ;Debug *tArray\i[i]
Next

t = ElapsedMilliseconds()
CountingSort(*tArray, #AnzEintrys, #Max)
t1 = ElapsedMilliseconds()-t
MessageRequester("", Str(t1) + " ms")

For i = 0 To #AnzEintrys-1
  Debug *tArray\i[i]
Next
Gruß, Alex

Verfasst: 27.07.2009 17:43
von PMV
PeterJ hat geschrieben: Die 2. Dimension geht deshalb nicht weil die Arrays unterschiedlich lang sind und ich dann nicht die Möglichkeit habe mit REDIM individuell zu dimensionieren.
Redim funktioniert doch mit Mehrdimensionalen Arrays, du kannst damit
halt nur die letzte Dimension ändern, aber genau das ist auch jetzt der
fall, wenn du das so umständlich machst. Die erste Dimension ist halt die
Anzahl deiner Variablen, die du von Hand geschrieben hast. Die kannst zur
laufzeit auch nicht löschen oder erstellen. :wink:

MFG PMV

Verfasst: 29.07.2009 13:42
von PeterJ
PMV hat geschrieben:[Redim funktioniert doch mit Mehrdimensionalen Arrays, du kannst damit halt nur die letzte Dimension ändern, aber genau das ist auch jetzt der fall, wenn du das so umständlich machst. Die erste Dimension ist halt die Anzahl deiner Variablen, die du von Hand geschrieben hast. Die kannst zur laufzeit auch nicht löschen oder erstellen. :wink:
MFG PMV
nicht ganz, bei 2-dimensionalen Arrays hätte ich z.B. die Situation:
array(1,n1) n1=1,2, ... 10
array(2,n2) n2=1,2, ... 100
array(3,n3) n3=1,2,...1000

Nachdem ein REDIM immer nur die letzte Dimension ändern kann, kann ich nur REDIM ARRAY(3,1000) als den insgesamt maximalen Wert angeben.
Ich könnte nicht sagen
REDIM ARRAY(1,10)
REDIM ARRAY(2,100)
REDIM ARRAY(3,1000)

Verfasst: 29.07.2009 13:43
von Kaeru Gaman
ReDim braucht du aber nur dann, wenn du den Inhalt buffern willst.
wenn der dir egal ist, kannst du einfach Dim benutzen, und du erhältst ein neues leeres Array mit dem selben Namen.

Verfasst: 30.07.2009 17:06
von PMV
PeterJ hat geschrieben:Nachdem ein REDIM immer nur die letzte Dimension ändern kann, kann ich nur REDIM ARRAY(3,1000) als den insgesamt maximalen Wert angeben.
Ich könnte nicht sagen
REDIM ARRAY(1,10)
REDIM ARRAY(2,100)
REDIM ARRAY(3,1000)
Stimmt, und du schreibst dein Programm für einen speziellen Rechner, der
nicht all so viel RAM hat? :mrgreen:

9.990 + 9.900 = 19.890 Byte zu viel ... naja gut, wenn du dafür lieber
Spagetticode produzierst, ist dir natürlich erlaubt. :lol: kleiner Spaß :D

MFG PMV

Verfasst: 30.07.2009 22:30
von PeterJ
PMV hat geschrieben:Stimmt, und du schreibst dein Programm für einen speziellen Rechner, der nicht all so viel RAM hat? :mrgreen:

9.990 + 9.900 = 19.890 Byte zu viel ... naja gut, wenn du dafür lieber
Spagetticode produzierst, ist dir natürlich erlaubt. :lol: kleiner Spaß :D

MFG PMV
Ausgangslage war sortieren von String Arrays, insoweit ist mein REDIM natürlich nicht korrekt und was Dimensionen anbelangt nur beispielhaft. Real würde er in etwa so aussehen:
REDIM ARRAY.S(100,n), wobei n=1,...1.500.000 (derzeit größter Fall den ich hatte). Stringlänge im Schnitt 60 Bytes.
Das macht also 100*1.500.000*61 macht 8.5 GB, das könnte ein normal XP nicht addressieren. Die Applikation selbst braucht meist nur 1 ganz großen Array, und mehrere kleinere Kontrollarrays.
Dabei entsteht nicht notwendigerweise Spagetticode, das alles läßt sich wunderbar modularisieren.