C++ 快速排序实现

C++ 快速排序实现,c++,C++,大家好,我是C++新手,一直在潜心研究搜索和排序算法,并决定尝试编写自己的算法。以下是我的原型: void quicksort(int data[ ], size_t n); // Precondition: data is an array with at least n components. // Postcondition: The elements of data have been rearranged so // that data[0] <= data[1] <= .

大家好,我是
C++
新手,一直在潜心研究搜索和排序算法,并决定尝试编写自己的算法。以下是我的原型:

void quicksort(int data[ ], size_t n);
// Precondition: data is an array with at least n components.
// Postcondition: The elements of data have been rearranged so
// that data[0] <= data[1] <= ... <= data[n-1].

void partition(int data[ ], size_t n, size_t& pivot_index);
// Precondition: n > 1, and data is an array (or subarray)
// with at least n elements.
// Postcondition: The function has selected some "pivot value"
// that occurs in data[0]..data[n-1]. The elements of data
// have then been rearranged, and the pivot index set so that:
//   -- data[pivot_index] is equal to the pivot;
//   -- Each item before data[pivot_index] is <= the pivot;
//   -- Each item after data[pivot_index] is > the pivot.

void setPivot(int data[ ], size_t n);
// Precondition: n > 1 and data is an array or subarray
// Postcondition: data[0] holds the selected pivot value
//  The original value of data[0] has been swapped with the selected pivot value
我已经开始函数定义:

void quicksort(int data[ ], size_t n)
// Library facilities used: cstdlib
{
    size_t pivot_index; // Array index for the pivot element
    size_t n1;          // Number of elements before the pivot element
    size_t n2;          // Number of elements after the pivot element

    if (n > 1)
    {
        // Partition the array, and set the pivot index.
        partition(data, n, pivot_index);

        // Compute the sizes of the subarrays.
        n1 = pivot_index;
        n2 = n - n1 - 1;

        // Recursive calls will now sort the subarrays.
        quicksort(data, n1);
        quicksort((data + pivot_index + 1), n2);
    }
}

void partition(int data[ ], size_t n, size_t& pivot_index)
// Library facilities used: algorithm, cstdlib
{
    assert(n > 1);
    setPivot(data, n);
}

void setPivot(int data[ ], size_t n)
// Library facilties used: algorithm, cstdlib
// This function chooses a pivot value as the median of three
// randomly selected values.  The selected pivot is swapped with
// data[0] so that the pivot value is in the first position of the array
{
    assert(n > 1);

}

