Search code examples
c#quicksort

How to fix this quicksort?


I've made a quicksort algorithm in c# that works when there are only 10 items in the array. When I increase this number it gets stuck in an infinite loop. This is the code where the issue lies:

         while (true)
         {
            while (((IComparable)arrayToSort[left]).CompareTo(pivot) < 0)
            {
                left++;
            }

            while (((IComparable)arrayToSort[right]).CompareTo(pivot) > 0)
            {
                right--;
            }

            if (left < right) //This is where the loop becomes infinite.
            {
                object temp =arrayToSort[right];
                arrayToSort[right] = arrayToSort[left];
                arrayToSort[left] = temp;
                reDrawer.reDrawSample(right, g, arrayToSort, picSamples); //This is used to draw lines that are sorted to make the sorting visual.
                reDrawer.reDrawSample(left, g, arrayToSort, picSamples);
                refresher.refreshPicture(picSamples); //This is used to refresh the image with the lines.
                Thread.Sleep(20);
            }
            else
            {
                return right;
            }

Both of the comparison while statements are false but this if is true, and I can't see a way out of it. It occurs when right == pivot or left == pivot.

Can anyone see the issue?

The array currently has 50 variables, and this issue only occurs at high numbers of variables. I don't want to use an array with less than 50 variables.

Here's the full method:

class Quick_Sort
{
    /// <summary>
    /// This subroutine creates a pivot and partitions the array accordingly.
    /// </summary>
    /// <param name="arrayToSort"></param>
    /// <param name="left"></param>
    /// <param name="right"></param>
    /// <returns></returns>
    public int partition(ArrayList arrayToSort, int left, int right)
    {
        int pivot = (int)arrayToSort[left];
        ReDrawer reDrawer = new ReDrawer();
        Refresher refresher = new Refresher();

        while (true)
        {
            while (((IComparable)arrayToSort[left]).CompareTo(pivot) < 0)
            {
                left++;
            }

            while (((IComparable)arrayToSort[right]).CompareTo(pivot) > 0)
            {
                right--;
            }

            if (left < right)
            {
                object temp =arrayToSort[right];
                arrayToSort[right] = arrayToSort[left];
                arrayToSort[left] = temp;
                reDrawer.reDrawSample(right, g, arrayToSort, picSamples);
                reDrawer.reDrawSample(left, g, arrayToSort, picSamples);
                refresher.refreshPicture(picSamples);
                Thread.Sleep(speed);
            }
            else
            {
                return right;
            }
        }
    }

    /// <summary>
    /// This recursive subroutine is responsible for sorting the array into the correct order after the individual partitions have been ordered.
    /// </summary>
    /// <param name="arr"></param>
    /// <param name="left"></param>
    /// <param name="right"></param>
    public void sortArray(ArrayList arr, int left, int right)
    {
        if (left < right)
        {
            int pivot = partition(arr, left, right);

            if (pivot > 1)
            {
                sortArray(arr, left, pivot - 1);
            }

            if (pivot + 1 < right)
            {
                sortArray(arr, pivot + 1, right);
            }
        }
    }

}

When sortArray is called, left = 0, right = 49 & array is a random 50 element one-dimensional array.

You can ignore the references to reDrawer and refresher as these don't affect the sorting algorithm, they only draw the results in a picture box.


Solution

  • It occurs when right == pivot or left == pivot.

    You are right, in that case you stop in/de-creasing left/right. You need to in/de-crease both atleast once in each iteration.

    public int partition(ArrayList arrayToSort, int left, int right)
    {
        int pivot = (int)arrayToSort[left];
        left--;
        right++;  //To prevent the first iteration from ignoring the outermost elements
        ReDrawer reDrawer = new ReDrawer();
        Refresher refresher = new Refresher();
    
        while (true)
        {
            do
            {
                left++;
            }while (((IComparable)arrayToSort[left]).CompareTo(pivot) < 0);
    
            do
            {
                right--;
            }while (((IComparable)arrayToSort[right]).CompareTo(pivot) > 0);
    
            if (left < right)
            {
                object temp =arrayToSort[right];
                arrayToSort[right] = arrayToSort[left];
                arrayToSort[left] = temp;
                reDrawer.reDrawSample(right, g, arrayToSort, picSamples);
                reDrawer.reDrawSample(left, g, arrayToSort, picSamples);
                refresher.refreshPicture(picSamples);
                Thread.Sleep(speed);
            }
            else
            {
                return right;
            }
        }
    }