QuickSort方法在C ++中仅使用单个向量作为输入参数

时间:2018-03-29 07:29:14

标签: c++ quicksort

我正在尝试用C ++编写QuickSort方法。我认为我的问题在于:

if( i <= j )

因为这不是比较矢量中的值而是我的索引。我试图使用括号operator []来访问该值,但代码消耗内存并且不会自行结束。

此外,我宁愿将其保留为单个方法,而不是将其拆分为分区方法和排序方法。

STD :: sort与其他排序方法一起在其他地方实现。我写这篇文章时遇到了麻烦;我的输入仅限于矢量。

这就是我所拥有的

vector<double> QuickSort(vector<double> & vec1){

    double i = 0;
    double j = vec1.size()-1;
    int size = vec1.size();
    double tmp;

    double pivot = vec1[(i + j) / 2];

//   partition 

    while (i <= j) {
        while (vec1[i] < pivot)
            i++;
        while (vec1[j] > pivot)
            j--;
        if (vec1[j] <= vec1[j-1]) {
            tmp = vec1[j-1];
            vec1[j-1] = vec1[j];
            vec1[j] = tmp;
            i++;
            j--;
        }
    }

//    recursion 

    if (vec1[i] > vec1[i+1]) {
        QuickSort(vec1);
    }

    if (vec1[j] <vec1[j-1]) {
        QuickSort(vec1);
    }

    return vec1;
}

请提出建议和意见。

3 个答案:

答案 0 :(得分:1)

编写递归函数的第一条规则是定义没有什么可做的情况。您的代码不会执行此操作,并且假定它永远不会到达。大小&lt; = 1的向量是空的,并且在这样的向量上测试vec1[i] > vec1[i+1]是未定义的行为。

编写递归函数的第二个规则是确保每次内部调用都减少问题大小。你的代码没有这样做,它将整个向量传递给它自己(两次,如果第一个将返回)。

向量不是由double索引,而是由size_t s(或带有符号转换的int s)索引。

您通过引用接受vec1,改变它,然后在回复中复制它。做一个,而不是两者。

here

的实施
namespace detail {    
    template<class FwdIt, class Compare = std::less<>>
    void QuickSortImpl(FwdIt first, FwdIt last, Compare cmp = Compare{})
    {
        auto const N = std::distance(first, last);
        if (N <= 1) return;
        auto const pivot = *std::next(first, N / 2);
        auto const middle1 = std::partition(first, last, [=](auto const& elem){ 
            return cmp(elem, pivot); 
        });
        auto const middle2 = std::partition(middle1, last, [=](auto const& elem){ 
            return !cmp(pivot, elem);
        });
        QuickSortImpl(first, middle1, cmp);
        QuickSortImpl(middle2, last, cmp);
    }   
}

void QuickSort(vector<double>& vec1)
{
    detail::QuickSortImpl(vec1.begin(), vec1.end());
}

如果你真的坚持拥有一个功能参数,可以使用范围库(boost::rangerange v3)来完成

template<class Range>
void QuickSort(Range& range)
{
    auto const N = std::distance(range.begin(), range.end());
    if (N <= 1) return;
    auto const pivot = *std::next(range.begin(), N / 2);
    auto left_range = boost::partition<boost::return_begin_found>(
        range.begin(), 
        range.end(), 
        [=](auto const& elem){ 
            return elem < pivot; 
        }
    );
    auto right_range = boost::partition<boost::return_found_end>(
        left_range.end(), 
        range.end(), 
        [=](auto const& elem){ 
            return !(pivot < elem);
        }
    );
    QuickSort(left_range);
    QuickSort(right_range);
}   

答案 1 :(得分:0)

我建议使用std::sort,除非你有充分的理由不这样做。

为了让一个函数只接受一个参数,std::sort的包装可能看起来像这样,但是你正在复制你的向量。如果您不喜欢这样,可以通过引用传递它。

#include <iostream>   // std::cout
#include <algorithm>  // std::sort
#include <vector>     // std::vector

std::vector<double> mySort(const std::vector<double> unsorted) {
    std::vector<double> sorted = unsorted; 
    std::sort(sorted.begin(), sorted.end()); 
    return sorted;
}

