Pivot-Wahl beim QuickSort steigert die Effizienz, eine Lüge???

deggit_biber

Aktives Mitglied
Hallo

Ich beschäftige mich gerade mit dem QuickSort genau gesagt mit der Wahl eines geeigneten Pivot-Elements zur Steigerung der Effizienz.

Soweit ich gelernt habe, trägt die Wahl des Pivot-Elements maßgeblich zur Effizienz des Algorithmus bei. Dies wollte ich einmal überprüfen, indem ich drei verschieden Varianten, die sich in ihrer Wahl des Pivot-Elements unterscheiden, programmiert habe.

Variante 1: quickSortLinks
Immer das linke Element als Pivot nehmen

Variante 2: quickSortMitte

Immer ein Element aus der Mitte nehmen
Variante 3 quickSortRandom

Drei Werte Random aussuchen und dann das nehmen, welches vom Wert in der Mitte liegt.

Die Effizienz überprüfe ich mit einem einfachen Zähler, der Vergleiche. Alle drei Algorithmen laufen auf einem eigenen Array, welches aber von der Int-Wert Belegung identisch sind.

Zu meinem Erstaunen benötigen alle drei Algorithmen fast genau die gleiche Anzahl an vergleichen, um das Array zu sortieren.

Jetzt frage ich mich, habe ich etwas falsch gemacht?
- Zähler an der falschen stelle
- falscher QuickSort-Algorithmus? (Der Grund-Algo, stammt von dieser Seite: http://www.algolist.net/Algorithms/Sorting/Quicksort)
- wer weiß was… ;-)

Hier einmal der Code.
Java:
import java.util.Random;

/**
* Beschreiben Sie hier die Klasse Sortieren.
*
* @author (Ihr Name)
* @version (eine Versionsnummer oder ein Datum)
*/
public class QuickSortPivot
{
    int n;
    int vergleicheLinks=0, vergleicheMitte=0, vergleicheRandom=0;
   
    private int[] arr1;
    private int[] arr2;
    private int[] arr3;   

    /**
     * Konstruktor für Objekte der Klasse Sortieren
     *
     * @param pElemente Anzahl der zu sortierenden Elemente
     *
     */
    public QuickSortPivot(int pElemente)
    {    
        System.out.print('\u000C'); // Konsole leeren. 
        arr1 = new int[pElemente];
        arr2 = new int[pElemente];
        arr3 = new int[pElemente];

        arrayFuellen();
        arrayDuplizieren();

        System.out.println("Elemente des unsortierten Arrays:");
        arrayAusgebenLinks(arr1);
        System.out.println("");

   
        quicksortLinks(arr1, 0, arr1.length-1);
        System.out.println("Pivot-Element Links");
        arrayAusgebenLinks(arr1);
        System.out.println("");

        //quicksortLinks(arr1, 0, arr1.length-1);
        //System.out.println("Pivot-Element Links - Erneutes Sortieren auf dem bereits sortierten Array");
        //arrayAusgebenLinks(arr1);
        //System.out.println("");
       

        quicksortMitte(arr2, 0, arr2.length-1);
        System.out.println("Pivot-Element Mitte");
        arrayAusgebenMitte(arr2);
        System.out.println("");

        //quicksortMitte(arr2, 0, arr2.length-1);
        //System.out.println("Pivot-Element Mitte - Erneutes Sortieren auf dem bereits sortierten Array");
        //arrayAusgebenMitte(arr2);
        //System.out.println("");

       
        quicksortRandom(arr3, 0, arr3.length-1);
        System.out.println("Pivot-Element Random");
        arrayAusgebenRandom(arr3);
        System.out.println("");

        //quicksortRandom(arr3, 0, arr3.length-1);
        //System.out.println("Pivot-Element Random - Erneutes Sortieren auf dem bereits sortierten Array");
        //arrayAusgebenRandom(arr3);
        //System.out.println("");
    }  

    /**
     * Die Methode arrayFuellen() befüllt das Array
     * mit Random-Werten zwischen 0 und 100
     */  
    public void arrayFuellen()
    {
        Random rnd = new Random();

        for(int i=0; i<=arr1.length-1; i++)
        {
            arr1[i] = rnd.nextInt(1000);   //liefert eine zufällige Zahl zwischen 0 und 1000
        }
    }
    /**
     * Die Methode arrayDuplizieren() vervielfältigt
     * das Original-Array
     */  
    public void arrayDuplizieren()
    {
        for(int i=0; i<=arr1.length-1; i++)
        {
            arr2[i] = arr1[i]; 
            arr3[i] = arr1[i];
        }
    }

   

    void quicksortLinks(int arr[], int left, int right)
    {
        int index = partition(arr, left, right);
        if (left < index - 1)
            quicksortLinks(arr, left, index - 1);
        if (index < right)
            quicksortLinks(arr, index, right);
    }
    int partition(int arr[], int left, int right)
    {
        int i = left, j = right;
        int tmp;
        int pivot = arr[left];

        while (i <= j)
        {
            vergleicheLinks++;
            while (arr[i] < pivot) i++;
            while (arr[j] > pivot) j--;
           
            if (i <= j)
            {
               
                tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
                i++;
                j--;
            }
        }
        return i;
    }

   
   
