【问题标题】:how to implement quick sort algorithm in C++如何在 C++ 中实现快速排序算法
【发布时间】:2014-04-25 15:17:57
【问题描述】:

这是来自 MITOcw(Introduction To Algorithms ) 讲座的快速排序算法

QUICKSORT(A,p,q)
if(p < q)
then r = PARTITION(A,p,q)
     QUICKSORT(A,p,r-1)
     QUICKSORT(A,r+1,q)

PARTITION(A,p,q)
x = A[p]
i=p
for j = p+1 to q
    if A[j] <= x
       then i = i+1
            swap A[i] with A[j]
swap A[p] with A[i]
return i

这里是它在整数数组上的 C++ 实现

#include <iostream>

using namespace std;

void quickSort(int *,int,int);

int partition(int *, int,int);

int main()
{
    int A[10]={6,10,13,5,8,3,2,25,4,11};
    int p=0,q=10;

    cout<<"======Original======="<<endl;
    for(int f=0; f<10; f++)
        cout<<A[f]<<endl;

    quickSort(A,p,q);

    cout<<"======Sorted======="<<endl;
    for(int f=0; f<10; f++)
        cout<<A[f]<<endl;
}


void quickSort(int *A, int p,int q)
{
    int r;
    if(p<q)
    {
        r=partition(A, p,q);
        quickSort(A,p,(r-1)); //I think the problem is here this first quickSort call
                              // is reducing the value of r and hence value of q becomes
                              // less than p recursively. How can I separate both calls
                              // one for left and one for right sub array of the pivot. 
        quickSort(A,(r+1),q);
    }
}


int partition(int *A, int p,int q)
{
    int x= A[p];
    int i=p;
    int temp;
    int j;

    for(j=p+1; j<q; j++)
    {
        if(A[j]<=x)
        {
            i=i+1;
            temp= A[j];
            A[j]=A[i];
            A[i]=temp;
        }

    }

    temp= A[p];
    A[p]=A[i];
    A[i]=temp;

    return i;
}

尽管 quickSort 函数的前两次运行提供了所需的输出,但代码不会产生排序数组。也就是说,它将第一个枢轴元素放在正确的位置

【问题讨论】:

    标签: c++ algorithm sorting recursion quicksort


    【解决方案1】:

    这是一个基于模板的解决方案。但是,它目前仅适用于元素数组。如果有人有改进使其适用于数组和 STL 容器,请这样做。

    template<typename T, typename compare = std::less<T>>
    void q_sort(T input[], int l_idx, int r_idx, compare comp = compare()) {
    
        if (l_idx >= r_idx)
            return;
    
        // The below is the partition block (can be made a sub function)
    
        int left = l_idx;
        int right = r_idx;
        {
            int pivot_idx = l_idx;
            T pivot = input[pivot_idx];
    
            while (left < right) {
                while (comp(input[left], pivot))
                    left++;
                while (comp(pivot, input[right]))
                    right--;
                swap(input[left], input[right]);
            }
    
            swap(pivot, input[left]);
        }
    
        q_sort(input, l_idx, left, comp);
        q_sort(input, left+1, r_idx, comp);
    
    }
    
    template<typename T, typename compare = std::less<T>>
    void quick_sort(T array[], int N, compare comp = compare()) {
        // This is an improvisation on the merge sort algorithm
        // is in-place and works on the divide-and-conquer methodology
        // Choose a pivot and find its appropriate place, such that
        // All elements less than the pivot are on its left and all elements
        // greater are on its right. Once found, split the porlblem into subsets
        // of elements less than and greater than the pivot and recursively
        // follow the process.
        q_sort(array, 0, N-1, comp);
    
    }
    
    int main()
    {
    
        int input[] = {11, 6, 3, 21, 9, 12};
        std::cout << "Before : ";
        for (int i=0; i < 6; i++)
            std::cout << input[i] << " ";
        std::cout << std::endl;
    
        quick_sort(input, 6);
        // or 
        //quick_sort(input, 6, std::greater<int>());
    
        std::cout << "After : ";
        for (int i=0; i < 6; i++)
            std::cout << input[i] << " ";
        std::cout << std::endl;
    
    }
    

    【讨论】:

    • 我猜你的实现中有一个错误。我将您的代码用于随机整数数组。该程序刚刚在某处被阻塞...
    【解决方案2】:

    因为我看到各种答案,你可以试试这个:

    #include <iostream>
    
    void quickSort(int a[], int first, int last);
    int pivot(int a[], int first, int last);
    void swap(int& a, int& b);
    void swapNoTemp(int& a, int& b);
    void print(int array[], const int& N);
    
    using namespace std;
    
    int main()
    {
        int test[] = { 7, -13, 1, 3, 10, 5, 2, 4 };
        int N = sizeof(test)/sizeof(int);
    
        cout << "Size of test array :"  << N << endl;
    
        cout << "Before sorting : " << endl;
        print(test, N);
    
        quickSort(test, 0, N-1);
    
        cout << endl << endl << "After sorting : " << endl;
        print(test, N);
    
        return 0;
    }
    
    /**
     * Quicksort.
     * @param a - The array to be sorted.
     * @param first - The start of the sequence to be sorted.
     * @param last - The end of the sequence to be sorted.
    */
    void quickSort( int a[], int first, int last ) 
    {
        int pivotElement;
    
        if(first < last)
        {
            pivotElement = pivot(a, first, last);
            quickSort(a, first, pivotElement-1);
            quickSort(a, pivotElement+1, last);
        }
    }
    
    /**
     * Find and return the index of pivot element.
     * @param a - The array.
     * @param first - The start of the sequence.
     * @param last - The end of the sequence.
     * @return - the pivot element
    */
    int pivot(int a[], int first, int last) 
    {
        int  p = first;
        int pivotElement = a[first];
    
        for(int i = first+1 ; i <= last ; i++)
        {
            /* If you want to sort the list in the other order, change "<=" to ">" */
            if(a[i] <= pivotElement)
            {
                p++;
                swap(a[i], a[p]);
            }
        }
    
        swap(a[p], a[first]);
    
        return p;
    }
    

    我有它在Quicksort (C++)

    【讨论】:

      【解决方案3】:

      一个更简单和干净的实现,还为您提供 QuickSort 的最小 SWAPS 数量:

      int quickSort(int[], int, int);
      
      int partition(int[], int, int, int&);
      
      int main()
      {
          int array[] = {4, 2, 5};
          int size = sizeof(array)/sizeof(array[0]);
      
          /*
           first and last indices are passed
           idea is to move lower elements to the left of the list/pivot
           */
      
          int swaps = quickSort(array, 0, size-1);
      
          std::cout << "Minimum Swaps are: " << swaps << std::endl;
      
          for(int i = 0; i < size; i++)
          {
              std::cout << array[i] << " ";
          }
      }
      
      int quickSort(int array[], int start, int end)
      {
          int swaps = 0;
          if(start < end)
          {
              int pIndex = partition(array, start, end, swaps);
              //after each call one number(the PIVOT) will be at its final position
              swaps += quickSort(array, start, pIndex-1);
              swaps += quickSort(array, pIndex+1, end);
          }
          return swaps;
      }
      
      int partition(int array[], int start, int end, int& swaps)
      {
          int pivot = array[end];
          int pIndex = start;
      
          for(int i = start; i < end; i++)
          {
              if(array[i] <= pivot)
              {
      
                  if(pIndex != i)
                  {
                      std::swap(array[i], array[pIndex]);
                      swaps++;
                  }
                  pIndex++;
              }
          }
          if(pIndex != end)
          {
              std::swap(array[pIndex], array[end]);
              swaps++;
          }
          return pIndex;
      }
      

      【讨论】:

        【解决方案4】:

        你的考虑是错误的。 r 的值不会改变,因为它是作为 Quicksort 函数的值(不是参考)。 您使用p,q 处理范围,这样p 是范围中的第一个索引,q 是范围中不是的第一个索引。

        因此,您的调用是错误的:

        r=partition(A, p,q);
        quickSort(A,p,r); //range is from A[p] to A[r-1] 
        quickSort(A,(r+1),q); //range is from A[r+1] to A[q-1]
        

        这是完整的示例。我使用 std::swap 来改变元素和 ans std::vector 而不是数组。

        #include <iostream>
        #include <vector>
        
        using namespace std;
        
        void quickSort(vector<int>&,int,int);
        
        int partition(vector<int>&, int,int);
        
        int main()
        {
            vector<int> A = {6,10,13,5,8,3,2,25,4,11};
            int p=0;
            int q=10;
        
            cout<<"======Original======="<<endl;
            for(auto e: A)
                cout<< e <<" ";
            cout<< endl;    
        
            quickSort(A,p,q);
        
            cout<<"======Sorted======="<<endl;
            for(auto e: A)
                cout<< e <<" ";
            cout<< endl;   
        }
        
        
        void quickSort(vector<int>& A, int p,int q)
        {
            int r;
            if(p<q)
            {
                r=partition(A, p,q);
                quickSort(A,p,r);  
                quickSort(A,r+1,q);
            }
        }
        
        
        int partition(vector<int>& A, int p,int q)
        {
            int x= A[p];
            int i=p;
            int j;
        
            for(j=p+1; j<q; j++)
            {
                if(A[j]<=x)
                {
                    i=i+1;
                    swap(A[i],A[j]);
                }
        
            }
        
            swap(A[i],A[p]);
            return i;
        }
        

        现场示例:ideone

        【讨论】:

        • 嗨,我正在尝试理解这个算法,枢轴是什么?如果我改变 p 或 q 的值,算法不会对所有数组进行排序。
        • @D1X A[p] 是枢轴元素。由于p 是需要排序的数组部分的左边界,因此枢轴元素始终是第一个元素。只有索引 pq 之间的数组部分被排序。
        • 那么如果我想选择另一个枢轴我该怎么做呢?
        • 重写方法int partition(...)。例如。选择第二个(或最后一个)元素,并在当前过程开始时将其与第一个元素交换。
        • 为什么是 q=10 ?而 p 仍然 = 0。
        猜你喜欢
        • 2019-05-01
        • 2023-03-30
        • 1970-01-01
        • 2022-06-21
        • 2023-01-31
        • 2019-11-20
        • 2018-05-17
        • 1970-01-01
        • 2018-09-20
        相关资源
        最近更新 更多