int main() {
    std::vector<double> myvector{32, 71, 12, 45, 26, 80, 53, 33};

    for (const auto item : myvector) {
        std::cout << item << " ";
    }
    std::cout << std::endl;

    auto myvector_sorted = mySort(myvector);

    for (const auto item : myvector_sorted) {
        std::cout << item << " ";
    }
    std::cout << std::endl;

    return 0;
}

然而,实施的底部没有意义,因为

if (vec1[i] > vec1[i + 1]) {
    QuickSort(vec1);
}
if (vec1[j] < vec1[j - 1]) {
    QuickSort(vec1);
}

将始终QuickSortvec1一起开始。您还需要传递ij。为了有一个参数接口,你可以写

vector<double> QuickSort(vector<double> & vec1, int i = 0, int j = vec1.size() - 1 ) {
    int size = vec1.size();
    ....

答案 2 :(得分:0)

我修改了你的代码。我决定将枢轴指数作为最后一项。并添加了一些测试代码。它运作正常。我认为如果QuickSort函数具有索引参数,则可以更简单地实现。

#include <iostream>
#include <vector>
#include <chrono>


using namespace std ;

void printvector(vector<double> v) {
cout << "vector : " ;
for (double n : v) {
cout << n << " " ;
}
cout << endl ;
}

vector<double> QuickSort(vector<double>& vec1){

    double i = 0;
    double j = vec1.size()-2;
    double tmp;
    int pivotindex = vec1.size()-1 ;
    double pivot = vec1[pivotindex];

    if ( vec1.size()<=1 )
        return vec1 ;

    cout << "QuickSort: ";
    printvector(vec1) ;

    while (i <= j) {
        while (vec1[i] < pivot) {
            i++;
        }
        while (vec1[j] > pivot)
            j--;
         if (i <= j) {
            tmp = vec1[i];
            vec1[i] = vec1[j];
            vec1[j] = tmp;
            i++;
            j--;
        }
    }
    // pivot change
    vec1[pivotindex] = vec1[i] ;
    vec1[i]=pivot ;
    pivotindex=i ;

    cout << "pivotting: ";
    printvector(vec1) ;

    if (vec1.size()<=2 )
        return vec1 ;
    // partition
    vector<double> left_vec, right_vec ;
    vector<double>::iterator pivotiter = vec1.begin()+pivotindex ;
    copy(vec1.begin(), pivotiter, back_inserter(left_vec)) ;
    copy(pivotiter+1, vec1.end(), back_inserter(right_vec)) ;

    cout << "left: ";
    printvector(left_vec) ;
    cout << "right: ";
    printvector(right_vec) ;

   if (left_vec.size()>0 ) {
        QuickSort(left_vec);
        copy(left_vec.begin(), left_vec.end(), vec1.begin()) ;
    }
   if (right_vec.size()>0 ) {
        QuickSort(right_vec);
        copy(right_vec.begin(), right_vec.end(), pivotiter+1) ;
    }
    return vec1;
}

int main()
{
//vector<double> v { 5 } ;
//vector<double> v { 5, 3 } ;
//vector<double> v { 5, 3, 1 } ;
//vector<double> v { 1, 3, 5 } ;
//vector<double> v { 9,4,8,5,1,2,7 } ;
vector<double> v  ;
//srand( time(NULL) ) ;
int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
srand( now ) ;
for (int i=0; i<rand()%30+1; i++) {
    v.push_back( rand()%10000 ) ;
}

cout << "input values: " ;
printvector(v) ;

vector<double> ret = QuickSort(v) ;
cout << "output values: " ;
printvector(ret) ;
cout << endl << endl ;

return 0 ;
}

输出就是这个。

input values: vector : 1778 9400 9330 783 3148 2029 9685 
QuickSort: vector : 1778 9400 9330 783 3148 2029 9685 
pivotting: vector : 1778 9400 9330 783 3148 2029 9685 
left: vector : 1778 9400 9330 783 3148 2029 
right: vector : 
QuickSort: vector : 1778 9400 9330 783 3148 2029 
pivotting: vector : 1778 783 2029 9400 3148 9330 
left: vector : 1778 783 
right: vector : 9400 3148 9330 
QuickSort: vector : 1778 783 
pivotting: vector : 783 1778 
QuickSort: vector : 9400 3148 9330 
pivotting: vector : 3148 9330 9400 
left: vector : 3148 
right: vector : 9400 
output values: vector : 783 1778 2029 3148 9330 9400 9685