    void quicksortMitte(int arr[], int left, int right)
    {
        int index = partition2(arr, left, right);
        if (left < index - 1)
            quicksortMitte(arr, left, index - 1);
        if (index < right)
            quicksortMitte(arr, index, right);
    }
    int partition2(int arr[], int left, int right)
    {
        int i = left, j = right;
        int tmp;
        int pivot = arr[(left + right) / 2];

        while (i <= j)
        {
            vergleicheMitte++;
            while (arr[i] < pivot) i++;
            while (arr[j] > pivot) j--;
           
            if (i <= j)
            {
               
                tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
                i++;
                j--;
            }
        }
        return i;
    }   

   
    void quicksortRandom(int arr[], int left, int right)
    {
        int index = partition3(arr, left, right);
        if (left < index - 1)
            quicksortRandom(arr, left, index - 1);
        if (index < right)
            quicksortRandom(arr, index, right);
    }
    int partition3(int arr[], int left, int right)
    {
        int i = left, j = right;
        int tmp;
       
        // Vergleichselement pivot
        int p1=0, p2=0, p3=0;
        int pivot = 0;

        Random rnd1 = new Random();
        Random rnd2 = new Random();
        Random rnd3 = new Random();
       
        if (arr.length<3)
        {
            pivot = arr[left];
        }
       
        if (arr.length>=3)
        {
            p1 = arr[left+rnd1.nextInt(right-left+1)];  
            p2 = arr[left+rnd2.nextInt(right-left+1)];
            p3 = arr[left+rnd3.nextInt(right-left+1)];   

            if (p2<p1 && p3>p1 || p2>p1 && p3<p1)    
            {
                pivot = p1;
            }
            if (p1<p2 && p3>p2 || p1>p2 && p3<p2)    
            {
                pivot = p2;
            }
            if (p1<p3 && p2>p3 || p1>p3 && p2<p3)    
            {
                pivot = p3;
            }

            if (p1==p2 || p2==p3 || p1==p3)  
            {
                pivot = p1;
            }
        }
  
        while (i <= j)
        {
           
            while (arr[i] < pivot) i++;
            while (arr[j] > pivot) j--;
           
            if (i <= j)
            {
                vergleicheRandom++;
                tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
                i++;
                j--;
            }
        }
        return i;
    }      

   

    /**
     * Die Methode arrayAusgeben() gibt die Integer-Werte
     * der der Arrays aus.
     *
     */   
    public void arrayAusgebenLinks(int arr[])
    {
        for(int i=0; i<=arr.length-1; i++)
        {
            System.out.print(arr[i] + ", ");
        }
        System.out.println("");
        System.out.print("Anzahl der Vergleiche: " +vergleicheLinks);
        System.out.println("");
    } 
    public void arrayAusgebenMitte(int arr[])
    {
        for(int i=0; i<=arr.length-1; i++)
        {
            System.out.print(arr[i] + ", ");
        }
        System.out.println("");
        System.out.print("Anzahl der Vergleiche: " +vergleicheMitte);
        System.out.println("");
    }
    public void arrayAusgebenRandom(int arr[])
    {
        for(int i=0; i<=arr.length-1; i++)
        {
            System.out.print(arr[i] + ", ");
        }
        System.out.println("");
        System.out.print("Anzahl der Vergleiche: " +vergleicheRandom);
        System.out.println("");
    }   
}

Ich habe die drei Algorithmen auf einem Array der Größe 10000, mit random Elemente zwischen 0 und 1000, laufen lassen. Ausgabe siehe Anhang


Im Anhang mein BlueJ-Projekt.

Ich würde gerne wissen, ob ich einen Fehler gemacht habe, oder ob das mit der Wahl des Pivot-Elements doch nicht stimmt. (kann ich mir ja eigentlich nicht vorstellen)

viele liebe Grüße,
Deggit
 

Anhänge

  • quicksort.JPG
    quicksort.JPG
    45,5 KB · Aufrufe: 58
  • 120_Aufgabe1_Sortieren_Loesung.zip
    21,5 KB · Aufrufe: 7

JCODA

Top Contributor
Soweit ich gelernt habe, trägt die Wahl des Pivot-Elements maßgeblich zur Effizienz des Algorithmus bei.
Das stimmt. Allerdings hat es nichts damit zu tun, das Pivot links,rechts oder random zu wählen. (Das ist in diesem Fall einfach "random" (weil ohne Betrachtung der Gesamtheit der Elemente))
Sondern es hat damit zu tun, wie es sich zum median verhält. Wenn du als Pivot immer den Median wählst, hast du die beste Laufzeit, da die rekursiven Reste möglichst gleichgroß sind.
Leider benötigt man auch Zeit um den Median zu berechnen, deshalb versucht man eine gute "Heuristik" zu finden, um möglichst nahe am Median zu liegen.
 

deggit_biber

