Erklärung des Codes

Hallo!

Kann mir jemand bitte diesen Code erklären? Also was die einzelnen Methoden ect. sind und machen! Bin ein blutiger Anfänger in Java!

Danke im Voraus!



    public static char getChar(String str, int pos) {
        return (pos < str.length()) ? (str.charAt(pos)) : (char) 96;
    }

    public static void radixSort(Object[] array) {        
        @SuppressWarnings("unchecked") //?????????
        ArrayList<Object>[] buckets = (ArrayList<Object>[]) new ArrayList[27];

        for (int i = 0; i < 3; i++) { // Pro Stelle ein Durchgang
            for (int j = 0; j < 27; j++) {
                buckets[j] = new ArrayList<Object>();
            }

            for (int j = 0; j < array.length; j++) {
                int bucketNumber = (int) getChar(array[j].toString().toLowerCase(), 2 - i) - 96;
                buckets[bucketNumber].add(array[j]);
            }

            int k = 0;
            for (int j = 0; j < 27; j++) {
                for (Object str : buckets[j]) {
                    array[k++] = str;
                }
            }
        }
    }
}```

So ganz allgemein hier wird sortiert:
http://de.wikipedia.org/wiki/Radixsort

Wo hängt es denn? Bis wohin ist noch alles klar?

um ehrlich zu sein verstehe ich den Code überhaupt nicht! leider

Schleifen, if-Abfragen, Variablentypen, Klassen und Methoden…
…das sind nun mal Grundlagen, ohne die wirst du nie Java verstehen können.

Die Eigeninitiative und Bereitschaft Java zu erlernen, können wir dir hier leider nicht geben.

Das hier return (pos < str.length()) ? (str.charAt(pos)) : (char) 96; ist der ternäre Operator, eine Art abgekürztes “if” in der Form “Bedingung ? dann das : sonst das”.

Das @SuppressWarnings("unchecked") kannst du erst einmal ignorieren, wie der Name sagt unterdrückt es eine Compiler-Warnung (die gibt es, weil Arrays nicht mit Generics umgehen können).

Der Rest sind Zuweisungen, Methoden und Schleifen, entweder normale oder sogenannte erweiterte oder “for-each” (die mit Doppelpunkt). Das solltest du dir aber wirklich selbst aneignen.

Wenn du etwas nicht verstehst (oder überprüfen willst, ob du es richtig verstanden hast), schau dir mal an, wie ein Debugger funktioniert, damit kannst du das Programm Schritt für Schritt ausführen lassen, Inhalte auslesen u.s.w.

Wieso willst du denn so “komplizierten” Code verstehen? Nimm dir doch was einfacheres für den Anfang vor, wenn du noch so ein blutiger Anfänger bist. Einige Themen wurden ja hier schon genannt:

  • If-Bedingung
  • for-schleife
  • Klassen
  • Methoden

Also der Code ist schon ziemlich häßlich… Hab’ mal versucht den zu kommentieren, vielleicht hilft’s dir weiter.

‘kommentierter Quellcode’
[spoiler]
Die Kommentierung geschah “aus dem Handgelenk”, ich habe nicht getestet ob die Zeilen tatsächlich das tun was ich vermute…

    /**
     * Extrahiert ein einzelnes Zeichen aus einem String
     *
     * @param str
     *    String, aus dem ein einzelnes Zeichen extrahiert wird
     *
     * @param pos
     *    Position des zu extrahierenden Zeichens im String
     *
     * @return
     *    Das extrahierte Zeichen. Wenn das gewünschte Zeichen nicht
     *    im String existiert (weil der String zu kurz ist) wird das
     *    Zeichen 96 ("`") zurückgegeben (dieses Zeichen ist das größte
     *    aller Zeichen, die lexikographisch kleiner als 'a' sind)
     */
    public static char getChar(String str, int pos) {
        return (pos < str.length()) ? (str.charAt(pos)) : (char) 96;
    }
    /*
     * Anmerkung: diese Methode könnte man auch "ausfuehrlich" 
     * schreiben. Das saehe dann z.B. so aus:
     * 
     *    public static char getChar(String str, int pos) {
     *        char result;
     *
     *        if( pos < str.length() ) {
     *           result = str.charAt(pos);
     *        } else {
     *           result = (char) 96;
     *        }
     *        
     *        return result;
     *    }
     */


    /**
     * sortiert ein array vom Typ Object.
     * Die Sortierung erfolgt lexikographisch nach denjenigen Strings,
     * welche die Aufrufe von Object.toString() zurückgeben. Die Strings 
     * duerfen nur Buchstaben und das Zeichen '`' enthalten.
     * 
     * @param array 
     *   die zu sortierenden Objekte
     */
    public static void radixSort(Object[] array) {
        // unterdruecke "unchecked"-Compilerwarnungen. Ansonsten wuerde
        // der Compiler meckern wenn er die Einhaltung der Typsicherheit
        // nicht sicherstellen kann.
        @SuppressWarnings("unchecked") //?????????

        // lege ein Array von 27 buckets an. ein bucket ist dabei 
        // eine ArrayList mit Objekten vom Typ Object
        ArrayList<Object>[] buckets = (ArrayList<Object>[]) new ArrayList[27];

        // iteriere über drei Stellen, nach denen sukzessiv sortiert werden soll
        // (erst nach der dritten, dann nach der zweiten, dann nach der ersten)
        for (int i = 0; i < 3; i++) {

            // initialisiere jeden der 27 Buckets mit einer leeren ArrayList
            // (vom Typ Object)
            for (int j = 0; j < 27; j++) {
                // bucket nummer j wird eine nigel-nagel-neue ArrayList
                // zugewiesen. diese kann Objekte aller Art aufnehmen.
                buckets[j] = new ArrayList<Object>();
            }

            // iteriere ueber die gegebenen Objekte um sie in die buckets
            // zu verteilen
            for (int j = 0; j < array.length; j++) {

                // bestimme die Nummer eines buckets. Dazu wird das aktuelle Object
                // mittels seiner individuellen Methode in einen String umgewandelt
                // (lowerCase) und aus diesem String ein einzelnes Zeichen (an
                // Position 2-i) extrahiert. Es wird gehofft, das dieses Zeichen ein
                // Kleinbuchstabe oder das Zeichen "`" ist. Der so erhaltene ASCII-Wert
                // wird anschliessend auf einen Wert zwischen 0 und 26 (einschliesslich)
                // abgebildet (durch das -96)
                int bucketNumber = (int) getChar(array[j].toString().toLowerCase(), 2 - i) - 96;

                // das aktuelle Object wird in den bucket mit der zuvor ermittelten
                // Nummer gelegt
                buckets[bucketNumber].add(array[j]);
            }

            // das Array wird im Folgenden neu befuellt. Die bisher darin enthaltenen
            // Referenzen auf die Objekt werden dabei ueberschrieben. Diese Referenzen
            // befinden sich aber noch in den buckets. Wir durchlaufen die buckets um
            // alle Objekt wieder ins Array hineinzuschreiben, allerdings in einer
            // neuen Reihenfolge

            // Derjenige Index, an welchen das naechste Objekt ins Array geschrieben
            // wird, wird mit 0 initialisiert
            int k = 0;

            // iteriere ueber die 27 buckets
            for (int j = 0; j < 27; j++) {

                // iteriere ueber die Objekte im aktuellen bucket
                for (Object str : buckets[j]) {

                    // hole das aktuelle Objekt aus dem aktuellen bucket und schreibe
                    // es ins Array. dann erhoehe den Index fuer die Schreibposition
                    // des Arrays.
                    array[k++] = str;
                }
            }
        }
    }

