<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Annotations]]></title><description><![CDATA[B.Tech IT undergraduate learning Java, Spring Boot, and backend development. I write about algorithms, systems, and the ideas behind how software works.]]></description><link>https://pratishtha1452.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>Annotations</title><link>https://pratishtha1452.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Wed, 16 Sep 2026 05:43:38 GMT</lastBuildDate><atom:link href="https://pratishtha1452.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Quick Sort Through Lomuto and Hoare Partitioning]]></title><description><![CDATA[Most people learn Quick Sort with a single-partition algorithm and assume that's how it works. It doesn't.
Quick Sort's behaviour depends heavily on how you partition the array, and the two most commo]]></description><link>https://pratishtha1452.hashnode.dev/quick-sort-through-lomuto-and-hoare-partitioning</link><guid isPermaLink="true">https://pratishtha1452.hashnode.dev/quick-sort-through-lomuto-and-hoare-partitioning</guid><category><![CDATA[Quick Sort]]></category><category><![CDATA[sorting]]></category><category><![CDATA[DSA]]></category><category><![CDATA[algorithms]]></category><dc:creator><![CDATA[Pratishtha Deshpande]]></dc:creator><pubDate>Tue, 01 Sep 2026 14:42:32 GMT</pubDate><content:encoded><![CDATA[<p>Most people learn Quick Sort with a single-partition algorithm and assume that's how it works. It doesn't.</p>
<p><strong>Quick Sort's behaviour depends heavily on how you partition the array</strong>, and the two most common approaches—<strong>Lomuto and Hoare</strong>—move elements around in surprisingly different ways.</p>
<p>In this article, we'll understand both schemes visually, implement them in Java, and compare them.</p>
<h3>Understanding Quick Sort</h3>
<p>Quick Sort is a divide-and-conquer sorting algorithm. Instead of sorting the entire array at once, it repeatedly picks a pivot, partitions the array around that pivot, and recursively sorts the resulting subarrays. For this reason, it is sometimes called <strong>partition-exchange sort</strong>.</p>
<p>The algorithm follows three simple steps:</p>
<ol>
<li><p>Choose a pivot element.</p>
</li>
<li><p>Partition the array so that smaller elements move to one side and larger elements move to the other.</p>
</li>
<li><p>Repeat the process on both partitions until each subarray contains one or zero elements.</p>
</li>
</ol>
<p>Initially, this seems straightforward. However, the most important part of Quick Sort is how the partitioning is performed. After partitioning, every element smaller than the pivot will appear on its left, while larger elements will appear on its right. The exact arrangement depends on the partitioning strategy used.</p>
<h3>Partitioning</h3>
<p>Partitioning is the crucial step in Quick Sort. Instead of sorting the entire array in one pass, Quick Sort first rearranges the elements around a pivot. After partitioning, every element smaller than the pivot ends up on one side, while every larger element ends up on the other.</p>
<p>The exact order of elements within each side doesn't matter yet. The goal is only to split the array into two smaller problems that can be solved recursively.</p>
<p>Take this array, for example :</p>
<p><code>[8, 3, 1, 7, 0, 10, 2, 5]</code> Let the Pivot be 5.</p>
<p><strong>Before Partitioning -&gt;</strong></p>
<img src="https://cdn.hashnode.com/uploads/covers/6a9454963cf48ec0a4827072/9fa5d83f-ff2f-4f1d-99c0-bcf044de2294.svg" alt="" style="display:block;margin:0 auto" />

<p><strong>After Partitioning -&gt;</strong></p>
<p>The array might look like this. Notice that all the elements on the left of the pivot are less than it, while the elements on the right of the pivot are greater than it.</p>
<p><code>[3, 1, 0, 2, 5, 10, 7, 8]</code></p>
<img src="https://cdn.hashnode.com/uploads/covers/6a9454963cf48ec0a4827072/e925d56b-2896-4551-8809-313351fa49e9.svg" alt="" style="display:block;margin:0 auto" />

<p>Now, how do we move the elements around the pivot? The answer depends on the partitioning strategy. As said earlier, there are two partitioning schemes: Lomuto and Hoare. Lomuto uses a growing boundary with a single scanning pointer, while Hoare uses two pointers moving toward each other.</p>
<hr />
<h3>Lomuto Partitioning Scheme</h3>
<p>The Lomuto Partition Scheme approaches partitioning by maintaining a growing boundary of elements that belong before the pivot. As it scans the array from left to right, every element smaller than or equal to the pivot is moved into this growing region.</p>
<p>Lomuto uses <strong>one scanning pointer (</strong><code>j</code><strong>) and one boundary pointer (</strong><code>i</code><strong>)</strong>.</p>
<p>For this walkthrough, we'll use the same array introduced earlier.</p>
<p><code>[8, 3, 1, 7, 0, 10, 2, 5]</code> Pivot = 5 (last element)</p>
<p>Before the algorithm begins, each pointer has a specific responsibility.</p>
<ul>
<li><p><code>i</code> marks the boundary of elements that are already smaller than or equal to the pivot.</p>
</li>
<li><p><code>j</code> Scans the array from left to right, examining one element at a time.</p>
</li>
</ul>
<p>Initially,</p>
<ul>
<li><p><code>i = low - 1</code></p>
</li>
<li><p><code>j = low</code></p>
</li>
</ul>
<p>Initially, i = -1, and j is at low. We have marked the low and high pointers as 0 and the last index(n - 1), respectively, where n is the length of the array.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a9454963cf48ec0a4827072/e90b8384-3a49-4940-b3ca-2e5dd9a8ac4e.svg" alt="" style="display:block;margin:0 auto" />