Aktives Mitglied
@JStein52: Danke, dass du auch hier einmal rein schaust.
1) Wie das angehängte Projekt enthält den QuickSort nicht. Liegt es vielleicht an der BlueJ-Datei? ICh habe den Anhang gerade noch einmal heruntergeladen und mit BlueJ geöffnet. Klappt alles.
2) In der Ausgabe sind die Pivot-Element gar nicht sichtbar. Sondern nur die Elemente der Array und die Anzahl der Vergleiche die benötigt wurden, um das Array zu sortieren.

@JCODA: Auch dir vielen Dank, dass du einmal drüber geschaut hast.
Aber gerade beim 3er Random Wählen müsste doch statistisch Häufiger ein Wert in der Mitte raus kommen als beim immer links wählen.

Beispiel:
Sei Zahlenreihe:
787, 960, 515, 12, 341, 740, 882, 352, 207, 611, 36, 158, 669, 158, 164, 506, 701, 481, 586, 316, 615

Wähle ich immer das erste so habe ich 787, 960 usw.
bei Zahlen zwischen 0 und 1000 hätte ich am liebsten immer die 500, richtig?

Also wähle ich jetzt drei Random und nehme das mittlere, dann komme ich der 500 doch immer näher, als wenn ich immer nur das erste nehmen würde

Random: 740, 207 und 669 -> 669

So meine Logik, leider klappt es nicht im Programm. Ich hätte zumindest beim bei der Random-Variante eine kleine Verbesserung, also weniger Vergleiche, erwartet. Aber egal ob ich 1000 oder 1000000 Zahlen sortieren lasse. Die Vergleiche sind immer nahezu identisch, da kann doch etwas nicht stimmen!?

LG
Deggit
 

JStein52

Top Contributor
Wie das angehängte Projekt enthält den QuickSort nicht.
Das ist die Klasse Sortieren aus deinem Anhang.
Code:
/**
* Beschreiben Sie hier die Klasse Sortieren.
*
* @author (Ihr Name)
* @version (eine Versionsnummer oder ein Datum)
*/
public class Sortieren
{
    private List<Integer> liste;

    /**
     * Konstruktor für Objekte der Klasse Sortieren
     */
    public Sortieren()
    {
        System.out.print('\u000C'); // Konsole leeren.
        listeErstellen();
        listeAusgeben();
        System.out.println("insertionSort() ausführen.");
        insertionSort();
        listeAusgeben();

        listeErstellen();
        System.out.println("selectionSort() ausführen.");
        selectionSort();
        listeAusgeben();
    }
   
    /**
     * Die Methode selectionSort() realisiert das
     * Sortieren durch Auswaehlen.
     *
     */
    public void selectionSort()
    {
        List<Integer> sortierteListe = new List<Integer>();
        liste.toFirst();
        while (!liste.isEmpty())
        {          
            int hilf = liste.getContent();
            liste.next();

            while (liste.hasAccess())
            {
                if (liste.getContent() < hilf)
                {
                    hilf = liste.getContent();

                }               
                liste.next();
            }
            loescheElement(hilf);
            sortierteListe.append(hilf);
        }

        liste = sortierteListe;
    }

    /**
     * Die Methode loescht ein Elemente mit dem Wert
     * der als Parameter angegebenen Variablen aus der Originalliste.
     *
     * @param pWert der Wert des zu loeschenden Elementes
     */
    public void loescheElement(int pWert)
    {
        liste.toFirst();
        while (liste.hasAccess() && liste.getContent() != pWert)
        {              
            liste.next();
        }
        if (liste.getContent() == pWert) liste.remove();
        liste.toFirst();
    }

    /**
     * Die Methode insertionSort() realisiert das
     * Sortieren durch Einfuegen.
     *
     */
    public void insertionSort()
    {
        List<Integer> sortierteListe = new List<Integer>();
        while (!liste.isEmpty())
        {
            liste.toFirst();
            int aktuelles = liste.getContent();
            sortierteListe.toFirst();
            while (sortierteListe.hasAccess() && sortierteListe.getContent() < aktuelles)
            {
                sortierteListe.next();
            }
            if (sortierteListe.hasAccess())
            {
                sortierteListe.insert(aktuelles);
            }
            else {
                sortierteListe.append(aktuelles);
            }
            liste.remove();
        }
        liste = sortierteListe;
    }
    /**
     * Die Methode listeErstellen() erzeugt die
     * Originalliste mit vorgegebenen Integer-Werten.
     *
     */
    public void listeErstellen()
    {
        liste = new List<Integer>();
        liste.append(7);
        liste.append(13);
        liste.append(2);
        liste.append(36);
        liste.append(203);
        liste.append(8);
        liste.append(12);
    }
    /**
     * Die Methode listeAusgeben() gibt die Integer-Werte
     * der Originalliste aus.
     *
     */
    public void listeAusgeben()
    {
        liste.toFirst();
        System.out.println("Listenelemente:");
        while (liste.hasAccess())
        {
            System.out.print(liste.getContent().intValue());
            liste.next();
            if (liste.hasAccess()) System.out.print(", ");
        }
        System.out.println("");
    }
}
und ansonsten ist nur noch eine Klasse List enthalten.
 

