Helpdesk
Menschen Wissenschaft Politik Mystery Kriminalfälle Spiritualität Verschwörungen Technologie Ufologie Natur Umfragen Unterhaltung
weitere Rubriken
PhilosophieTräumeOrteEsoterikLiteraturAstronomieHelpdeskGruppenGamingFilmeMusikClashVerbesserungenAllmysteryEnglish
Diskussions-Übersichten
BesuchtTeilgenommenAlleNeueGeschlossenLesenswertSchlüsselwörter
Schiebe oft benutzte Tabs in die Navigationsleiste (zurücksetzen).

Mergesort Processing

92 Beiträge ▪ Schlüsselwörter: Processing, Mergesort ▪ Abonnieren: Feed E-Mail

Mergesort Processing

23.04.2010 um 11:12
@kisa

Ich sehe gerade, man kann sich Processing mal eben so runterladen. Ich konvertiere den Code mal ^^ das ist einfacher als jede Erklärung.


melden

Mergesort Processing

23.04.2010 um 12:37
@moredread
Danke, das tauschen mit dem Rechnen kannte ich nicht. Wieder etwas gelernt.

Mir ist schon klar, dass am Ende einer Zeichenkette noch ein x0 hängt und damit insgesamt 9 Byte belegt werden. Aber wolltest du wirklich die x0 mit sortieren?

Vielleicht stehe ich ja gerade mächtig auf der Leitung, aber ich meine, das Array sähe dann so aus:

a[0] = 'c'
a[1] = 'a'
a[2] = 'r'
a[3] = 'o'
a[4] = 'l'
a[5] = 'i'
a[6] = 'n'
a[7] = 'e'
a[8] = x0

Du hast den Iterator auf <8 abgefragt, d.h. der größte Wert von i ist 7. a[7] ist aber schon das 'e'. Vergleichst du jetzt also mit a[7+1]=a[8] greifst du auf die binäre 0 zu (die dann letztlich in a[0] landet...). Mache ich da einen Denkfehler? Oder hat C++ da irgendeine Besonderheit, die ich aus C nicht kenne?

Du hast in sofern Recht, als der Inhalt von der Stelle nach dem String zumindest dann immer definiert ist, wenn ich das als String definiert habe. Dann ist er immer x0. Nehme ich aber ein einfaches, selbstdefiniertes Array und schreibe meine Werte da rein, ist der Wert nach der Tabelle eben vom aktuellen Speicherzustand abhängig. Und damit mehr oder weniger zufällig.


melden

Mergesort Processing

23.04.2010 um 17:04
Zitat von LuftonLufton schrieb:Ich biete "caroline", 0, 7... (aber um 04:27 will ich das verzeihen )
:D Das war tatsächlich die frühe Uhrzeit. Im Code im vorherigen Beitrag ist der Aufruf richtig (sizeof name - 1)
Zitat von LuftonLufton schrieb:Das Problem mit dem doppelten Aufruf sehe ich übrigens nicht als so gravierend an. (Zumindest nicht in Zeiten einer (@kisa: weglesen )automatischen Garbage collection.)
Das Problem hier ist, dass der zweite Aufruf nicht erreicht wird solange r > l,
und dann ist der erste Aufruf bereits beim stack - unwinding.

Die Funktion tut also nicht das, was der Autor erwartet hat. Und mein Vstudio hat meine Meinung bestätigt :)


1x zitiertmelden

Mergesort Processing

24.04.2010 um 00:25
@OpenEyes
Zitat von OpenEyesOpenEyes schrieb:Das Problem hier ist, dass der zweite Aufruf nicht erreicht wird solange r > l,
und dann ist der erste Aufruf bereits beim stack - unwinding.

Die Funktion tut also nicht das, was der Autor erwartet hat.
Ich verstehe gerade nur Bahnhof - Koffer klauen...

Warum soll die Funktion nicht tun, was der Autor erwartet? Jetzt machst Du mich gerade neugierig...

Und r und l werden doch in jeder Instanz gar nicht geändert, dann würde der zweite Aufruf doch nie erfolgen... ??? Stehe ich gerade so auf dem Schlauch? (Kann es sein, dass bei VStudio die Parameter als static angelegt werden und somit jede neue Instanz die Werte überschreibt? Dann würde das in der Tat nicht funktionieren.)


melden

Mergesort Processing