[/spoiler]

Vielen Dank für die Erklärung erstmal!

 int[]   nPart = new int[2];
 int[][] part  = new int[2][a.length];

Die zwei Zeilen haben dich bestimmt verwirrt, oder? Mich auch.

Man muss sich forstellen, dass es zwei Arten von Fächern gibt: Ein Array mit Fächern in denen partitioniert wird und ein Array mit Zahlen in dem gesammelt wird. Welches welches ist, kann ich aber nicht sagen. Meine Murmel brummt schon wieder.

Je länger die Schlüssellänge der Elemente (der zu sortierenden Ele…), desto größer der Faktor m. Das habe ich begriffen. Wenn m zu groß is, schlägt die n*log_2(n)-Laufzeit die des Radixsort’s. Das ist auch klar. Auch wenn man praktisch nicht von einer unendlichen Schlüssellänge ausgehen kann.

Mal’ dir diese Kästchen auf Papier oder lege Bücher in Kartons, um alles zu klar zu machen.

Kann man den Code auch mit Arrays statt Strings implementieren? Falls ja, wie?

Danke im Voraus!

[QUOTE=Unregistered]Kann man den Code auch mit Arrays statt Strings implementieren?[/QUOTE]Ja kann man. [QUOTE=Unregistered;60830]Falls ja, wie?[/QUOTE]Wenn du einen Vorschlag machst, können wir dir sagen, was du evtl. besser / anders machen kannst. Geholfen wird gerne, wenn der Fragesteller schon was vorzuweisen hat. So aus dem nichts wird dir keiner Code präsentieren.