deggit_biber

Aktives Mitglied
ohhh du hast recht!!! Ich Programmiere immer auf alten Dateien und auf den ersten Blick sah es nach der richtigen Datei aus. Entschuldige bitte! Ich bin ja total dankbar, dass überhaupt jemand einmal drüber schaut.
 

Anhänge

  • 120_Aufgabe1c_QuickSortPivot_Loesung.zip
    23,3 KB · Aufrufe: 1

JCODA

Top Contributor
Also, als ich die Element-Größe auf bis zu 10000000 und die arrayGröße auf 1000000 und noch ne kleine änderung am Pivot gemacht hab' erhalte ich immer bessere Werte für das Mittlere aus Drei. Siehe folgenden Code. (Ich hab leider einige Änderungen gemacht u.a. Kommentare raus - sorry ... )

Java:
import java.util.Random;


public class QuickSortPivot {
    //int n;
    int vergleicheLinks = 0, vergleicheMitte = 0, vergleicheRandom = 0;

    private int[] arr1;
    private int[] arr2;
    private int[] arr3;

    private Random rnd = new Random();
   
    public static void main(String args[]) {
        new QuickSortPivot(1000000);
    }

    public QuickSortPivot(int pElemente) {
        System.out.print('\u000C'); // Konsole leeren.
        arr1 = new int[pElemente];
        arr2 = new int[pElemente];
        arr3 = new int[pElemente];

        arrayFuellen();
        System.out.println("");

        quicksortLinks(arr1, 0, arr1.length - 1);
        System.out.println("Pivot-Element Links");
        arrayAusgeben(arr1,vergleicheLinks);
        System.out.println("");


        quicksortMitte(arr2, 0, arr2.length - 1);
        System.out.println("Pivot-Element Mitte");
        arrayAusgeben(arr2,vergleicheMitte);
        System.out.println("");


        quicksortRandom(arr3, 0, arr3.length - 1);
        System.out.println("Pivot-Element Random");
        arrayAusgeben(arr3,vergleicheRandom);
        System.out.println("");

    }

    public void arrayFuellen() {
        for (int i = 0; i < arr1.length ; i++) {
            arr1[i] = rnd.nextInt(10000000);                                        
            arr2[i] = arr1[i];
            arr3[i] = arr1[i];
        }
    }

   
    void quicksortLinks(int arr[], int left, int right) {
        int index = partition(arr, left, right);
        if (left < index - 1)
            quicksortLinks(arr, left, index - 1);
        if (index < right)
            quicksortLinks(arr, index, right);
    }

    int partition(int arr[], int left, int right) {
        int i = left, j = right;
        int tmp;
        int pivot = arr[left];

        while (i <= j) {
            vergleicheLinks++;
            while (arr[i] < pivot)
                i++;
            while (arr[j] > pivot)
                j--;

            if (i <= j) {

                tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
                i++;
                j--;
            }
        }
        return i;
    }

    void quicksortMitte(int arr[], int left, int right) {
        int index = partition2(arr, left, right);
        if (left < index - 1)
            quicksortMitte(arr, left, index - 1);
        if (index < right)
            quicksortMitte(arr, index, right);
    }

    int partition2(int arr[], int left, int right) {
        int i = left, j = right;
        int tmp;
        int pivot = arr[(left + right) / 2];

        while (i <= j) {
            vergleicheMitte++;
            while (arr[i] < pivot)
                i++;
            while (arr[j] > pivot)
                j--;

            if (i <= j) {

                tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
                i++;
                j--;
            }
        }
        return i;
    }

    void quicksortRandom(int arr[], int left, int right) {
        int index = partition3(arr, left, right);
        if (left < index - 1)
            quicksortRandom(arr, left, index - 1);
        if (index < right)
            quicksortRandom(arr, index, right);
    }

    int partition3(int arr[], int left, int right) {
        //System.out.println(left+" "+right);
        int i = left, j = right;
        int tmp;

        // Vergleichselement pivot
        int p1 = 0, p2 = 0, p3 = 0;
        int pivot = 0;

       

        if (right-left < 2) {
            pivot = arr[left];
        }else {
            int range = right - left + 1;
            p1 = arr[left + rnd.nextInt(range)];
            p2 = arr[left + rnd.nextInt(range)];
            p3 = arr[left + rnd.nextInt(range)];

            pivot = getMiddle(p1, p2, p3);
            //System.out.println(left + " "+ right);
            //System.out.println(p1+" "+p2+" "+p3+" "+pivot);
        }

        while (i <= j) {

            while (arr[i] < pivot)
                i++;
            while (arr[j] > pivot)
                j--;

            if (i <= j) {
                vergleicheRandom++;
                tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
                i++;
                j--;
            }
        }
        return i;
    }

    private int getMiddle(int p1, int p2, int p3) {
        int pivot = p1;
        if (p1 < p2 && p3 > p2 || p1 > p2 && p3 < p2) {
            pivot = p2;
        }else if (p1 < p3 && p2 > p3 || p1 > p3 && p2 < p3) {
            pivot = p3;
        }else if (p1 == p2){
            pivot = p1;
        }else if(p2 == p3 || p1 == p3) {
            pivot = p3;
        }
        return pivot;
    }