24.04.2010 um 02:08
Anhang: mergesort.pdf (107, KB)@kisa
@OpenEyes
@moredread

Ich habe mal versucht den Sourcecode, so wie er ist zu erklären. Meine Bitte zunächst an OpenEyes und Moredread: schaut mal rein ob ich irgendwelchen eklatanten Blödsinn geschrieben habe.

@kisa, du liest dir den Text bitte mal durch ob du ihn verstehst. (Vorsicht, ist lang geworden...)


melden

Mergesort Processing

24.04.2010 um 11:58
@Lufton

r und l werden in der Rekursion geändert. Wenn r nichtmehr größer ist haben wir entweder ein Feld mit der Breite 0 oder der Breite 1.
Das wäre dann der Abbruch der Rekursion.

Oder mit anderen Worten, Felder mit der Breite 1 oder 0 werden nichtmehr weitersortiert weil sie ja in sich schon sortiert sind.


melden

Mergesort Processing

24.04.2010 um 17:00
@interpreter
Felder mit der Breite 0? Sprich gar kein Element? Wie soll das funktionieren? Sehe ich gar nicht.

Und ja, jeder Aufruf von mergesort bekommt andere Werte für l und r übermittelt, das ist mir schon klar. Aber in welcher Programmiersprache sind denn die Parameter nicht lokal? Wenn l und r überschrieben würden, würde das ganze Programm nicht funktionieren. Weil der erste Aufruf dann mit l=0 und r=7 aufgerufen würde und das ja runtergeht bis zur letzten Instanz, die dann mit l=0 und r=0 aufgerufen wird. Damit würde keine darüberliegende Instanz noch richtig arbeiten, wenn auch bei ihr r plötzlich den Wert 0 hätte.


melden

Mergesort Processing

24.04.2010 um 19:12
@Lufton

sie werden doch nicht überschrieben. l= 0 und r = 7 werden übergeben. Rekursion mit l=0 und r=3 außerdem Rekursion mit l=4 und r = 7 etc.

Allerdings behandelt alles das selbe Array denn wärend der Zeiger zwar lokal übergeben wird kann man von überall auf das Datenelement zugreifen auf das er zeigt.

l und r werden nur in den Unteraufrufen geändert. Die aufrufende Funktion behält ihre Werte selbsverständlich bei.

1 Instanz aufgerufen mit 0 und 7
2 Instanz mit 0 und 3
3 Instanz mit 4 und 7

in den jeweiligen Instanzen wird l und r nicht geändert.


1x zitiertmelden

Mergesort Processing

24.04.2010 um 19:17
@Lufton

Bisschen Geduld bis morgen - ich hab eine alternative rekursive Funktion geschrieben die auch funktioniert, und habe beide Funktionen in ein kleines Programm eingebaut. Muss nur noch ausführliche Kommentare schreiben.

Zu Deiner Verwunderung:

Das Problem mit dem Geposteten Code liegt hier:

void mergesort(int a[], int l, int r){ // l=linker Rand, r=rechter Rand
if(r>l){
int i, j, k, m; // Variablen deklarieren
m=(r+l)/2; // Mitte ermitteln

************
mergesort(a, l, m); // linke Teildatei
Hier ist Schluss, so lange die Abbruchbedingung nicht erreicht wird.

mergesort(a, m+1, r); // rechte Teildatei
************

Der zweite Aufruf wird erst erreicht, wenn die Abbruchbedingung (r == l) erreicht wird, und ab da beginnt bereits der Merge - Vorgang, bei dem aber nur eine korrekt (?, habe ich nicht überprüft) gesplittete linke Array - Hälfte zur Verfügung steht.

Der Sort funktioniert nicht, kann aufgrund des oben gesagten nicht funktionieren.

Dazu kommt noch, dass das ganze Ding unnötig kompliziert ist und eigentlich kein Merge - Sort sondern ein falsch programmierter Drei - Bänder - Sort ist. Da nach dem Splitten beim Merge - Sort jeder der "endgültigen Helfer" ohnehin nur ein Element in der Hand hält, ist das Splitting, also der ganze erste Teil der Funktion völlig überflüssig.

Falls Dir ein Drei - Bänder - Sort nichts sagt, das hat man zuerst in der Zeit der Dampfcomputer (keine Festplatten sondern nur Bandstationen) erfunden.

Dabei wird auch die Originaldatei "gesplittet, und zwar so, dass vom Originalband so lange auf band A geschrieben wird, wie die Daten in der richtigen Reihenfolge sind, dann wird auf Band B gewechselt und dort weitergeschrieben solange die Daten dort in der richtigen Reihenfolge sind, dann wieder auf A und so fort.

Im nächsten Schritt werden die Inhalte der Bänder wie beim Merge - Sort wieder auf dem Originalband gemischt, dann wieder gesplittet (da sind dann die Pakete mit richtiger Reihenfolge schon länger. Und so fort...

for(i=m+1; i>l; i--) b[i-1]=a[i-1]; // linke Teildatei in Hilfsarray
for(j=m; j<r; j++) b[r+m-j]=a[j+1]; // rechte Teildatei umgedreht in

Die rechte Teildatei gibt es zu dem Zeitpunkt noch gar nicht, oder nicht richtig.

// Hilfsarray
for(k=l; k<=r; k++)
a[k]=(b<b[j])?b[i++]:b[j--]; // füge sortiert in a ein
} // Ende der if-Abfrage
}



melden

Mergesort Processing

24.04.2010 um 19:28
@OpenEyes

Aber die linke Teildatei führt doch ihrerseits mergesort für ihren Teil aus.
Die Rekursion geht solange weiter bis zwei Unterelemente entstehen die man sortieren kann.


melden

Mergesort Processing

24.04.2010 um 20:03
@interpreter

Schau Dir den Code nochmal genau an. (Ich kan hier großlippig sicher reden, weil ich das Ding sicherheitshalber kompiliert und getestet habe :) )
Zitat von kisakisa schrieb am 19.04.2010:void mergesort(int a[], int l, int r){ // l=linker Rand, r=rechter Rand
if(r>l){
int i, j, k, m; // Variablen deklarieren
m=(r+l)/2; // Mitte ermitteln
mergesort(a, l, m); // linke Teildatei
^
|
Hier wird dir Funktion erneut aufgerufen, mit l und m, wobei m die Hälfte des vorherigen Wertes von r ist
Alles was ab hier folgt wird zunächst _nicht_ ausgeführt. Die Funktion ruft sich an diesem Punkt immer wieder selbst auf. Erst, wenn r == l erreicht wird kommt der erste Aufruf überhaupt zurück und der zweite Aufruf wird ausgeführt. _Aber_ welche Parameter bekommt dieser jetzt? r ==0 und l == 0. Also macht der zweite Aufruf gar nichts sondern bricht seinerseits ebenfalls ab. Was danach passiert ist nur noch ein Rückzugsgefecht :)

Text
mergesort(a, m+1, r); // rechte Teildatei
for(i=m+1; i>l; i--) b[i-1]=a[i-1]; // linke Teildatei in Hilfsarray
for(j=m; j<r; j++) b[r+m-j]=a[j+1]; // rechte Teildatei umgedreht in
// Hilfsarray
for(k=l; k<=r; k++)
a[k]=(b<b[j])?b[i++]:b[j--]; // füge sortiert in a ein
} // Ende der if-Abfrage
}
Eine Funktion aus sich selbst heraus mehrmals rekursiv aufzurufen ist (fast) unmöglich und erfordert in den wenigen Sonderfällen so viel Nachdenken, dass fast immer eine andere Lösung ökonomischer, weniger Fehleranfällig und weit billiger ist.


melden

Mergesort Processing

24.04.2010 um 20:13
@OpenEyes

Aber die Aufrufende Funktion behält doch die Ursprungswerte es ist eine andere Instanz.

Wenn die komplette Rekursionstiefe durchschritten ist hat die ursprüngliche Funktion immernoch die Werte 0 und 7.

folglich wird auch die rechte seite des Arrays mit 4 und 7 aufgerufen.
Es sei denn natürlich du deklarierst l und r als statisch.


melden

Mergesort Processing

24.04.2010 um 20:19
Hier ein kleines Beispiel einer Funktion in C# mit mehrfacher Rekursion zum multiplizieren extrem hoher Zahlen im Karatsuba Algorithmus

