{"id":4049,"date":"2024-09-19T13:09:57","date_gmt":"2024-09-19T11:09:57","guid":{"rendered":"https:\/\/www.capri-soft.de\/blog\/?p=4049"},"modified":"2024-09-19T13:11:19","modified_gmt":"2024-09-19T11:11:19","slug":"algorithmen-und-datenstrukturen-der-single-pivot-quicksort-in-java","status":"publish","type":"post","link":"https:\/\/www.capri-soft.de\/blog\/?p=4049","title":{"rendered":"Algorithmen und Datenstrukturen: Der &#8222;Randomized Single-Pivot QuickSort&#8220; in Java"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Der Algorithmus<\/h2>\n\n\n\n<p>Der QuickSort-Algorithmus ist ein rekursiver Sortieralgorithmus nach dem Teile- und Herrsche-Prinzip. Er ruft sich so lange selber auf, bis alle Array-Elemente auf der linken und rechten Stack-Seite eines Pivot-Elements sortiert sind. Zun\u00e4chst wird die zu sortierende Liste in zwei Teillisten (\u201elinke\u201c und \u201erechte\u201c Teilliste) getrennt. Dazu w\u00e4hlt Quicksort ein sogenanntes&nbsp;Pivotelement&nbsp;aus der Liste aus. Alle Elemente, die kleiner als das Pivotelement sind, kommen in die linke Teilliste, und alle, die gr\u00f6\u00dfer sind, in die rechte Teilliste. Die Elemente, die gleich dem Pivotelement sind, k\u00f6nnen sich beliebig auf die Teillisten verteilen. Nach der Aufteilung sind die Elemente der linken Liste kleiner oder gleich den Elementen der rechten Liste.<\/p>\n\n\n\n<p>Anschlie\u00dfend muss man also noch jede Teilliste in sich sortieren, um die Sortierung zu vollenden. Dazu wird der Quicksort-Algorithmus jeweils auf der linken und auf der rechten Teilliste ausgef\u00fchrt. Jede Teilliste wird dann wieder in zwei Teillisten aufgeteilt und auf diese jeweils wieder der Quicksort-Algorithmus angewandt, und so weiter. Diese Selbstaufrufe werden als&nbsp;Rekursion&nbsp;bezeichnet. Wenn eine Teilliste der L\u00e4nge eins oder null auftritt, so ist diese bereits sortiert und es erfolgt der&nbsp;Abbruch der Rekusion.<\/p>\n\n\n\n<p>Der Prinzip:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Auswahl eine zuf\u00e4lligen Pivot-Elements (muss nicht das kleinste Element im Array sein)<\/li>\n\n\n\n<li>Sortierung aller kleineren Zahlen als das Pivot-Element auf die linke Seite des Stapels\/Stacks<\/li>\n\n\n\n<li>Sortierung aller gr\u00f6\u00dferen Zahlen als das Pivot-Element auf die rechte Seite des Stapels\/Stacks<\/li>\n\n\n\n<li>Rekursiver Aufruf f\u00fcr die linke Seite des Stapels\/Stacks bis sich die zwei Left- und Right-Pointer \u00fcberschneiden, weil keine kleinere Zahl mehr gefunden wurde, die links vom Pivot-Element einsortiert werden kann.<\/li>\n\n\n\n<li>Rekursiver Aufruf f\u00fcr die rechte Seite des Stapels\/Stacks bis sich die zwei Left- und Right-Pointer \u00fcberschneiden, weil keine gr\u00f6\u00dfere Zahl mehr gefunden wurde, die rechts vom Pivot-Element einsortiert werden kann.<\/li>\n<\/ol>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage AlgoDat;\n \npublic class QuickSort {\n    \/\/ Zu sortierendes Array\n    private int myArray&#x5B;] = {22, 6, 2, 4, 10, 3, 9, 7, 5, 8, 1};\n \n    \/\/ H\u00e4lt die Klasse als instanziertes Objekt\n    @SuppressWarnings(&quot;unused&quot;)\n    private static QuickSort program;\n    private java.util.Random rnd = new java.util.Random();\n \n    \/\/ Hilfsfunktion f\u00fcr das Ausgeben des Arrays\n    public void OutputOfIntArray(int myArray&#x5B;])\n    {\n        if (myArray != null)\n        {\n            for (int i = 0; i &lt; myArray.length; i++) {\n                if (i &gt; 0) System.out.print(&quot;;&quot;);\n                System.out.print(myArray&#x5B;i]);\n            }\n \n            System.out.println();\n        }\n    }\n \n    \/\/ Generiert ein zuf\u00e4lliges Integer-Array der Gr\u00f6\u00dfe size mit Werten zwischen 0 und upperLimit\n    public int&#x5B;] generateIntegerArrayOfSize(int size, int upperLimit)\n    {       \n        int&#x5B;] generatedArray = new int&#x5B;size];\n         \n        for (int i = 0; i &lt; generatedArray.length; i++)\n        {\n            generatedArray&#x5B;i] = rnd.nextInt(upperLimit);\n        }\n \n        return generatedArray;\n    }\n \n    public void makeQuickSort(int&#x5B;] arrayToSort, int fromIndex, int toIndex)\n    {\n        \/\/ Rekursionsabbruch\n        if (fromIndex &gt;= toIndex)\n        {\n            return;\n        }\n \n        \/\/ Das Pivot-Element muss beim Teile-Herrsche-Prinzip nicht die kleinste Zahl im Array sein \n        \/\/ und kann willk\u00fcrlich gew\u00e4hlt werden - wie hier das letzte Element des Array\n        int pivot = arrayToSort&#x5B;toIndex];\n        \/\/ Im Average Case performt der Quicksort aber besser, wenn es zuf\u00e4llig ausgew\u00e4hlt wird\n        \/\/ int pivotIndex = rnd.nextInt(toIndex - fromIndex) + fromIndex;\n        \/\/ int pivot = arrayToSort&#x5B;pivotIndex];\n \n        \/\/ Diese Pointer beinhalten den Index der Elemente, die miteinander verglichen und ggfs. vertauscht werden, wenn sie kleiner\/gr\u00f6\u00dfer als das Pivot sind.\n        int leftPointer = fromIndex;\n        int rightPointer = toIndex;\n \n        \/\/ Partitioniere, so lange wie sich die Pointer nicht in die Quere kommen\n        while (leftPointer &lt; rightPointer)\n        {\n            \/\/ Verschiebe leftPointer so lange, bis ein Element gefunden wird, was gr\u00f6\u00dfer als das Pivot ist\n            \/\/ (oder wie sich die Pointer nicht \u00fcberschneiden)\n            while (arrayToSort&#x5B;leftPointer] &lt;= pivot &amp;&amp; leftPointer &lt; rightPointer)\n            {\n                leftPointer++;\n            }\n \n            \/\/ Verschiebe rightPointer so lange, bis ein Element gefunden wird, was gr\u00f6\u00dfer als das Pivot ist\n            \/\/ (oder wie sich die Pointer nicht \u00fcberschneiden)\n            while (arrayToSort&#x5B;rightPointer] &gt;= pivot &amp;&amp; leftPointer &lt; rightPointer)\n            {\n                rightPointer--;\n            }\n \n            \/\/ Vertausche die Elemente am Index von leftPointer und rightPointer\n            int swapVar = arrayToSort&#x5B;leftPointer];\n            arrayToSort&#x5B;leftPointer] = arrayToSort&#x5B;rightPointer];\n            arrayToSort&#x5B;rightPointer] = swapVar;\n        }\n \n        \/\/ Vertausche die Elemente am Array-Index von leftPointer und toIndex\n        int swapVar = arrayToSort&#x5B;leftPointer];\n        arrayToSort&#x5B;leftPointer] = arrayToSort&#x5B;toIndex];\n        arrayToSort&#x5B;toIndex] = swapVar;\n \n        \/\/ QuickSort f\u00fcr die linke Seite vom Pivot-Element\n        this.makeQuickSort(arrayToSort, fromIndex, leftPointer - 1);\n \n        \/\/ QuickSort f\u00fcr die rechte Seite vom Pivot-Element\n        this.makeQuickSort(arrayToSort, leftPointer + 1, toIndex);\n    }\n \n    \/\/ Konstruktor\n    public QuickSort()\n    {\n        System.out.print(&quot;Vorher: &quot;);\n        this.OutputOfIntArray(myArray);\n \n        long startZeit = System.nanoTime();\n \n        \/\/ this.OutputOfIntArray(this.generateIntegerArrayOfSize(1000, 100));\n        this.makeQuickSort(myArray, 0, myArray.length - 1);\n \n        long endZeit = System.nanoTime();\n \n        System.out.print(&quot;Nachher: &quot;);\n        this.OutputOfIntArray(myArray);\n \n        System.out.println(&quot;Ich habe &quot; + (endZeit - startZeit) + &quot; ns gebraucht.&quot;);\n    }\n \n    public static void main(String&#x5B;] args) \n    {\n        \/\/ Instanziere aus den statischem Programm ein echtes Objekt\n        \/\/ damit nicht alle Methoden und Variablen static sein m\u00fcssen.\n        program = new QuickSort();\n    }\n}\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\">Ausgabe<\/h2>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nVorher: 22;6;2;4;10;3;9;7;5;8;1\nNachher: 1;2;3;4;5;6;7;8;9;10;22\nIch habe 7200 ns gebraucht.\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\">Komplexit\u00e4t: O-Notation (Ordnung)<\/h2>\n\n\n\n<p>Der Quick-Sort hat im Average-Case die Komplexit\u00e4t\u00a0<strong>O(n* log(n))<\/strong>\u00a0und im Worst-Case die Komplexit\u00e4t\u00a0<strong>O(n\u00b2)<\/strong>.<\/p>\n\n\n\n<p><\/p>\n<iframe src=\"http:\/\/www.facebook.com\/plugins\/like.php?href=https%3A%2F%2Fwww.capri-soft.de%2Fblog%2F%3Fp%3D4049&amp;layout=standard&amp;show_faces=true&amp;width=450&amp;action=like&amp;colorscheme=light\" scrolling=\"no\" frameborder=\"0\" allowTransparency=\"true\" style=\"border:none; overflow:hidden; width:450px;margin-top:5px;\"><\/iframe>","protected":false},"excerpt":{"rendered":"<p>Der Algorithmus Der QuickSort-Algorithmus ist ein rekursiver Sortieralgorithmus nach dem Teile- und Herrsche-Prinzip. Er ruft sich so lange selber auf, bis alle Array-Elemente auf der linken und rechten Stack-Seite eines Pivot-Elements sortiert sind. Zun\u00e4chst wird die zu sortierende Liste in zwei Teillisten (\u201elinke\u201c und \u201erechte\u201c Teilliste) getrennt. Dazu w\u00e4hlt Quicksort ein sogenanntes&nbsp;Pivotelement&nbsp;aus der Liste aus. &hellip; <a href=\"https:\/\/www.capri-soft.de\/blog\/?p=4049\" class=\"more-link\"><span class=\"screen-reader-text\">Algorithmen und Datenstrukturen: Der &#8222;Randomized Single-Pivot QuickSort&#8220; in Java<\/span> weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[475,15,3],"tags":[454,457,488,489,490,473,491,461,492],"class_list":["post-4049","post","type-post","status-publish","format-standard","hentry","category-algorithmen-und-datenstrukturen","category-java","category-programmierung","tag-algodat","tag-java","tag-quick-sort","tag-quicksort","tag-quicksort-in-java","tag-rekursiv","tag-single-pivot","tag-sortieralgorithmus","tag-sortierverfahren"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p4yGeN-13j","jetpack_likes_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/posts\/4049","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4049"}],"version-history":[{"count":2,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/posts\/4049\/revisions"}],"predecessor-version":[{"id":4051,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/posts\/4049\/revisions\/4051"}],"wp:attachment":[{"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4049"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4049"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4049"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}