Ja, das geht. Da musst du mal schauen an welchen Stellen das Programm Bezug auf die Strings nimmt. Und diese Stellen dann halt entsprechend ändern damit sie stattdessen Arrays verwenden.

Würde es so gehen? Also ich bekomme eine Fehlermeldung bei array.charAt(pos)!

     
       public static char getChar(String[] array, int pos) {
           
           char result;
           
           if( pos < array.length ) {
            result = array.charAt(pos); //bei array.charAt(pos) bekomme ich eine Fehlermeldung
             } else {
            result = (char) 96;
             }

            return result;
            }       

    public static void radixSort(Object[] array) {        
        @SuppressWarnings("unchecked") //?????????
        ArrayList<Object>[] buckets = (ArrayList<Object>[]) new ArrayList[27];

        for (int i = 0; i < 3; i++) { // Pro Stelle ein Durchgang
            for (int j = 0; j < 27; j++) {
                buckets[j] = new ArrayList<Object>();
            }

            for (int j = 0; j < array.length; j++) {
                int bucketNumber = (int) getChar(array[j].toString().toLowerCase(), 2 - i) - 96;
                buckets[bucketNumber].add(array[j]);
            }

            int k = 0;
            for (int j = 0; j < 27; j++) {
                for (Object str : buckets[j]) {
                    array[k++] = str;
                }
            }
        }
    }
}```

Arrays sind keine Strings, du bekommst den Inhalt eines Elements über array[pos]. Aber das sind wirklich einfachste Grundlagen, also bist du reif für die Insel: http://openbook.galileocomputing.de/javainsel9/javainsel_03_007.htm#mj11a4689950bdbe50e0c6342eb22737a6

Ich habe dir das mal implementiert: ``` public static void sortiereStringsNachRadixsort(String… strings) {
int len = 0;
for (String string : strings) {
if (string.length() > len)
len = string.length();
}
ArrayList[] box = new ArrayList[256];
for (int i = 0; i < box.length; i++) {
if (i == 0) {
box[0] = new ArrayList(strings.length < 10 ? 10 : strings.length); // box[0] bigger/greater
continue;
}
box** = new ArrayList();
}
for (int i = len - 1; i >= 0; i–) {
//partitionieren
for (String string : strings) {
if (i < string.length()) {
box[string.charAt(i)].add(string);
} else {
box[0].add(string);
}
}
//aufsammeln
int j = 0;
for (ArrayList arrayList : box) {
for (Iterator iter = arrayList.iterator(); iter.hasNext(); iter.remove()) {
strings[j++] = iter.next();
}
}
}
}