    public void arrayAusgeben(int arr[],int vergleiche) {
        for (int i = 0; i <= arr.length - 1; i++) {
            // System.out.print(arr[i] + ", ");
        }
        System.out.println("");
        System.out.print("Anzahl der Vergleiche: " + vergleiche);
        System.out.println("");
    }


}
 

deggit_biber

Aktives Mitglied
Toll!!! Lag es dann wohl hauptsächlich an den falschen Start setting?

Eine Kleinigkeit ist mir noch aufgefallen. Beim RandomQuickSort ist der Vergleichszähler in der If-Anweisung. soll das so sein? Bei den anderen beiden ist er in der while-schleife.

vielen lieben Dank,
für deine Mühe

PS: Packe ich den Zähler auch in die while-Schleife, schneidet der Random wieder viel schlechter ab. Eigentlich müssten die Zählen doch bei allen drei Algorithmen an der gleichen Stellen sein, oder?
 

JCODA

Top Contributor
Eine Kleinigkeit ist mir noch aufgefallen. Beim RandomQuickSort ist der Vergleichszähler in der If-Anweisung. soll das so sein? Bei den anderen beiden ist er in der while-schleife.
PS: Packe ich den Zähler auch in die while-Schleife, schneidet der Random wieder viel schlechter ab. Eigentlich müssten die Zählen doch bei allen drei Algorithmen an der gleichen Stellen sein, oder?
Ooops. hehe tut mir leid, da ist was schief gelaufen. Ich steh gerade aufm Schlauch ...
 

deggit_biber

Aktives Mitglied
Also der Ort muss überall gleich sein, denke da sind wir uns einig ;-)
Ich würde den Zähler auch in die While-Schleife packen, da ja i mit j verglichen wird und erst wenn er ein i findet, das >= pivot ist und ein j, das <= pivot ist tauscht er.

Leider sind dann die Anzahl der Vertauschungen beim Random wieder am schlechtesten und von der Logik müssten sie doch am besten sein ;-)

Ich raff das net...
 

JCODA

Top Contributor
Okay, wenn ich folgendes tue: Also Alle Element-Vergleiche zähle, in denen "arr" vorkommt (d.h. innerhalb der beiden while und zwei zusätzlich, da die while-vergleiche ja einmal mehr ausgeführt werden) dann siehts ganz gut aus:
Java:
import java.util.Random;


public class QuickSortPivot {
    //int n;
    int vergleicheLinks = 0, vergleicheMitte = 0, vergleicheRandom = 0;

    private int[] arr1;
    private int[] arr2;
    private int[] arr3;

    private Random rnd = new Random();
   
    public static void main(String args[]) {
        new QuickSortPivot(1000000);
    }

    public QuickSortPivot(int pElemente) {
        System.out.print('\u000C'); // Konsole leeren.
        arr1 = new int[pElemente];
        arr2 = new int[pElemente];
        arr3 = new int[pElemente];

        arrayFuellen();
        System.out.println("");

        quicksortLinks(arr1, 0, arr1.length - 1);
        System.out.println("Pivot-Element Links");
        arrayAusgeben(arr1,vergleicheLinks);
        System.out.println("");


        quicksortMitte(arr2, 0, arr2.length - 1);
        System.out.println("Pivot-Element Mitte");
        arrayAusgeben(arr2,vergleicheMitte);
        System.out.println("");


        quicksortRandom(arr3, 0, arr3.length - 1);
        System.out.println("Pivot-Element Random");
        arrayAusgeben(arr3,vergleicheRandom);
        System.out.println("");

    }

    public void arrayFuellen() {
        for (int i = 0; i < arr1.length ; i++) {
            arr1[i] = rnd.nextInt(10000000);                                        
            arr2[i] = arr1[i];
            arr3[i] = arr1[i];
        }
    }

   
    void quicksortLinks(int arr[], int left, int right) {
        int index = partition(arr, left, right);
        if (left < index - 1)
            quicksortLinks(arr, left, index - 1);
        if (index < right)
            quicksortLinks(arr, index, right);
    }

    int partition(int arr[], int left, int right) {
        int i = left, j = right;
        int tmp;
        int pivot = arr[left];

        while (i <= j) {
            vergleicheLinks+=2;
            while (arr[i] < pivot){
                vergleicheLinks++;
                i++;
            }
            while (arr[j] > pivot){
                vergleicheLinks++;
                j--;
            }
               

            if (i <= j) {

                tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
                i++;
                j--;
            }
        }
        return i;
    }

    void quicksortMitte(int arr[], int left, int right) {
        int index = partition2(arr, left, right);
        if (left < index - 1)
            quicksortMitte(arr, left, index - 1);
        if (index < right)
            quicksortMitte(arr, index, right);
    }

