有没有更有效的方法来做这个算法?

时间:2014-01-24 07:45:09

标签: c++ algorithm recursion big-o

据我所知,此算法将正确搜索,并在需要时结果为true。在课堂上我们讨论的是Big O分析,所以这个分配是为了说明递归搜索比迭代搜索更快。关键是要搜索一个数字,使得A [i] = i(找到与索引中存储的数字相同的索引)。该算法与迭代算法相比仅变化约100纳秒,但有时迭代算法更快。我使用rand()函数在main中设置了向量。我运行两百万次算法并记录时间。我问的问题是,这种算法是否尽可能高效,或者有更好的方法吗?

bool recursiveSearch(vector<int> &myList, int beginning, int end)
{
    int mid = (beginning + end) / 2;

    if (myList[beginning] == beginning) //check if the vector at "beginning" is
    {                                      //equal to the value of "beginning"
        return true;
    }

    else if (beginning == end) //when this is true, the recursive loop ends.
    {                          //when passed into the method: end = size - 1
        return false;
    }

    else
    {
        return (recursiveSearch(myList, beginning, mid) || recursiveSearch(myList, mid + 1, end));
    }

}

编辑:列表在传入之前已预先订购,并在main中进行检查以确保开头和结尾都存在

4 个答案:

答案 0 :(得分:1)

一种可能的“改进”是不通过传递引用来复制每次递归中的向量:

bool recursiveSearch(const vector<int>& myList, int beginning, int end)

答案 1 :(得分:1)

除非你对数据的排序有所了解,否则执行像这样的分区搜索绝对没有优势。

实际上,您的代码实际上是在尝试进行线性搜索,因此实际上它实现了一个简单的for循环,并且需要大量的堆栈和开销。

请注意,您的代码有一种奇怪之处:如果第一个元素不匹配,您将调用recursiveSearch(myList, beginning /*=0*/, mid)。由于我们已经知道元素0不匹配,因此您将再次细分,但仅在重新测试元素之后。

所以给定一个没有匹配的6个元素的向量,你将打电话给:

  

recursiveSearch(myList,0,6);    - &GT; &LT; recursiveSearch(myList,0,3)|| recursiveSearch(myList,4,6); &GT;    - &GT; &LT; recursiveSearch(myList,0,1)|| recursiveSearch(2,3)&gt; &LT; recursiveSearch(myList,4,5); || recursiveSearch(myList,5,6); &GT;    - &GT; &LT; recursiveSearch(myList,0,0)|| recursiveSearch(myList,1,1)&gt; &LT; recursiveSearch(myList,2,2)|| recursiveSearch(myList,3,3)&gt; ...

最后,你在给定索引上失败了,因为你达到了开始和结束都是那个值的条件,这似乎是一种消除每个节点的昂贵方法,而最终结果不是分区搜索,它是一个简单的线性搜索,你只需要使用大量的堆栈深度来实现目标。

因此,更简单,更快捷的方法是:

for (size_t i = beginning; i < end; ++i) {
    if (myList[i] != i)
        continue;
    return i;
}

由于我们在这里尝试优化,值得指出MSVC,GCC和Clang都假设if表达了可能的情况,所以我在这里针对我们有一个大的退化情况进行优化矢量没有或迟到的比赛。如果我们很幸运并且我们很早就找到了结果,那么我们愿意支付潜在分支机构的费用,因为我们要离开。我意识到分支缓存很快就会为我们解决这个问题,但是再次 - 优化;-P

正如其他人所指出的,你也可以从不按值传递矢量(强制复制)中受益

const std::vector<int>& myList

答案 2 :(得分:0)

显而易见的“改进”是在所有剩余核心上运行线程。只需将vector分成number of cores - 1块,然后使用条件变量在发现主线程时发出信号。

答案 3 :(得分:0)

如果您需要在未排序的数组中找到A[i] == i的元素,那么唯一的方法就是遍历每个元素,直到找到它为止。

最简单的方法是:

bool find_index_matching_value(const std::vector<int>& v)
{
    for (int i=0; i < v.size(); i++) {
        if (v[i] == i)
            return true;
    }
    return false; // no such element
}

这是O(n),你不可能在算法上做得更好。因此,我们必须将注意力转向微观优化。

总的来说,如果在现代机器上,你的递归解决方案比上面的简单解决方案更快,我会非常惊讶。虽然编译器(可能)能够删除额外的函数调用开销(有效地将递归解决方案转换为迭代解决方案),但按顺序运行数组(如上所述)可以最佳地使用缓存,而对于大型缓存数组,你的分区搜索不会。