【问题标题】:Stackoverflow with Quicksort Java implementationStackoverflow 与 Quicksort Java 实现
【发布时间】:2013-02-16 05:36:14
【问题描述】:

在 java 中实现快速排序时遇到一些问题。运行此程序时出现 stackoverflow 错误,我不确定为什么。如果有人能指出错误,那就太好了。

si 是起始索引。 ei 是结束索引。

public static void qsort(int[] a, int si, int ei){

    //base case
    if(ei<=si || si>=ei){}


    else{ 
        int pivot = a[si]; 
        int length = ei - si + 1; 
        int i = si+1; int tmp; 

        //partition array 
        for(int j = si+1; j<length; j++){
            if(pivot > a[j]){
                tmp = a[j]; 
                a[j] = a[i]; 
                a[i] = tmp; 

                i++; 
            }
        }

        //put pivot in right position
        a[si] = a[i-1]; 
        a[i-1] = pivot; 

        //call qsort on right and left sides of pivot
        qsort(a, 0, i-2); 
        qsort(a, i, a.length-1); 
    }
}

【问题讨论】:

  • 哪一行抛出异常?
  • 最后两行。在枢轴的右侧和左侧调用快速排序的两个。
  • 如果子数组大小为 0 或 1,基本情况看起来很标准。
  • or 条件的右侧和左侧看起来是一回事。 ei &lt;= si 在逻辑上与si &gt;= ei 完全相同。
  • 我在主要方法中有它:qsort(ar, 0, ar.length-1);其中 ar 是我创建的数组。

标签: java algorithm sorting stack-overflow quicksort


【解决方案1】:

首先,您应该按照 Keith 的建议修复 qsort 递归调用的边界,否则您总是会一遍又一遍地对整个数组进行排序。你必须调整你的分区循环: j 是一个索引,从子数组的开头到它的结尾(包括最后一个元素)。所以你必须从 si + 1 循环到 ei(包括 ei)。

所以这是更正后的代码。我跑了几个测试用例,结果似乎还不错。

    public static void qsort(int[] a, int si, int ei){
    //base case
    if(ei<=si || si>=ei){}

    else{ 
        int pivot = a[si]; 
        int i = si+1; int tmp; 

        //partition array 
        for(int j = si+1; j<= ei; j++){
            if(pivot > a[j]){
                tmp = a[j]; 
                a[j] = a[i]; 
                a[i] = tmp; 

                i++; 
            }
        }

        //put pivot in right position
        a[si] = a[i-1]; 
        a[i-1] = pivot; 

        //call qsort on right and left sides of pivot
        qsort(a, si, i-2); 
        qsort(a, i, ei); 
    }
}