public static int[] IntKar(int[]arr1,int[]arr2)
{
int[] res=new int[1];
int[] znull= new int[1];
int länge;
if(ArrOps.Gleich(arr1,znull)||ArrOps.Gleich(arr2,znull))
{
return znull;
}
if((long)arr1.Length*(long)arr2.Length<120)
{
res=ArrOps.Mult(arr1,arr2);
return res;
}
if(arr1.Length<arr2.Length)
{
länge=arr2.Length/2;
}else
{
länge=arr1.Length/2;
}

int[] xH=ArrOps.IntSR(arr1,länge);
int[] xL=ArrOps.IntStEx(arr1,länge);
int[] yH=ArrOps.IntSR(arr2,länge);
int[] yL=ArrOps.IntStEx(arr2,länge);


int[] p1=ArrOps.IntKar(xH,yH);
int[] p2=ArrOps.IntKar(xL,yL);
int[] p3=ArrOps.IntKar(ArrOps.Add(xH,xL),ArrOps.Add(yH,yL));
res=ArrOps.Add(ArrOps.IntSL(p1,2*länge),ArrOps.Add(ArrOps.IntSL(ArrOps.Sub(p3,ArrOps.Add(p1,p2)),länge),p2));
return res;
}


melden

Mergesort Processing

24.04.2010 um 21:19
@interpreter
Zitat von interpreterinterpreter schrieb:1 Instanz aufgerufen mit 0 und 7
2 Instanz mit 0 und 3
3 Instanz mit 4 und 7
Eben nicht. Das ist ja das Schwierige an Rekursionen:

1 Instanz aufgerufen mit 0 und 7
2 Instanz mit 0 und 3
3 Instanz mit 0 und 1
4 Instanz mit 0 und 0

Und jetzt wird erst zum ersten Mal der zweite Aufruf gemacht....

4. Instanz kehrt zurück zum 2. Aufruf. zweiter Aufruf erfolgt mit l==0 und r ==0
und so weiter
Zitat von interpreterinterpreter schrieb:n den jeweiligen Instanzen wird l und r nicht geändert.
aber es wird abgefragt und ist Abbruch - Bedingung. Und jede Instanz wird mit anderen Werten aufgerufen.

Hab Geduld bis morgen. Da Du C# programmierst nehme ich an, dass Du VStudio hast. Ich poste morgen einen Code, bei dem Du nur die "§" durch 4 Blanks ersetzen musst um ihn kompilieren und debuggen zu können. Und dann geh den Code mal im Step - mode mit dem Debugger durch. Ist einfacher als wenn ich 10 Seiten Analyse schreiben muss. :)


1x zitiertmelden

Mergesort Processing

24.04.2010 um 21:42
Wenn er aus der vierten Instanz zurückkehrt wird die zweite hälfte der dritten Instanz mit 2 und 3 aufgerufen.
Es ist eine Instanz. Warum sollten sich die Parameter ändern.
Zitat von OpenEyesOpenEyes schrieb:Eben nicht. Das ist ja das Schwierige an Rekursionen:

1 Instanz aufgerufen mit 0 und 7
2 Instanz mit 0 und 3
3 Instanz mit 0 und 1
4 Instanz mit 0 und 0
Ja genau die4 Instanz läuft in die Abbruchbedingungen und die Dritte Instanz ruft die 5te Instanz auf mit 1und 1 die widerum abbricht.
Darufhin werden die for-schleifen der 3ten Instanz durchlaufen die 0 und 1 sortieren .

Die zweite hälfte der 2ten Instanz ruft die 6te Instanz auf. Die wird mit 2 und 3 aufgerufen.
Zwei Unterinstanzen die mit 2 2 und 3 3 aufgerufen werden brechen nacheinander ab dann sortiert er 2 und 3, verlässt die 6te Instanz und sortiert zurück in der 2ten Instanz
0 und 1 mit 2und 3. Wenn die 2te Instanz damit terminiert ist beginnt das gleiche Spielchen nochmal in der 2ten Rekursion der 1ten Instanz.

Du solltest bedenken das die If-Verzweigung nicht nochmal durchlaufen wird wenn er aus einem unteren Rekursionsschritt zuückkommt.


1x zitiertmelden

Mergesort Processing

24.04.2010 um 21:43
Zitat von interpreterinterpreter schrieb:Wenn er aus der vierten Instanz zurückkehrt wird die zweite hälfte der dritten Instanz mit 2 und 3 aufgerufen.
Ignorier diesen Abschnitt.


melden

Mergesort Processing

24.04.2010 um 23:42
@OpenEyes

kleines Detail. C# abstrahiert die System-schicht komplett, ähnlich wie Java.

Da bei diesem Algorithmus der zeiger auf das Array a[] übergeben würd gehe ich davon aus das es sich bei der Sprache um C ,C++ oder eine ähnliche Programmiersprache handelt.

