什么样的优化会提高我的表现?

时间:2016-03-14 12:59:36

标签: c++ performance sorting optimization

我编写了一个小型java程序,它对排序算法(合并排序,选择排序)进行基准测试,并显示他们对人物对象(名称,升序)进行排序所需的时间。

该程序的C ++版本比java版本慢至少4倍。有几位开发人员说他们通过优化代码来排序java。释放模式,/ O2,64位,....我已经完成了那些调整。

我的排序算法是否有任何低效率(特别是合并排序)?

//create a subvector
template <typename T> std::vector<T> splitVec(std::vector<T> main, size_t from, size_t to) {

std::vector<T>::const_iterator first = main.begin() + from;
std::vector<T>::const_iterator last = main.begin() + to;
std::vector<T> erg(first, last);

return erg;
}

//merge sort - sorting process
template <typename T> std::vector<T> merge(std::vector<T> m1, std::vector<T> m2) {

unsigned int posA = 0, posB = 0;

std::vector<T> erg;

while (posA < m1.size() && posB < m2.size()) {
    if (m1.at(posA).compareTo(m2.at(posB)) <= 0) {
        erg.push_back(m1.at(posA));
        posA++;
    }
    else {
        erg.push_back(m2.at(posB));
        posB++;
    }
}

while (posA < m1.size()) {
    erg.push_back(m1.at(posA));
    posA++;
}

while (posB < m2.size()) {
    erg.push_back(m2.at(posB));
    posB++;
}

return erg;
}

//merge sort-split up vectors
template <typename T> std::vector<T> mergeSort(std::vector<T> pers) {

if (pers.size() > 1) {

    //Split pers into two equally sized vectors
    std::vector<T> p1(splitVec(pers, 0, pers.size()/2));
    std::vector<T> p2(splitVec(pers, (pers.size()/2), pers.size()));

    return merge(mergeSort(p1), mergeSort(p2));
}
else
    return pers;
}

提前致谢

5 个答案:

答案 0 :(得分:3)

不要传递矢量。不是通过价值,而是通过参考。传递迭代器:

template <class Iter>
void sort(Iter first, Iter last) {
    ...
}

sort(my_vector.begin(), my_vector.end();

要分割范围,只需计算中间值:

template <class Iter>
Iter mid(Iter first, Iter last) {
    return first + (last - first) / 2;
}

这假设代码仍在对某种容器中保存的值进行排序(在原始代码中为std::vector),因此迭代器是随机访问迭代器。

答案 1 :(得分:1)

通过引用传递向量。这应该会显着提高性能。

当您按值传递矢量时,每次都会复制它(在每个步骤中添加O(n)的复杂度)

答案 2 :(得分:1)

通过引用传递源数据而不是复制它将是一个巨大的改进。

此外,您应reserve erg空格,否则您在添加更多内容时会反复重新分配和复制所有元素。

答案 3 :(得分:1)

使用push_back而不是索引很慢。一次性分配工作数组或向量,并索引到该数组,可以消除所有这些递归分配。使用一对相互递归的函数消除了在合并后必须复制数据的过程。

自下而上的合并排序会稍快一些,虽然自下而上的合并排序通常是大多数库使用的(例如std :: stable_sort),但自上而下合并排序似乎是课堂教学的内容。

自顶向下合并排序的示例模板,适用于数组或向量(将向量作为指向第一个元素的指针传递)。

template <typename T>
void TopDownSplitMergeAtoA(T a[], T b[], size_t ll, size_t ee);
template <typename T>
void TopDownSplitMergeAtoB(T a[], T b[], size_t ll, size_t ee);
template <typename T>
void TopDownMerge(T a[], T b[], size_t ll, size_t rr, size_t ee);

template <typename T>
void MergeSort(T a[], size_t n)             // entry function
{
    if(n < 2)                               // if size < 2 return
        return;
    T *b = new T[n];
    TopDownSplitMergeAtoA(a, b, 0, n);
    delete[] b;
}

template <typename T>
void TopDownSplitMergeAtoA(T a[], T b[], size_t ll, size_t ee)
{
    if((ee - ll) == 1)                  // if size == 1 return
        return;
    size_t rr = (ll + ee)>>1;           // midpoint, start of right half
    TopDownSplitMergeAtoB(a, b, ll, rr);
    TopDownSplitMergeAtoB(a, b, rr, ee);
    TopDownMerge(b, a, ll, rr, ee);     // merge b to a
}

template <typename T>
void TopDownSplitMergeAtoB(T a[], T b[], size_t ll, size_t ee)
{
    if((ee - ll) == 1){                 // if size == 1 copy a to b
        b[ll] = a[ll];
        return;
    }
    size_t rr = (ll + ee)>>1;           // midpoint, start of right half
    TopDownSplitMergeAtoA(a, b, ll, rr);
    TopDownSplitMergeAtoA(a, b, rr, ee);
    TopDownMerge(a, b, ll, rr, ee);     // merge a to b
}

template <typename T>
void TopDownMerge(T a[], T b[], size_t ll, size_t rr, size_t ee)
{
    size_t o = ll;                          // b[]       index
    size_t l = ll;                          // a[] left  index
    size_t r = rr;                          // a[] right index
    while(1){                               // merge data
        if(a[l] <= a[r]){                   // if a[l] <= a[r]
            b[o++] = a[l++];                //   copy a[l]
            if(l < rr)                      //   if not end of left run
                continue;                   //     continue (back to while)
            while(r < ee)                   //   else copy rest of right run
                b[o++] = a[r++];
            break;                          //     and return
        } else {                            // else a[l] > a[r]
            b[o++] = a[r++];                //   copy a[r]
            if(r < ee)                      //   if not end of right run
                continue;                   //     continue (back to while)
            while(l < rr)                   //   else copy rest of left run
                b[o++] = a[l++];
            break;                          //     and return
        }
    }
}

答案 4 :(得分:0)

你错过了一个非常大的优化。您按值而不是按引用传递所有向量。这意味着每个函数调用都在复制向量,效率非常低。

由于java中的所有内容都是指针,因此您的java代码不会生成所有这些副本,而这些副本应该是C ++代码中减速的主要部分。