我的问题是完成
void分区(int data[],size\t n,size\t&pivot\u index
void setPivot(int data[],size\t n)的最佳方法是什么
关于速度?

这是一个需要回答的有点棘手的问题,我喜欢你用双脚跳进去。因此,在构造编译器时,你根据一条指令与另一条指令相比所花费的时间单位来选择指令。尽管你可以使用Raymond的建议,只使用预先构造的代码,但你不会学到太多在比较排序算法中,最昂贵的两条指令是数组中的比较和交换,所以要最小化它们

我将首先讨论一个好的分区算法背后的数学问题。假设数据在数据[0 ]中,考虑最好的方法来最小化那些昂贵的掉期。

   [34, 33, 9, 45, 1, -1, 9, -18, 75, 100]
一个好的分区可以最小化我们移动轴心的次数,因为我们不能最小化我们移动某物的次数(如果可以的话,我们就不会进行排序)

wall:=1
对于(i:=1;i数据[i]){
交换(数据、墙、i)
++墙
}
}
交换(数据,墙1,0)
枢轴指数:=墙-1
那么现在来回答为什么这是最有效的方法之一

  • 它最大限度地减少了昂贵的掉期交易的数量
  • 它最大限度地减少了添加的数量
  • 它确实使用的添加是+,它将100%转换为INC%reg汇编指令,这比向寄存器添加1要快,而寄存器不能保证(…但很可能会)。((这样做真是太迂腐了))
  • 接下来是一个选择轴心的聪明方法。在评论中,它说的是中值,但出于统计原因,我要将其改为“选择三个随机数”。快速排序的运行时复杂性完全取决于轴心的选择。选择错误可能是O(n^2),选择正确则近似于O(n*log(n))。最好选择将数组平均分成两段等长的数据。50%的数据点高于数据点,50%低于数据点,即平均值。如果我们必须计算平均值,计算总体平均值会很慢,并且会破坏我们获得的任何性能,因此我们只需要计算平均值e估计总体平均值的样本平均值

    void setPivot(int data[ ], size_t n)
    
       index1:= rand_uniform()*n
       index2:= rand_uniform()*n
       index3:= rand_uniform()*n
    
       mean:=(data[index1]+data[index2]+data[index3])/3
    
       offset1:=abs(index1-mean)
       offset2:=abs(index2-mean)
       offset3:=abs(index3-mean)
    
       if(offset1 < offset2 && offset1 < offset3)
           swap(data,0,index1)
       else if(offset2 < offset1 && offset2 < offset3)
           swap(data,0,index2)
       else if(offset3 < offset1 && offset3 < offset2)
           swap(data,0,index3)
    
    void setPivot(整数数据[],大小)
    index1:=rand_uniform()*n
    index2:=rand_uniform()*n
    index3:=rand_uniform()*n
    平均值:=(数据[index1]+数据[index2]+数据[index3])/3
    抵销1:=abs(指数1平均值)
    抵销2:=abs(指数2平均值)
    抵销3:=abs(指数3平均值)
    如果(偏移量1<偏移量2&&偏移量1<偏移量3)
    交换(数据,0,索引1)
    否则如果(偏移量2<偏移量1&&偏移量2<偏移量3)
    交换(数据,0,index2)
    否则如果(偏移量3<偏移量1&&偏移量3<偏移量2)
    交换(数据,0,索引3)
    

    应该清楚的是,这样做会有很多开销,但是setPivot的时间复杂度是恒定的,这意味着对于足够大的n来说,这样做会更快,因为选择的piviot在统计上会更频繁地将数据分成两个相等的部分,这是一个好的分治算法的全部要点thm.

    试试
    std::partition
    。太棒了!信息量非常大!那么您认为对于较大的数据库来说,快速排序是更快的选择吗?我知道,根据数据最初的排序方式,即升序到降序,或者至少是按一定顺序排序,那么其他排序方法是首选的?还是应该只使用快速排序@AlexChapman学习不同的排序算法是很好的,但是一旦你知道它们是如何工作的,你通常只需要使用标准库就可以做到这一点(例如,
    std::sort
    )。我不会这么说,因为快速排序有O(nlog(n))最佳时间它本身就是最好的。它确实平均有一个很好的运行时间,并且这个使用智能枢轴选择的实现在最坏情况下运行的时间是O(n^2)是极不可能的。还有另一个排序算法利用了总是在O(nlog(n))中运行的堆时间公正地命名为HeapSort,这是你绝对应该检查的东西。如果你想得到真正的最佳,你可以计算出n个void分区的大小比void setPivot快,然后切换到一个简单的pivot选择。太棒了!谢谢@kryler,我感谢你提供的所有信息!
    wall:=1
    for(i:=1; i < n; ++i){
       if(data[0]>data[i]){
          swap(data, wall, i)
          ++wall
       }
    }
    
    swap(data, wall-1, 0)
    pivot_index:=wall-1
    
    void setPivot(int data[ ], size_t n)
    
       index1:= rand_uniform()*n
       index2:= rand_uniform()*n
       index3:= rand_uniform()*n
    
       mean:=(data[index1]+data[index2]+data[index3])/3
    
       offset1:=abs(index1-mean)
       offset2:=abs(index2-mean)
       offset3:=abs(index3-mean)
    
       if(offset1 < offset2 && offset1 < offset3)
           swap(data,0,index1)
       else if(offset2 < offset1 && offset2 < offset3)
           swap(data,0,index2)
       else if(offset3 < offset1 && offset3 < offset2)
           swap(data,0,index3)