【讨论】:

    【解决方案2】:
    int partition(int array[], int too_big_index, int too_small_index)
    {
         int x = array[too_big_index];
         int i = too_big_index;
         int j = too_small_index;
         int temp;
         do
         {                 
             while (x <array[j])
            {
                  j --;
            } 
             while (x >array[i])
             {
                  i++;
             } 
              if (i < j)
             { 
                     temp = array[i];    
                     array[i] = array[j];
                     array[j] = temp;
             }
         }while (i < j);     
         return j;           // middle  
    }
    
    void QuickSort(int num[], int too_big_index, int too_small_index)
    {
          // too_big_index =  beginning of array
          // too_small_index = end of array
    
         int middle;
         if (too_big_index < too_small_index)
        {
              middle = partition(num, too_big_index, too_small_index);
              QuickSort(num, too_big_index, middle);   // sort first section
              QuickSort(num, middle+1, too_small_index);    // sort second section
         }
         return;
    }
    
    
    
    void main()
    {
        int arr[]={8,7,13,2,5,19,1,40,12,34};
    
        QuickSort(arr,0,9);
        for(int i=0;i<10;i++)
             System.out.println(arr[i]);
    }
    

    【讨论】:

      【解决方案3】:

      您的手上可能有一个无限递归错误。从我的快速浏览中不确定,但是...

      即使您不这样做,您仍将在此实现中使用 lots 的堆栈。足以导致堆栈溢出。如果你用已经排序的 100 万个项目调用它会发生什么?您将它们划分为 1 和 999,999 项,然后递归。因此,您需要 100 万个堆栈帧才能完成这项工作。

      有很多方法可以解决这个问题,包括递归两个范围中较小的一个并迭代两个范围中较大的一个,或者在堆数据结构中自己实现堆栈等。您可能希望做得更好但是,由于深堆栈也意味着您正在超越 O(n lg n) 排序界限。

      附言错误在这里:

      qsort(a, 0, i-2); 
      qsort(a, i, a.length-1); 
      

      应该是

      qsort(a, si, i-2);
      qsort(a, i, ei);
      

      【讨论】:

      • @MitchWheat:所以也许我应该说的是“错误”,而不是“错误”。
      • 老老实实的叫我,但我认为答案的重点是完全回答问题?
      • @MitchWheat:我的修复解决了我尝试的一个示例的堆栈溢出问题。我不会为他详尽地测试他的代码以找到可能存在的任何其他错误。
      • 是的,它修复了 stackoverflow,但数组仍然没有正确排序......几乎没有穷尽......
      • @MitchWheat:我不认为他希望我们修复他的代码,他想理解为什么它会溢出堆栈。如果我只是想修复他的代码,我会写“删除所有内容并改为调用Arrays.sort(a, si, ei+1)”。
      【解决方案4】:

      你可以试试这个:

      public void sort(int[] A) {
              if (A == null || A.length == 0)
                  return;
              quicksort(A, 0, A.length - 1);
          }
      
          public void quicksort(int[] A, int left, int right) {
              int pivot = A[left + (right - left) / 2];
              int i = left;
              int j = right;
              while (i <= j) {
                  while (A[i] < pivot) {
                      i++;
                  }
                  while (A[j] > pivot) {
                      j--;
                  }
                  if (i <= j) {
                      exchange(i, j);
                      i++;
                      j--;
                  }
              }
      
              if(left < j)
                  quicksort(A,left,j);
              if(i < right)
                  quicksort(A,i,right);
          }
      
          public void exchange(int i, int j){
              int temp=A[i];
              A[i]=A[j];
              A[j]=temp;
          }
      
          public String toString() {
              String s = "";
              s += "[" + A[0];
              for (int i = 1; i < A.length; i++) {
                  s += ", " + A[i];
              }
              s += "]";
              return s;
          }
      

      来源:Code 2 Learn: Quick Sort Algorithm Tutorial

      【讨论】:

      • 我不明白最外面的 while 循环之后的 2 行。为什么我们必须这样做? if(left
      【解决方案5】:
      import java.util.Arrays;
      
      
      public class QuickSort {
      
      
          public static int pivot(int[] a, int lo, int hi){
              int mid = (lo+hi)/2;
              int pivot = a[lo] + a[hi] + a[mid] - Math.min(Math.min(a[lo], a[hi]), a[mid]) - Math.max(Math.max(a[lo], a[hi]), a[mid]);
      
              if(pivot == a[lo])
                  return lo;
              else if(pivot == a[hi])
                  return hi;
              return mid;
          }
      
          public static int partition(int[] a, int lo, int hi){
      
              int k = pivot(a, lo, hi);
              //System.out.println(k);
              swap(a, lo, k);
              //System.out.println(a);
              int j = hi + 1;
              int i = lo;
              while(true){
      
                  while(a[lo] < a[--j])
                      if(j==lo)   break;
      
                  while(a[++i] < a[lo])
                      if(i==hi) break;
      
                  if(i >= j)  break;
                  swap(a, i, j);
              }
              swap(a, lo, j);
              return j;
          }
      
          public static void sort(int[] a, int lo, int hi){
              if(hi<=lo)  return;
              int p = partition(a, lo, hi);
              sort(a, lo, p-1);
              sort(a, p+1, hi);
          }
      
          public static void swap(int[] a, int b, int c){
              int swap = a[b];
              a[b] = a[c];
              a[c] = swap;
          }
      
          public static void sort(int[] a){
              sort(a, 0, a.length - 1);
              System.out.print(Arrays.toString(a));
          }
      
          public static void main(String[] args) {
              int[] arr = {5,8,6,4,2,9,7,5,9,4,7,6,2,8,7,5,6};
              sort(arr);
          }
      }
      

      试试这个。它肯定会起作用。

      【讨论】:

        【解决方案6】:

        //刚刚为此实现了测试器类,它会工作的

        public int[] sort(int[] A, int from, int to ){

        if(from<to){
            int pivot=partition(A,from,to);
            if(pivot>1)
                sort(A,from, pivot-1);
        
            if(pivot+1<to)
                sort(A, pivot+1, to);
        
        
        }
        
        return array;
        

        }

        public int partition(int A[ ], int from, int to){

        while(from < to){
            int pivot=A[from];
        
            while(A[from]<pivot)
                from++;
        
            while(A[to]>pivot)
                to--;
        
        
            if(from<to)   
                swap(A,to,from);
        
        
        
        }
            return to;
        }
        
        private void swap(int A[], int i, int j){
            int temp = A[i];
            A[i] = A[j];
            A[j] = temp;}
        

        【讨论】:

          【解决方案7】:

          这应该很准确。 Code below with this Image makes way more sense.

          public void quickSort(long[] a){
          
            int startingIndex = 0;
            int endingIndex = a.length - 1;
            qsort(a, startingIndex, endingIndex);
          
          }
          
          private void qsort(long[] a, int startingIndex, int endingIndex){
          
            if (startingIndex < endingIndex){
              int middleIndex = partition(a, startingIndex, endingIndex);
              qsort(a, startingIndex, middleIndex-1);
              qsort(a, middleIndex+1, endingIndex);
            }
          
          }
          
          private int partition(long[] a, int startingIndex, int endingIndex){
            long pivot = a[endingIndex];
            int endWall = endingIndex;
            int wall = 0;
          
            while (wall < endWall){
          
              if (a[wall] < pivot){
                wall++;
              }
              else {
                a[endWall] = a[wall];
                a[wall] = a[endWall - 1];
                a[endWall - 1] = pivot;
                endWall--;
              }
            }
            return wall;
          }
          

          享受吧!

          【讨论】:

            【解决方案8】:
            public class MyQuickSort {
            
                private int array[];
                private int length;
            
                public void sort(int[] inputArr) {
            
                    if (inputArr == null || inputArr.length == 0) {
                        return;
                    }
                    this.array = inputArr;
                    length = inputArr.length;
                    quickSort(0, length - 1);
                }
            
                private void quickSort(int lowerIndex, int higherIndex) {
            
                    int i = lowerIndex;
                    int j = higherIndex;
                    // calculate pivot number, I am taking pivot as middle index number
                    int pivot = array[lowerIndex+(higherIndex-lowerIndex)/2];
                    // Divide into two arrays
                    while (i <= j) {
                        /**
                         * In each iteration, we will identify a number from left side which 
                         * is greater then the pivot value, and also we will identify a number 
                         * from right side which is less then the pivot value. Once the search 
                         * is done, then we exchange both numbers.
                         */
                        while (array[i] < pivot) {
                            i++;
                        }
                        while (array[j] > pivot) {
                            j--;
                        }
                        if (i <= j) {
                            exchangeNumbers(i, j);
                            //move index to next position on both sides
                            i++;
                            j--;
                        }
                    }
                    // call quickSort() method recursively
                    if (lowerIndex < j)
                        quickSort(lowerIndex, j);
                    if (i < higherIndex)
                        quickSort(i, higherIndex);
                }
            
                private void exchangeNumbers(int i, int j) {
                    int temp = array[i];
                    array[i] = array[j];
                    array[j] = temp;
                }
            
                public static void main(String a[]){
            
                    MyQuickSort sorter = new MyQuickSort();
                    int[] input = {24,2,45,20,56,75,2,56,99,53,12};
                    sorter.sort(input);
                    for(int i:input){
                        System.out.print(i);
                        System.out.print(" ");
                    }
                }
            }
            

            【讨论】:

              【解决方案9】:
              // the partition function
              public static int Sort(int arr[], int start, int end)
              {
                  int pivot = arr[end];
                  int pIndex = start;
                  for(int i = start; i< end;i++)
                  {
                      if(arr[i] <= pivot)
                      {
                          int temp = arr[i];
                          arr[i] = arr[pIndex];
                          arr[pIndex] = temp;
                          pIndex++;
                      }
                  }
                  int temp = arr[pIndex];
                  arr[pIndex] = pivot;
                  arr[end] = temp;
                  return pIndex;
              }
              public static void quickSort(int arr[],int start,int end)
              {
                  if(start>=end)
                      return;
                  // finding the pivot element
                  int pivot = Sort(arr,start,end);
                  quickSort(arr,start,pivot-1);
                  quickSort(arr,pivot+1,end);
                  
              }
              

              【讨论】:

                【解决方案10】:

                快速排序对恰好按正确顺序的输入稍微敏感,在这种情况下它可以跳过一些交换。 Mergesort 没有任何此类优化,这也使得 Quicksort 与 Mergesort 相比要快一些。

                Why Quick sort is better than Merge sort

                【讨论】:

                  猜你喜欢
                  • 2019-11-05
                  • 2013-03-16
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-12-14
                  • 2015-04-21
                  • 2011-07-24
                  相关资源
                  最近更新 更多