<ul>
<li><p>The blue arrow (<code>i</code>) sits before the array because no elements have been placed into the "smaller" region yet.</p>
</li>
<li><p>The orange arrow (<code>j</code>) begins scanning from the first element.</p>
</li>
</ul>
<p><strong>Step-By-Step Execution:</strong></p>
<ol>
<li><p><code>[8, 3, 1, 7, 0, 10, 2, 5]</code> <code>i = -1</code>, <code>j = 0</code> -&gt; element at j = 8; 8 is greater than pivot (8 &gt; 5), so nothing changes. Move j.</p>
</li>
<li><p><code>[8, 3, 1, 7, 0, 10, 2, 5]</code> <code>i = -1</code>, <code>j = 1</code> -&gt; element at j = 3 -&gt; 3 is smaller than pivot (3 &lt; 5), so -&gt; <code>i++</code> and swap <code>a[i] and a[j]</code>.</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/6a9454963cf48ec0a4827072/1cee7f72-8f31-4971-a902-5ff592f71a2f.svg" alt="" style="display:block;margin:0 auto" />

<ol>
<li>Continue scanning and swapping. The algorithm uses the same rule.</li>
</ol>
<ul>
<li><p>j= 2 -&gt; 1 -&gt; swap</p>
</li>
<li><p>j= 3 -&gt; 7 -&gt; skip</p>
</li>
<li><p>j= 4 -&gt; 0 -&gt; swap</p>
</li>
<li><p>j= 5 -&gt; 10 -&gt; skip</p>
</li>
<li><p>j= 6 -&gt; 2 -&gt; swap</p>
</li>
</ul>
<p>After <code>j</code> finishes scanning the array, all smaller elements have already been grouped.</p>
<p>The only remaining step is placing the pivot between the two regions.</p>
<p>Before the final swap:</p>
<p><code>[3, 1, 0, 2, 8, 10, 7, 5]</code></p>
<p>Swap <code>arr[i + 1]</code> with the pivot.</p>
<p><strong>Final result:</strong></p>
<p><code>[3, 1, 0, 2, 5, 10, 7, 8]</code></p>
<img src="https://cdn.hashnode.com/uploads/covers/6a9454963cf48ec0a4827072/e8022d48-f1f5-48c5-9b38-d14a517e98d4.svg" alt="" style="display:block;margin:0 auto" />

<p><strong>Java Implementation</strong></p>
<pre><code class="language-java">static int lomutoPartition(int[] arr, int low, int high) {
    int pivot = arr[high]; int i = low - 1;

    for (int j = low; j &lt; high; j++) {
        if (arr[j] &lt;= pivot) {
            i++;
            swap(arr, i, j);
        }
    }

    swap(arr, i + 1, high);
    return i + 1;
}
</code></pre>
<p>Throughout the algorithm, one invariant always remains true:</p>
<ul>
<li><p>Everything before <code>i</code> is already less than or equal to the pivot.</p>
</li>
<li><p>Everything between <code>i + 1</code> and <code>j - 1</code> is greater than the pivot.</p>
</li>
<li><p>Everything after <code>j</code> has not been processed yet.</p>
</li>
</ul>
<h4>Recursive calls in Lomuto</h4>
<pre><code class="language-java">quickSort(arr, low, p - 1);
quickSort(arr, p + 1, high);
</code></pre>
<hr />
<h3>Hoare Partitioning Scheme</h3>
<p>While Lomuto grows a boundary from left to right, Hoare Partition takes a completely different approach. Instead of expanding a single region, it places two pointers at opposite ends of the array and moves them toward each other.</p>
<p>Whenever the left pointer finds an element that belongs on the right, and the right pointer finds an element that belongs on the left, the two elements are swapped. This continues until the pointers cross, at which point the array has been successfully partitioned.</p>
<p>One important distinction is that Hoare does not guarantee that the pivot ends up in its final sorted position after partitioning. Instead, it returns a partition boundary, and the recursive calls continue from there.</p>
<p>We'll use the same array as before.</p>
<p><code>[8, 3, 1, 7, 0, 10, 2, 5]</code> <code>Pivot = 8</code></p>
<p>Unlike Lomuto, the pivot is chosen as the first element. Many practical implementations choose the middle element as the pivot to reduce the chances of poor partitions on already sorted inputs, even though Hoare's original partition scheme uses the first element.</p>
<p>Before the algorithm begins:</p>
<ul>
<li><p><code>i</code> starts before the first element and moves right.</p>
</li>
<li><p><code>j</code> starts after the last element and moves left.</p>
</li>
</ul>
<p>Initially,</p>
<ul>
<li><p><code>i = low - 1</code></p>
</li>
<li><p><code>j = high + 1</code></p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/6a9454963cf48ec0a4827072/9839333b-8e0c-4b54-803b-607e8423595f.svg" alt="" style="display:block;margin:0 auto" />

<p><strong>Step-by-step execution</strong></p>
<ol>
<li><p>Initially, the array is -&gt; <code>[8, 3, 1, 7, 0, 10, 2, 5]</code> ; <code>i</code> moves right and finds an element greater than the pivot, while <code>j</code> moves left and finds an element smaller than the pivot.<br />Here, the element at <code>i = 0</code> (8) is equal to the pivot, and the element at <code>j = 7</code> is smaller than the pivot (5 &lt; 8). <strong>Swap them.</strong></p>
<p><strong>Array after swapping -&gt;</strong> <code>[5, 3, 1, 7, 0, 10, 2, 8]</code></p>
</li>
<li><p>Continue Searching. The pointers repeat the same process.</p>
<p><code>i</code> Now moves until it reaches <code>10</code>.</p>
<p><code>j</code> moves left until it reaches <code>2</code>.</p>
<p>Swap them.</p>
</li>
<li><p>The search continues. Eventually, <code>i &gt;= j</code>. At this moment, partitioning is complete.<br />Instead of moving the pivot again, the algorithm simply returns. <code>j</code>.</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/6a9454963cf48ec0a4827072/34b89433-1720-4ff6-ac44-2cc380b1f05a.svg" alt="" style="display:block;margin:0 auto" />

<p>The important takeaway is that the pivot (<code>8</code>) is not guaranteed to be in its final sorted position.</p>
<p>The returned value (<code>j</code>) simply marks where the array has been divided.</p>
<p><strong>Java Implementation</strong></p>
<pre><code class="language-java">static int hoarePartition(int[] arr, int low, int high) {
    int pivot = arr[low];
    int i = low - 1;
    int j = high + 1;

    while (true) {

        do {
            i++;
        }
        while (arr[i] &lt; pivot);

        do{
            j--;
        }
        while (arr[j] &gt; pivot);

        if (i &gt;= j)
            return j;

        swap(arr, i, j);
    }
}
</code></pre>
<h4>Recursive calls in Hoare</h4>
<p>Unlike Lomuto, Hoare returns a partition boundary, so the recursive calls are slightly different.</p>
<pre><code class="language-java">quickSort(arr, low, p);
quickSort(arr, p + 1, high);
</code></pre>
<hr />
<h3>Lomuto vs Hoare: Comparison</h3>
<p>Both Lomuto and Hoare partition an array around a pivot, but they work differently. Lomuto grows a boundary from left to right, while Hoare moves two pointers toward each other.</p>
<p><strong>Comparison Table</strong></p>
<table style="min-width:270px"><colgroup><col style="width:220px"></col><col style="min-width:25px"></col><col style="min-width:25px"></col></colgroup><tbody><tr><td><p><strong>Feature</strong></p></td><td><p><strong>Lomuto</strong></p></td><td><p><strong>Hoare</strong></p></td></tr><tr><td><p>Pivot selection</p></td><td><p>Last element</p></td><td><p>First element (original)</p></td></tr><tr><td><p>Pointers used</p></td><td><p>Boundary (<code>i</code>) + Scanner (<code>j</code>)</p></td><td><p>Two inward pointers (<code>i</code>, <code>j</code>)</p></td></tr><tr><td><p>Pivot ends in final position?</p></td><td><p>Yes</p></td><td><p>No</p></td></tr><tr><td><p>Returned value</p></td><td><p>Pivot index</p></td><td><p>Partition boundary (<code>j</code>)</p></td></tr><tr><td><p>Number of swaps</p></td><td><p>Usually more</p></td><td><p>Usually fewer</p></td></tr><tr><td><p>Ease of understanding</p></td><td><p>Easier</p></td><td><p>Slightly harder</p></td></tr><tr><td><p>Practical performance</p></td><td><p>Good</p></td><td><p>Often better</p></td></tr></tbody></table>

<img src="https://cdn.hashnode.com/uploads/covers/6a9454963cf48ec0a4827072/7c14da99-a9c9-4807-9eb4-0e1dda33ce05.svg" alt="" style="display:block;margin:0 auto" />

<hr />
<blockquote>
<p>If you're learning Quick Sort for the first time, Lomuto is usually easier to reason about because the pivot finishes in its final position after partitioning. Hoare, however, often performs fewer swaps, which is why many implementations prefer it in practice.</p>
</blockquote>
]]></content:encoded></item></channel></rss>