Dieser Algorithmus kann unter C# folglich nicht funktionieren.

in C# sind die Arrays Objekte und keine Zeiger auf Speicherplätze. So werden sie zu lokalen Variablen.


1x zitiertmelden

Mergesort Processing

24.04.2010 um 23:58
@interpreter
Wenn ich deine Beiträge so lese, ist mir nicht ganz klar, worüber wir zwei uns "gestritten" haben. Wir sind uns doch einig!

@OpenEyes
Du sagst, du kannst sicher reden, weil du es ausprobiert hast. Das mag sein. Habe ich auch, aber offensichtlich mit einem anderen Compiler. Unter C funktioniert der Algorithmus genau so wie beschrieben. Da sind r und l lokale Variablen, sprich was auch immer in "unteren" Instanzen passiert, es ändert nicht das r und l in der aufrufenden Instanz.

Wenn du aber mit einer Programmiersprache arbeitest, die das anders macht, dann verstehe ich dein Problem. Dann kann das nicht funktionieren...


1x zitiertmelden

Mergesort Processing

25.04.2010 um 00:37
Zitat von LuftonLufton schrieb:Unter C funktioniert der Algorithmus genau so wie beschrieben. .
Das habe ich auch vermutet.

Der Algorithmus ist übrigens einer für den C bzw C++ praktisch prädestiniert ist. Das sortieren eines Arrays wäre mit einer Alles-Ist-Objekt-Sprache wesentlich schwieriger zu realisieren.


1x zitiertmelden

Mergesort Processing

25.04.2010 um 02:40
Anhang: testmergesort.exe (173, KB)Also hier einmal eine lauffähige C Version des Programmes. Wie man sieht, habe ich lediglich ein paar Spielereien eingebaut. Z.B., dass das Hilfsarray dynamisch abhängig vom übergebenen Wert angelegt wird.

Dann meldet sich jede Instanz von mergesort, sagt der wievielte Aufruf er ist, in welcher Rekursionsebene er sich gerade befindet und welchen String er sortieren soll. (Und ja, ich weiß, dass man da noch viel optimieren kann. Bin etwas eingerostet in C... Wollte aber zeigen, dass es so funzt.

Das lauffähige Programm habe ich auch mal angefügt. Es erwartet als Parameter den zu sortierenden String. Für unser Beispiel wird es also mit "testmergesort caroline" aufgerufen.


Hier die Source:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int iRekEbene = 0;
int iAnzAufruf = 0;


void mergesort( char *, char *, int, int );



int main(int argc, char *argv[])
{
int iAnzElemente = 0;
int z;
if (argc > 1)
{
printf( "zu sortierender String: %s\n", argv[1] );
for (z=0;argv[1][z]>0;z++) iAnzElemente++;
printf( "Anzahl Elemente : %d\n\n", iAnzElemente );
char b[ iAnzElemente ]; // Hilfarray anlegen mit gleicher Größe
mergesort( argv[1], &b[0], 0, iAnzElemente - 1 );
printf( "\nsortierter String : %s\n\n", argv[1] );
}
return 0;
}


void mergesort( char a[], char b[], int l, int r ) // l=linker Rand, r=rechter Rand
{
int iCount;

iAnzAufruf++; // der wievielte Aufruf von Mergesort ist das?
iRekEbene++; // welche Rekursionsebene?


printf( "%3d. Aufruf, %3d. Ebene, sortiere den String: ", iAnzAufruf, iRekEbene);
for(iCount=l; iCount <= r ; iCount++) printf("%c",a[iCount]);
printf("\n");

if(r>l) // ist es mehr als ein Element?
{
int i, j, k, m; // Variablen deklarieren
m=(r+l)/2; // Mitte ermitteln
mergesort(a, b, l, m); // linke Teildatei rekursiv sortieren lassen
mergesort(a, b, m+1, r); // rechte " " " "
for(i=m+1; i>l; i--) b[i-1]=a[i-1]; // linke Teildatei in Hilfsarray
for(j=m; j<r; j++) b[r+m-j]=a[j+1]; // rechte Teildatei umgedreht in Hilfsarray
for(k=l; k<=r; k++)
a[k]=(b[ i ] < b[ j ] ) ? b[ i++ ]:b[ j-- ]; // füge sortiert in a ein
}

iRekEbene--;
}


melden