    int partition2(int arr[], int left, int right) {
        int i = left, j = right;
        int tmp;
        int pivot = arr[(left + right) / 2];

        while (i <= j) {
            vergleicheMitte+=2;
            while (arr[i] < pivot){
                i++;
                vergleicheMitte++;
            }
            while (arr[j] > pivot){
                vergleicheMitte++;
                j--;
            }
               

            if (i <= j) {

                tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
                i++;
                j--;
            }
        }
        return i;
    }

    void quicksortRandom(int arr[], int left, int right) {
        int index = partition3(arr, left, right);
        if (left < index - 1)
            quicksortRandom(arr, left, index - 1);
        if (index < right)
            quicksortRandom(arr, index, right);
    }

    int partition3(int arr[], int left, int right) {
        int i = left, j = right;
        int tmp;

        int p1 = 0, p2 = 0, p3 = 0;
        int pivot = 0;
        if (right-left < 2) {
            pivot = arr[left];
        }else {
            int range = right - left + 1;
            p1 = arr[left + rnd.nextInt(range)];
            p2 = arr[left + rnd.nextInt(range)];
            p3 = arr[left + rnd.nextInt(range)];

            pivot = getMiddle(p1, p2, p3);
        }

        while (i <= j) {
            vergleicheRandom+=2;
            while (arr[i] < pivot){
                i++;
                vergleicheRandom++;
            }
               
            while (arr[j] > pivot){
                j--;
                vergleicheRandom++;
            }
               

            if (i <= j) {               
                tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
                i++;
                j--;
            }
        }
        return i;
    }

    private int getMiddle(int p1, int p2, int p3) {
        int pivot = p1;
        if (p1 < p2 && p3 > p2 || p1 > p2 && p3 < p2) {
            pivot = p2;
        }else if (p1 < p3 && p2 > p3 || p1 > p3 && p2 < p3) {
            pivot = p3;
        }else if (p1 == p2){
            pivot = p1;
        }else if(p2 == p3 || p1 == p3) {
            pivot = p3;
        }
        return pivot;
    }


    public void arrayAusgeben(int arr[],int vergleiche) {
        for (int i = 0; i <= arr.length - 1; i++) {
            // System.out.print(arr[i] + ", ");
        }
        System.out.println("");
        System.out.print("Anzahl der Vergleiche: " + vergleiche);
        System.out.println("");
    }


}
 

deggit_biber

Aktives Mitglied
ohhh ja das sieht schon recht gut aus.

Warum machst du dies?

vergleicheLinks+=2;

bin auch gerade mit der Notation nicht so vertraut. Setzt du hier VergleicheLinks auf 2?
 

JCODA

Top Contributor
das ist äquivalent zu vergleicheLinks=vergleicheLinks+2;
Also vergleicheLinks wird um 2 erhöht.
Und warum mache ich das: Bei einer while-Schleife wird ja immer ein Vergleich mehr ausgeführt, als die Schleife betreten wird, denn irgendwann ist ja die Bedingung falsch, aber der Vergleich wurde ja trotzdem durchgeführt.
 

deggit_biber

Aktives Mitglied
Ahhh das leuchtet ein.

Müsste ich das in der inneren while dann nicht auch machen?
Code:
            while (arr[i] < pivot)
            {
                vergleicheLinks++;
                i++;
            }
ändern in
Code:
            while (arr[i] < pivot)
            {
                vergleicheLinks+=2;
                i++;
            }

Also eigentlich in allen while-schleifen, oder?

Denke da gerade noch einmal drüber nach.
So ganz passt es mit dem
vergleicheLinks+=2;
aber nicht, glaube ich zumindest.
Wenn ich das so lassen, dann wird doch bei jedem Eintritt in die while-Schleife der Zähler um zwei erhöht. Aber eigentlich müsste er doch bei jedem Eintritt nur um eins erhöht werden und wenn er nicht rein kann, dann müsste er auch um eins erhöht werden.
Beispiel er kann 10 mal reingehen, dann wären 10+1 Vergleichen (+1, weil noch der letzte Vergleich hinzukommt, da wo er nicht reingehen konnte)

Bei vergleicheLinks+=2;
wären es aber 20 Vergleiche.

Habe ich da jetzt einen Denkfehler?
 
Zuletzt bearbeitet:

JStein52

Top Contributor
Ich habe auch mal ein bisschen rumprobiert. Die drei Verfahren sind bei der Anzahl Vergleiche und Anzahl Vertauschungen etwas unterschiedlich. Bei mir ergaben sich folgende Werte:
Code:
                   Vergleiche             Vertauschungen
Pivot-Left:        577000                  158900
Pivot-Mitte:       488000                  156300
Pivot-Random:      391000                  162400
 

deggit_biber

Aktives Mitglied
@JStein52: Vielen lieben Dank! Das deckt sich mit meinen Ergebnissen. Hätte trotzdem gedacht, dass die Auswirkungen größer wären. Ich denke richtig gute Implementierungen nutzen noch den ein oder anderen Trick ;-)

