Sortieralgorithmen in Java

  • Hallo Leute,
    ich hatte vor einiger Zeit in Informatik das Thema Sortieralgorithmen.
    Wir Programmieren eigentlich immer nur in Java und meistens mit der Oberfläche BlueJ.
    Im Unterricht haben verschieden Algorithmen besprochen, wie den Insertion-Sort, den Bubble-Sort, usw.
    Da mir die Laufzeit aber immer etwas zu lang war, dachte ich mir das ich einfach mal einen eigenen Sortieralgorithmus schreibe, der NICHT auf Vertauschungen basiert.
    Nachdem das Programm geschrieben war und alle Bugs beseitigt waren, konnte ich stolz einen Algorithmen präsentieren, der positive, ganze Zahlen extrem schnell (25 Mio zufällige Zahlen von 0- 10 Mio werden in weniger als 1 Sekunde sortiert) sortiert, leider nur positive Integers...
    Ich hab auch eine Idee wie ich negative sortieren kann, nur wird das mit den Kommazahlen schwer, da ein Array in Java den Index 1,2 nicht besitzt.
    Vielleicht kennt sich einer von euch damit etwas besser aus und hat ein par Ideen, hier ist der komplette Quellcode:


    /**
    * Switch-Sort:
    * Ein nicht auf Vertauschungen basierender Algorhytmus der ohne (direkte) Vergleiche und mit nur 3 durchläufen
    * einen Array mit belibig vielen Zahlen sortiert.
    */
    public class SwitchSort
    {
    private int pAnzahlZahlen;
    private int pZahlengröße;
    private int ÜbertragsArray[];
    private int StartArray [];
    private int merker = 0;
    public SwitchSort(int anzahlZahlen, int zahlengröße)
    {
    pAnzahlZahlen = anzahlZahlen;
    pZahlengröße = zahlengröße;
    StartArray = new int [pAnzahlZahlen];
    for(int i=0; i != pAnzahlZahlen; i++)
    {
    int p = 0;
    p = (int) (Math.random()*pZahlengröße); //Array wird zufällig befüllt
    StartArray[i] = p;
    }
    }

    public int größteZahl() //Diese Methode sucht die größte Zahl aus dem Array
    {
    int merker = StartArray[0];
    for(int i=0; i < pAnzahlZahlen; i++)
    {
    if(StartArray[i] > merker)
    {
    merker = StartArray[i];
    }
    }
    return merker;
    }

    public void DoTheMath()
    {
    int i; //Universal-Variable
    merker=this.größteZahl(); //Variable wird mit dem Wert der größten Zahl belegt
    i = merker+1;
    ÜbertragsArray = new int [i++]; //Hier wird ein Array Declariert, der die größe der größten Zahl hat
    int Zähler=0; //Zähler geht die eingelnen Indiezes im StartArray durch
    for(int t = StartArray.length-1 ; t >=0 ; t--) //Diese Schleife schreibt eine 1 in den passenden Index, wenn er nicht schon belegt ist, dann ADDIERT er eine 1 an den selben Index im MehrfachArray.
    {
    if(StartArray[t] >= 0)
    {
    ÜbertragsArray[StartArray[t]]++;
    }
    }

    for(int t=0;ÜbertragsArray.length != t; t++) //Diese Schleife Setzte die werte aus dem ÜbertragsArray nacheinander in den StartArray zurück, und erhöht dabei immer den Zähler,
    { //der auf den Index im StartArray zeigt, in den geschreiben werden darf. Sollte am selben Index etwas im MehrfachArray stehen,
    while(ÜbertragsArray[t] !=0) //wird der selbe Wert immer wieder in den Startarray geschriben (immer eine Stelle weiter) und dabei der MehrfachArray -1 gerechnet,bis dieser den Wert 0 annimmt.
    {
    StartArray[Zähler] = t;
    ÜbertragsArray[t] --;
    Zähler++;
    }
    }
    }
    }


    Wie gesagt das Programm vergleicht keine Zahlen sondern schreibt für eine 5 im ersten Array, eine 1 an den 5. Index im 2. Array (besser gesagt es wird 1 addiert).
    Was sagt ihr zum Programm? Lässt sich das so optimieren das ich auch negative und Kommazahlen sortieren kann und weiterhin nach dem selben Prinzip arbeiten kann?

  • sorry, wenn ich mir nun zu dieser späten Zeit nicht ganz den Quelltext durchgelesen hab, aber wie ich deiner Einleitung entnehmen kannn fehlen dir mehrdimensionale arrays, das geht in java so int array [][]auch hier zu lesen.


    kleine nicht meckern wollende Tipps zum posten:
    versuch den code in nem Spoiler einzubinden und eventuell hilft der codeblock noch für die Übersicht.


    mal blind dein code kopiert:


    ein weiterer Punkt: ich weiß nicht inwiefern dieses Forum das geeignete für die Fragestellung ist. Es gibt hier durchaus passende Mitglieder, nur ist es nicht unbedingt ein Programmierer und Mathematikerforum :-P

    Im Übrigen bin ich der Meinung, dass Karthago zerstört werden muss.
    (Ceterum censeo Carthaginem esse delendam (Cato Censorius))

    Einmal editiert, zuletzt von Pingoin ()

  • gut ich guck morgen nach der Fh mal inwieweit ich noch helfen kann... weil was du mit den abstrakten Arrays meinst, kann ich so noch nicht sehen und deinen Quelltext lesen hat nun auch keinen Sinn mehr bei der Uhrzeit, den Unterricht, den ich heute hatte, und dem Feierabendbierchen...

    Im Übrigen bin ich der Meinung, dass Karthago zerstört werden muss.
    (Ceterum censeo Carthaginem esse delendam (Cato Censorius))

  • du meinst also 1,2=6/5 und nicht erste palte zweite zeile...


    naja versuch es doch das doch indem du die einzelnen zahlen mit 10^16 zu multiplizieren und zu runden, dann hast du nur integer werte und so genau braucht es eh keiner... es frisst aber auch sehr viel speicher... wissenschafftlich realistisch brauch man die letzten 3-7 stellen hinter dem Komma, Zahlen die sich dann noch nicht entscheiden sind messtechnisch quasi gleich, also reicht das je nach zweck aus wie gesagt ein Array der größe frisst aber auch speicher:-P

    Im Übrigen bin ich der Meinung, dass Karthago zerstört werden muss.
    (Ceterum censeo Carthaginem esse delendam (Cato Censorius))

  • Also erstens mit dem Index 1,2 meine ich nicht 6/5. Bei abstrakten Arrays kann sind die Indices nicht immer mit ganzen Zahlen beziffert, also gibt es in einem Array z.B. Buchstaben als Indices.
    Nibooss : Ja solche Animationen findet man teilweise selbst auf Wikipedia und ich muss mir ja nicht anschauen wie mein Algorithmus arbeitet, ich hab den ja schließlich geschrieben ;)
    Und was sind hashmaps? Gibt es die in Java?


    Und das mein Algorithmus RAM frisst wie sonst was ist mir auch bewusst :D Ich habe ihn rein auf Schnelligkeit ausgelegt was mir auch verdammt gut gelungen ist.
    Außerdem verbraucht der nur etwas mehr wie 3 mal so viel RAM wie die anderen Algorithmen ^^

  • Infos über Hashmap:
    http://www.tutorialspoint.com/java/java_hashmap_class.htm
    Ich würde dir eine Hashmap empfehlen die ein Float als Key hat und ein Int als Value. Natürlich müsstest du dann auf Floats umsteigen aber das ist ja bei Komma Sachen generell nötig. Zum auslesen hast du ja noch das Eingabe Array ;)
    Béi weiteren Fragen schreib mir ne PN


    Das deutsche Volk ist ein Volk von Freien und deutscher Boden duldet keine Knechtschaft. Fremde Unfreie, die auf ihm verweilen macht er frei.

    Ich glaube an das Schlechte in Menschen und an das Gute im Hund

  • Das ganze sieht interessant aus, wird aber nicht gut mit anderen Werten als ganzen Zahlen funktionieren. Negative Zahlen ließen sich noch erreichen, wenn du neben der höchsten auch die niedgrigste Zahl ermittelst und dann dein "Übertrags-Array" entsprechend der Spanne zwischen größter und kleinster Zahl dimensionierst. Aber ganz davon abgesehen mag der Algorithmus zwar recht schnell sein von der Komplexität, aber er ist weder generisch noch besonders speicherfreundlich. Um generisch zu sein, muss man einfach Werte vergleichen, das kann man dann auch einfach auslagern in die Werte selbst. Und was den Speicher angeht, brauchst du im Vergleich zu "Vertauschenden"-Algorithmen doppelt so viel Speicher.
    Fazit: Interessanter Algorithmus, der nicht praktisch verwendbar ist.


    PS: Wenn hier schon mit Hashsets hantiert wird, kann man es auch gleich lassen, die bieten nämlich Sortierung

    Greif nach den Sternen kleiner Kerbal

  • Stimmt mein Programm verbraucht 2-3 mal so viel Speicher, ist bei über 10 Mio Zahlen aber auch mehr als 1.000 mal so schnell wie alle anderen.
    Und die Sortierung der Hashmaps nutzen dann, denk ich zumindest mal, auch einen Algorithmus der auf Vertauschungen basiert, oder?
    Wenn ja dann verwende ich die und nutze mein eigenes Verfahren.

  • Trisher von Hashsets war hier nirgends Rede. Hashmaps bieten soweit ich weiß keine Sortierung, Ich kann mich naturlich auch irren da mein Wissen zu 90% selbst beigebracht ist und daher nunmal lückenhaft ist.


    Das deutsche Volk ist ein Volk von Freien und deutscher Boden duldet keine Knechtschaft. Fremde Unfreie, die auf ihm verweilen macht er frei.

    Ich glaube an das Schlechte in Menschen und an das Gute im Hund

  • Ups, dass mit dem HashSet und HashMap war natürlich mein Fehler. In der Tat hat HashMap keine sinnvolle Sortierung. HashSet dummerweise auch nicht(dachte da an Collections.sort())
    Zu dem Algorithmus selber: bei 10^7 Zahlen bekomme ich ungefähr die 4-5fache Geschwindigkeit vom Arrays.sort(). 10^8 ist selbst mit 1GB für die VM nicht mehr machbar wegen des Speicherverbrauchs, was es schon fast unmöglich macht das auf 32bit Systemen einzusetzen. bei 2GB für die VM sind es auch wieder in etwa 4-5fache Geschwindigkeit.



    Meine Tests soweit (bei 10^8 Zahlen):
    "SwitchSort" ~2500-2600ms
    Array.sort() ~10000ms
    Collections.sort() ~ 72000ms (sehr sehr sehr speicherintensiv)


    Ichhab mir das ganze jetzt nochmal durch den Kopf gehen lassen und baue das gerade ein wenig um. Ich bin aber mit dem HashMap nicht so glücklich.

    Greif nach den Sternen kleiner Kerbal

  • Ich bin mittlerweile zu der Überzeugung gekommen, dass es mit einer HashMap nicht gut funkioniert. Ich sehe vorrangig zwei Probleme. Zum Einen steigt durch die Verwendung einer HashMap der Speicherverbrauch wieder dramatisch an. Außerdem glaube ich nicht dass es dann noch zu einem Zeitgewinn kommt, da das Erstellen einer HashMap/mehrerer HashMaps auch wieder Zeit kostet. Ich lasse mich aber gerne eines besseren belehren, aber es ist halt einfach ein Spezialfall des Integers, dass darüber die Position in einem Array zugeordnet werden kann. Das ist meinen Augen die ganze Magie an "SwitchSort".


    Übrigens finde ich die Idee sehr schön, dass du das "Übergangs"-Array nur so groß bemisst, wie tatsächlich die größte Zahl ist, das minimiert den Speicherverbrauch. Für den Spezialfall anzahl = größe ist es schneller "Übergangs"-Array gleich auf die Größe von Anzahl zu setzen und der Speicherplatzverlust ist minimal. Allerdings funktioniert es nur bis anzahl = größe danach kann es in eine ArrayIndexOutOfBounds-Exception laufen.
    Tatsächlich scheint es auch eine große Diskrepanz in der Zeit zu geben, wenn größe << anzahl.


    Für mich ist und bleibt es ein Spezialfall des Arrays mit Integer-Werten. Wenn es jemand schafft schneller als Array.sort() auf floats zu sein, wäre ich beeindruckt.
    Übrigens sind 10^9 an "Zahlenumfang" oder Anzahl an Zahlen selbst bei 4GB nicht mehr möglich ( benötigt werden jeweils 4,4gb). Beides zusammen ist selbst mit 10GB Speicher für die VM (!!!) nicht mehr möglich.


    Array.sort() setzt auf QuickSort. Die Implementierung hat aber den Vorteil, dass sie echt Multi-Threaded ist, was den Vorteil hat, dass es plötzlich viel schneller wird. Ich habe zu Hause nur einen 4 Kerner, ich werde morgen mal 10^9 und 10^8 per Array.sort() auf der Arbeit durchjagen (4Kerne+HT).


    Aber ich bin echt fasziniert von dem Ansatz, den habe ich seit dem ich angefangen habe zu programmieren noch nicht gesehen. Wobei ein Algorithmus für einen ausgeglichenen Baum dem sehr nahe kam.


    Edit: Das Ganze zeigt mir aber gerade nur, dass 0.22 immernoch nicht released ist... Verdammt
    Edit2: CountingSort auf Wikipedia

    Greif nach den Sternen kleiner Kerbal

    Einmal editiert, zuletzt von Trisher ()

  • Der nutzt echt Quicksort?
    Wir hatten den ja selber getestet (in der Schule) und bei 10^8 Zahlen haben wir den nach ein par Minuten abgebrochen, nichts mit ms :O
    Und ja ich glaube der Ansatz meines Algorithmus ist echt einzigartig *____*
    Und wie gesagt mir ist der Speicherverbrauch echt egal. Wenn man sich die riesigen Rechenzentren anschaut die mehrere TB an RAM haben, ich glaube die setzten auch ehr auf Schnelligkeit ^^

  • Ich hab mir mal die HashMaps angeschaut und sehe ein Problem,
    Beim Array habe ich vorher die Größe festgelegt und konnte irgendwo etwas reinschreiben, das geht mit Hashmaps ja leider nicht.


    Ich muss vor allem eine Hashmap erzeugen, wo die einzelnen float-werte schon als key drinstehen, sodass ich die wie ein Array behandeln kann :(
    Vielleicht finde ich ja eine Lösung.

  • Genau da ist ja das Problem. Im Endeffekt musst du ein Mapping finden, welches dann Zahlen im Array entspricht. also quasi ein int zu Wert und Anzahl. Das Problem ist, dass du die Werte irgendwie in Relation setzen musst. Bei deinem Algorithmus funktioniert dies explizit durch die Zuweisung zu einer bestimmten Position im Array, wobei die Position exakt dem Wert entspricht. Dies funktioniert aber eben nur bei Integern. Die Relation ist dann über die Position klar. Bei Floats geht das z.B. wieder nicht, weil du mit einem Float nicht auf ein Array zugreifen kannst. Um diese also zu soriteren, musst du sie in Relation setzen.
    Aber wenn du noch einen Algorithmus möchtest, der nicht auf Vertauschung basiert, dann wäre es einfach das Array abzulaufen und zB in eine Liste an der richten Position (hier sind Vergleiche nötig) einzufügen.
    Ich sehe ehrlich gesagt keine Lösung für das Problem mit der Hashmap. Du musst dazu ja wissen welche Werte du alle hast und selbst dann, musst du die Information über die Position und die Häufigkeit mitschleifen. Bei Ganzzahlen hast du den Vorteil, das Wert, Position und Anzahl eine besondere Konstellation bieten.

    Greif nach den Sternen kleiner Kerbal

    Einmal editiert, zuletzt von Trisher ()