[C#] Quick sort stack overflow

Quick Sort Stack Overflow

When using VS to write quick sorting, the following errors were found:
and errors such as stack overflow cannot be caught, which is really a headache.  ̄へ ̄
insert image description here

pit digging

Look at the code, using the digging method.

  public void QuickSort_v1(ref int[] data,int Low, int High)
  {
       if (Low >= High)
       {
           return;
       }
       int pivot = data[Low];  //使用data[Low]作为枢纽元素
       int i = Low;
       int j = High;
       while (i < j)
       {
           while (data[j] >= pivot && i < j)
           { 
               j--;
           }

           data[i] = data[j];              //比枢纽小的向前移动 
           while (data[i] <= pivot && i < j)
           {
               i++;
           }

           data[j] = data[i];              //比枢纽大的向后移动

       }
       data[i] = pivot; 
       QuickSort_v1(ref data,Low, i - 1); //左区间快排
       QuickSort_v1(ref data,i + 1, High); //右区间快排 
   }

There is no problem with this method for ordinary sorting, but there is a risk of overflow if the order of magnitude increases slightly. Of course, this depends on the face. Unfortunately, I got it once.


It is not difficult to see that the above code is very ironic, and the pivot always selects the first number. If the distribution of the test data is uneven, the distribution of the left and right intervals is uneven, and the stack overflows if there are too many recursions in one interval, for example, I bring in the 100,000 descending numbers, the 100,000 repeating numbers, and the 100,000 ascending ordinal numbers respectively, without exception. Sudden death. (ಥ_ಥ)

Of course there is still a solution:

  1. Improve hub selection: perform three-number selection, that is, compare the first, last and middle digits, and select a middle value as the pivot. (unable to resolve duplicates)
  2. While the three numbers are selected, the repeated numbers are aggregated: (to solve the overflow problem)
       public void QuickSort_v3(ref int[] data,int Low, int High)
        {
            if (Low >= High)
            {
                return;
            }
            //使用较为中间的数作为枢纽
            DealArray(Low, High);//作用:比较首位末位和中间位,选出中间大小的值与首位交换
            //到此可认为较为接近中间的值在第一位
            int i, j;
            int pivot;                    //使用data[Low]作为枢纽元素
            int pLow, pHigh;              //pLow与pHigh是记录枢纽两边 与枢纽值相同 的数量
            pivot = data[Low];
            i = Low;
            pLow = 0;
            j = High;
            pHigh = 0;
            while (i < j)
            {
                while (data[j] >= pivot && i < j)
                {
                    if (data[j] == pivot)
                    {
                    	//将与枢纽相同的值移动到一边
                        Swap(ref data,j, High - pHigh);//作用:交换两边的值
                        pHigh++;
                    }
                    j--;
                }

                data[i] = data[j];              //比枢纽小的向前移动 

                while (data[i] <= pivot && i < j)
                {
                    if (data[i] == pivot)
                    {
                        Swap(ref data,i, Low + pLow);
                        pLow++;
                    }
                    i++;
                }
                data[j] = data[i];              //比枢纽大的向后移动
            }
            data[i] = pivot;
            //把与枢轴相同的元素聚集起来  
            //将相同的值移动到中间
            for (int m = 0; m < pHigh; m++)
            {
                Swap( ref data, High - m, i + 1 + m);
            } 
            for (int n = 0; n < pLow; n++)
            {
                Swap( ref data , Low + n, i - 1 - n);
            }

            QuickSort_v3(ref data ,Low, i - 1 - pLow); //左区间快排
            QuickSort_v3( ref data ,i + 1 + pHigh, High); //右区间快排
        }

My number of comparisons is sky-high!
This method solves the problem of stack overflow in terms of digging holes, but due to lack of ability, it is always troublesome and uncomfortable for me to write it out.

left and right pointer

In fact, using the idea of ​​left and right pointer method can solve this problem better

   private void QuickSort_v4(ref int[] data,int low, int high)
   {
       int i = low, j = high;
       int pivot = data[low + (high - low) / 2];

       while (i <= j)
       {
           while (data[i] < pivot)
           {
               i++;
           }
           while (data[j] > pivot)
           {
               j--;
           }
           if (i <= j)
           {
               Swap(ref data ,i, j);
               i++;
               j--;
           }//同时加减,能够使大多数情况使枢纽考中,减少递归次数
       }
       if (low < j)
           QuickSort_v4(ref data,low, j);
       if (i < high)
           QuickSort_v4(ref data,i, high);
   }

This method can balance the left and right intervals very well, and it will not overflow so easily.

other

Quick sort can also be combined with other sorting algorithms to solve such problems.

Here are some articles from other bigwigs:

https://blog.csdn.net/qq_36528114/article/details/78667034 (quick sort (three algorithm implementations and non-recursive implementation))
https://blog.csdn.net/insistgogo/article/details/7785038 (three Quick sort and optimization of quick sort)


The level is limited, please bear with me ✧(≖ ◡ ≖✿

Guess you like

Origin blog.csdn.net/zigzagbomb/article/details/100852419