vielen lieben Dank an euch beide.
LG
Deggit
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
Zrebna Quicksort-Algorithmus - zufälliges Pivot wählen Allgemeine Java-Themen 6
L APACHE POI PIVOT TABELLEN Allgemeine Java-Themen 4
J JSP die richtige Wahl Allgemeine Java-Themen 2
S Wahl der Collection, unspezifizierte Elementtypen Allgemeine Java-Themen 4
L Die Wahl des richtigen Streams? Allgemeine Java-Themen 3
berserkerdq2 Weiß jemand wie ich im Scenebuilder das Fenster so darstellen kann, dass beim Vollbildmodus die Objekte so angezeigt werden? Allgemeine Java-Themen 1
C Probleme beim Erstellen eines runnable-jar files Allgemeine Java-Themen 1
B Mysteriöse Ergebnisse beim Baccarat Programm? Allgemeine Java-Themen 13
8u3631984 Problem beim Mocken von Record Klassen Allgemeine Java-Themen 4
A Zweite Service Klasse beim Kompilieren Allgemeine Java-Themen 6
B Java Reflection Probleme beim wehcselseitigen Referenzieren zweier Klassen/Objekte Allgemeine Java-Themen 14
B Stringmanipulationen beim Dateinamen Allgemeine Java-Themen 8
B Woher kommen die Bildschirmkoordinaten beim java Robot? Allgemeine Java-Themen 14
Alex_99 Programm stürzt beim Aufruf der Funktion ab? Text ausgeben Allgemeine Java-Themen 45
J Mein Frame friert ein beim Uploaden Allgemeine Java-Themen 4
P Selenium Scriipt zeigt Fehler beim Import Allgemeine Java-Themen 3
A Hilfe beim Verständnis Allgemeine Java-Themen 16
stormyark Problem beim Klassen erstellen Allgemeine Java-Themen 1
K Verbesserung der Laufzeit beim Sortieren von Einwohnern nach ihrem Geburtsjahr Allgemeine Java-Themen 0
B Compiler-Fehler Probleme beim Kompilieren mit Jsoup Allgemeine Java-Themen 8
G javamail Problem beim Empfangen von Nachrichten Allgemeine Java-Themen 3
yakazuqi Fehler beim Laden. JDA (Java Discord API) Allgemeine Java-Themen 1
T Problem beim Umwandeln in eine Jar-Datei Allgemeine Java-Themen 3
W Suche Ursache für NPE - woher kommt sie? (Hilfe beim Debugging) Allgemeine Java-Themen 19
U Fehler beim Compillieren Allgemeine Java-Themen 13
B neuroph hält beim XOR lernen nicht an Allgemeine Java-Themen 13
bueseb84 Fehler beim Import von Maven Dependencies aus lokalem artifactory Allgemeine Java-Themen 2
J Jasper Report - seltame Meldung beim compilieren Allgemeine Java-Themen 3
J Linux .jar beim Start automatisch ausführen Allgemeine Java-Themen 6
T String-Manipulation beim Ablauf in Eclipse und als JAR-File Allgemeine Java-Themen 8
V Threads Probleme beim Aufrufen von Methoden einer anderen Klasse (Threads) Allgemeine Java-Themen 14
M Gibt es eine API die den aktuellen Wert eines Indikators beim Trading zurückgibt? Allgemeine Java-Themen 7
A Fehler beim Öffnen eines Projekts Allgemeine Java-Themen 6
L Compiler-Fehler Generics beim Anhängen von Predicates Allgemeine Java-Themen 1
J WARNING: An illegal reflective access operation has occurred, beim Compilieren von JasperReports, was bedeutet das ? Allgemeine Java-Themen 23
J Problem beim Umstellen auf Java jdk 13 Allgemeine Java-Themen 3
A Problem beim öffnen von Java-Installern Allgemeine Java-Themen 1
J Problem beim Generischen Klassen und Interfaces Allgemeine Java-Themen 2
C Fehler beim Debuggen von Listen Allgemeine Java-Themen 4
L File beim Kopieren in einen anderen Ordner umbenennen Allgemeine Java-Themen 6
B Input/Output Probleme beim Ausführen von Shell-Befehlen mit Java Allgemeine Java-Themen 28
J Probleme beim einbinden von Zip4j library Allgemeine Java-Themen 6
T Compiler-Fehler NoClassDefFoundError beim Laden einer Class Allgemeine Java-Themen 11
S Seitenausrichtung beim Drucken Allgemeine Java-Themen 1
RalleYTN Brauche Hilfe beim Run-Length-Decoding Allgemeine Java-Themen 9
R Optimierung beim Vergleichen von 2 Bildern Allgemeine Java-Themen 23
F SQLite mit Java / Probleme beim INSERT Befehl Allgemeine Java-Themen 4
I Fehler beim Ant-Package erstellen mit Java 9 Allgemeine Java-Themen 1
S Eclipse Probleme beim Implementieren / Ausführen von jUnit 5-Test Suites Allgemeine Java-Themen 14
M Beim Öffnen Dialog Directory und Filetype definieren Allgemeine Java-Themen 2
G Problem beim GUI Allgemeine Java-Themen 9
A Probleme beim Verstehen einer Aufgabenstellung Allgemeine Java-Themen 11
A OOP Problem beim Berechnen der größten Fläche eines Ringes Allgemeine Java-Themen 19
F Problem beim Einlesen einer Textdatei Allgemeine Java-Themen 12
J Konstruktor in JSP beim Kompilieren nicht gefunden Allgemeine Java-Themen 3
perlenfischer1984 Probleme beim Mocken Allgemeine Java-Themen 6
A Fehler beim Aktualisieren JTable Allgemeine Java-Themen 1
J-Gallus Erste Schritte Wahrscheinlich Anfänger Fehler beim rechnen. Falsches Ergebnis. Allgemeine Java-Themen 9
U Swing Hilfe beim Quellcode für ein Codierungs-/Decodierungsprogramm Allgemeine Java-Themen 9
Fischkralle Beim Clean Coden an den Schnittstellen geschnitten. Allgemeine Java-Themen 10
H Beim Konstruktor "this" Allgemeine Java-Themen 4
I Problem beim Aufrufen, von Objektmethoden/ -variablen Allgemeine Java-Themen 6
J Interpreter-Fehler Fehler beim Verschlüsseln Invalid AES key length Allgemeine Java-Themen 1
R probleme beim starten von jar unter linux Allgemeine Java-Themen 2
Thallius Swing Merkwürdiges Verhalten beim Panel Tausch Allgemeine Java-Themen 3
Tacofan Sound beim öffnen der GUI Allgemeine Java-Themen 8
Z NullPointerException beim Schreiben einer ArrayList in eine Datei Allgemeine Java-Themen 6
B Endlosschleife beim Verteilen von Objekten Allgemeine Java-Themen 4
V JavaFX Fehler beim Starten einer Jar Allgemeine Java-Themen 7
B Fortschritt beim Schreiben einer Datei ausgeben lassen Allgemeine Java-Themen 7
J JDK installieren Das Jdk funtioniert beim Editor nicht. Allgemeine Java-Themen 3
R Verdrückt beim Sicherheitshinweis Allgemeine Java-Themen 2
M Probleme beim rechnen, bei Zahlen mit führenden Nullen. Allgemeine Java-Themen 7
javampir Input/Output Effizienz beim binären Lesen einer Datei Allgemeine Java-Themen 6
javampir Seltsame Lücken beim Abspielen von Sound Allgemeine Java-Themen 2
RalleYTN JAnsi Warum bleiben die Hintergrundfarben beim Reseten der Konsole? Allgemeine Java-Themen 0
T BufferedImage verändert sich beim Einlsesen Allgemeine Java-Themen 1
E JCuda-0.6.5 Probleme beim ausführen der Datei Allgemeine Java-Themen 0
S Verständnisproblem beim Mocking Allgemeine Java-Themen 8
W JNDI - LDAP - Probleme beim editieren von Usern Allgemeine Java-Themen 0
Athena Programm funktioniert nur beim Debugging korrekt, sonst nicht. Allgemeine Java-Themen 1
N Zahlensysteme umrechnen; Probleme beim Umwandeln Allgemeine Java-Themen 4
K Fehler beim erstellen von .jar Datei Allgemeine Java-Themen 3
M Eclipse Fehler beim Installieren des Plugins "Jigloo" Allgemeine Java-Themen 12
A Eclipse - Fehler beim "RUN" - "Unable to Launch - The selection cannot be launched" Allgemeine Java-Themen 6
G StackoverflowError beim laden einer FXMML Datei Allgemeine Java-Themen 1
L Methoden Methode gibt mir beim verschlüsseln mit RSA 0 bytes aus ? Allgemeine Java-Themen 1
D Selenium WebDriver HtmlUnitDriver Problem beim Automatisieren Allgemeine Java-Themen 1
A Probleme beim auslesen von Quelltext (HTML) Allgemeine Java-Themen 5
D Input/Output Zeilen werden "ignoriert" beim Einlesen aus einer Textdatei Allgemeine Java-Themen 3
L Suchvorschläge beim eingeben einzelner Buchstaben Allgemeine Java-Themen 3
B Compiler-Fehler NullPointerException beim Auslesen von .lang-Datei Allgemeine Java-Themen 3
U Eclipse Java Programm beschädigt .tar.gz dateien beim Entpacken Allgemeine Java-Themen 7
B Fehler beim Auslesen von Einstellungen. Zwei ähnliche Blöcke, nur eins geht. Allgemeine Java-Themen 5
P Auf die Anzahl der Joins achten beim WS design Allgemeine Java-Themen 1
reibi Classpath Classpath Variable beim Tomcat Allgemeine Java-Themen 2
H JUnit Fehler beim Compilieren - erledigt Allgemeine Java-Themen 0
J Fehler beim parsens eine Datums Allgemeine Java-Themen 3
A Java - Beim Abspeichern Redundanzen vermeiden! Allgemeine Java-Themen 6
L einfache Verzinsung mit for-Schleife & Ausschluss von Werten beim Einlesen Allgemeine Java-Themen 5

Ähnliche Java Themen

Neue Themen


Oben