public static void main(String[] args) {
    String[] s = "Es war ein mal ein Latten zaun, mit Zwischen raum, um hin durch zu schauen".split(" ");
    sortiereStringsNachRadixsort(s);
    System.out.println(Arrays.toString(s));
}```

Jetzt sieht man zwei Dinge: Die Laufzeit beträgt 256n (n ist die Anzahl der Strings), also (m) n (beides in Theta); wenn man weiß, wie lang die Strings der Übergabe sind, reicht auch ne Array; und Deque ist bei diesen Queue-/Stack-ähnlichen Aufgaben zu bevorzugen.

Edit: bigger, greater, larger, wie auch immer; und bei chars > 255 crasht das Programm mit einer AIOOBE.

Hier einmal mit ArrayDeque:

        int len = 0;
        for (String string : strings) {
            if (string.length() > len) {
                len = string.length();
            }
        }
        ArrayDeque<String>[] box = new ArrayDeque[256];
        for (int i = 0; i < box.length; i++) {
            box** = new ArrayDeque<String>();
        }
        for (int i = len - 1; i >= 0; i--) {
            //partitionieren
            for (String string : strings) {
                if (i >= string.length()) {
                    box[0].add(string);
                } else {
                    box[string.charAt(i)].add(string);
                }
            }
            //aufsammeln
            int j = 0;
            for (ArrayDeque<String> arrayDeque : box) {
                while (!arrayDeque.isEmpty()) {
                    strings[j++] = arrayDeque.remove();
                }
            }
        }
    }```

Und ein Microbenchmark dazu:

```    public static void main(String[] args) {
        String[] s = "aaaa aaa Es war ein mal ein Latten zaun, mit Zwischen raum, um hin durch zu schauen".split(" ");
        sortiereStringsNachRadixsort(s);
        System.out.println(Arrays.toString(s));
        //microbenchmark
        Random r = new Random();
        s = new String[100000];
        System.arraycopy("eins zwei drei".split(" "), 0, s, 0, 3);
        for (int i = 3; i < s.length; i++) {
            s** = s[r.nextInt(3)];
        }
        String[] s1 = new String[s.length];
        System.arraycopy(s, 0, s1, 0, s.length);

        long t1 = System.currentTimeMillis();
        Arrays.sort(s1);
        long t2 = System.currentTimeMillis();

        System.out.println(s1[0] + " " + s1[1] + " " + s1[2]);
        s1 = new String[s.length];
        System.arraycopy(s, 0, s1, 0, s.length);

        long t3 = System.currentTimeMillis();
        sortiereStringsNachRadixsort(s1);
        long t4 = System.currentTimeMillis();

        System.out.println(s1[0] + " " + s1[1] + " " + s1[2]);
        System.out.println(s[0] + " " + s[1] + " " + s[2]);
        System.out.println("modified qs:     " + (t2 - t1));
        System.out.println("rs (deque-impl): " + (t4 - t3));
    }```

Jetzt passiert etwas Erstaunliches, obwohl ich das nicht mit Arrays primitiver Typen realisiert habe, ist das (lineare) Sortierverfahren in diesem Falle etwas schneller als QuickSort:


run:
[Es, Latten, Zwischen, aaa, aaaa, durch, ein, ein, hin, mal, mit, raum, schauen, um, war, zaun, zu]
drei drei drei
drei drei drei
eins zwei drei
modified qs: 395
rs (deque-impl): 42
BUILD SUCCESSFUL (total time: 0 seconds)



Grüßle

*** Edit ***

Mhm, schon wieder geirrt, Arrays.sort(s1) kein QS, sondern whrs. MergeSort.

Wenn man das Sortierverfahren einmal aufschreibt, hat man es schnell gelernt. :verzweifel:

Ich kann mich daran erinnern das mein Tutor mir einmal Radixsort erklären wollte, ich in der Stunde aber geschlafen habe. Und dann wollte unser Prof. einmal einen Beweis vorbringen, als ich zuvor allerdings ziehmlich auffällig den Raum verlassen habe. Kein Wunder, das ich von der Uni geflogen bin.

Aber ich habe auch gelesen, das besserbegabte Kinder schlechter lernen können als andere, weil sie "das richtige$ Lernen niemals gelernt haben, resp. anders lernen als andere.

Aber die Schulzeit ist ja auch schon etwas länger her, und das andere heißt sich ja auch "Erwachsenenbildung". :verzweifel: