【问题标题】:Divide and Conquer array algorithm ++分治数组算法++
【发布时间】:2012-10-28 09:09:33
【问题描述】:

我正在尝试实现一个函数,该函数将查看数组的每个元素并确定该特定元素是否大于一个 INT 而小于另一个 INT。例如:

Return true if Arr[5] is >i && < u

我将此作为基本算法,它有效,但我想通过使用“分而治之”方法创建一段更高效的代码,但是我在使用递归使其计数和所有示例时遇到问题我见过只处理一个比较点,而不是两个。任何人都可以对这种情况有所了解。 (http://en.wikipedia.org/wiki/Divide_and_conquer_algorithm)

我的原始代码(线性):

int SimpleSort(int length) 
{ 
    int A[] = {25,5,20,10,50}; 
    int i = 25; //Less Than int 
    u = 2; //Greater Than 
    for(int Count = 0; Count < length; Count++) //Counter 
    { 
        if (A[Count] <= i && A[Count] >= u) //Checker 
            return true; 
    } return false;
}

到目前为止,我从中收集到的示例代码(经过数小时的各种工作并使用不同的示例代码后没有运气:

int A[] = {5,10,25,30,50,100,200,500,1000,2000};
int i = 10; //Less Than
int u = 5;  //Greater Than


int min = 1;
int max = length;
int mid = (min+max)/2;

if (i < A[mid] && u > A[mid])
{
    min = mid + 1;

}
else
{
    max = mid - 1;
}
Until i <= A1[mid] && u >= A1[mid])

如果这个问题不清楚,对不起,请问您是否需要我详细说明。

【问题讨论】:

  • 您想确定是否存在至少一个值在区间(i,u) 中?请注意,您的 i &gt; u 无法正常工作!
  • 这是一个糟糕的解释,我很抱歉,我将粘贴此代码的简单版本的答案,我正在尝试创建一个分而治之的版本
  • 我正在尝试将我之前提到的方法应用于此,以提高其对较大数组的效率 int SimpleSort(int length) { int A[] = {25,5,20,10, 50};诠释 i = 25; //小于 int u = 2; //大于 for(int Count = 0; Count = u) //Checker { return true; } } 返回错误;
  • 对不起,我没有代表回答我自己的问题....所以它必须去这里。这是我正在尝试改进的代码的简单版本。
  • 您是否假设输入列表中只有一个值符合必要条件,即。对于您提供的任何给定的 (u,i),至多有一个 n 满足 (u

标签: c++ algorithm divide-and-conquer


【解决方案1】:

假设您的输入向量是始终排序的,我认为这样的事情可能对您有用。这是我能想到的最简单的形式,性能是 O(log n):

bool inRange(int lval, int uval, int ar[], size_t n)
{
    if (0 == n)
        return false;

    size_t mid = n/2;
    if (ar[mid] >= std::min(lval,uval))
    {
        if (ar[mid] <= std::max(lval,uval))
            return true;
        return inRange(lval, uval, ar, mid);
    }
    return inRange(lval, uval, ar+mid+1, n-mid-1);
}

这使用隐含的范围差分;即它总是使用两个值中的较低者作为下限,并将两者中的较高者作为上限。如果您的使用要求 lvaluval 的输入值被视为福音,那么 any 调用 where lval &gt; uval 应该返回 false(因为这是不可能的),您可以删除std::min()std::max() 扩展。在任何一种情况下,您都可以通过制作外部前端加载器并预先检查 lvaluval 的顺序来进一步提高性能(a)如果需要绝对排序和 lval &gt; uval,则立即返回为 false,或者(b) 如果需要范围差异,则以适当的顺序预先确定 lval 和 uval。下面探讨了这两种外包装的示例:

// search for any ar[i] such that (lval <= ar[i] <= uval)
//  assumes ar[] is sorted, and (lval <= uval).
bool inRange_(int lval, int uval, int ar[], size_t n)
{
    if (0 == n)
        return false;

    size_t mid = n/2;
    if (ar[mid] >= lval)
    {
        if (ar[mid] <= uval)
            return true;
        return inRange_(lval, uval, ar, mid);
    }
    return inRange_(lval, uval, ar+mid+1, n-mid-1);
}

// use lval and uval as an hard range of [lval,uval].
//  i.e. short-circuit the impossible case of lower-bound
//  being greater than upper-bound.
bool inRangeAbs(int lval, int uval, int ar[], size_t n)
{
    if (lval > uval)
        return false;
    return inRange_(lval, uval, ar, n);
}

// use lval and uval as un-ordered limits. i.e always use either
// [lval,uval] or [uval,lval], depending on their values.
bool inRange(int lval, int uval, int ar[], size_t n)
{
    return inRange_(std::min(lval,uval), std::max(lval,uval), ar, n);
}

我把我认为你想要的那个留给了inRange。为希望涵盖主要和边缘情况而执行的单元测试以及结果输出如下所示。

#include <iostream>
#include <algorithm>
#include <vector>
#include <iomanip>
#include <iterator>

int main(int argc, char *argv[])
{
    int A[] = {5,10,25,30,50,100,200,500,1000,2000};
    size_t ALen = sizeof(A)/sizeof(A[0]);
    srand((unsigned int)time(NULL));

    // inner boundary tests (should all answer true)
    cout << inRange(5, 25, A, ALen) << endl;
    cout << inRange(1800, 2000, A, ALen) << endl;

    // limit tests (should all answer true)
    cout << inRange(0, 5, A, ALen) << endl;
    cout << inRange(2000, 3000, A, ALen) << endl;

    // midrange tests. (should all answer true)
    cout << inRange(26, 31, A, ALen) << endl;
    cout << inRange(99, 201, A, ALen) << endl;
    cout << inRange(6, 10, A, ALen) << endl;
    cout << inRange(501, 1500, A, ALen) << endl;

    // identity tests. (should all answer true)
    cout << inRange(5, 5, A, ALen) << endl;
    cout << inRange(25, 25, A, ALen) << endl;
    cout << inRange(100, 100, A, ALen) << endl;
    cout << inRange(1000, 1000, A, ALen) << endl;

    // test single-element top-and-bottom cases
    cout << inRange(0,5,A,1) << endl;
    cout << inRange(5,5,A,1) << endl;

    // oo-range tests (should all answer false)
    cout << inRange(1, 4, A, ALen) << endl;
    cout << inRange(2001, 2500, A, ALen) << endl;
    cout << inRange(1, 1, A, 0) << endl;

    // performance on LARGE arrays.
    const size_t N = 2000000;
    cout << "Building array of " << N << " random values." << endl;
    std::vector<int> bigv;
    generate_n(back_inserter(bigv), N, rand);

    // sort the array
    cout << "Sorting array of " << N << " random values." << endl;
    std::sort(bigv.begin(), bigv.end());

    cout << "Running " << N << " identity searches..." << endl;
    for (int i=1;i<N; i++)
        if (!inRange(bigv[i-1],bigv[i],&bigv[0],N))
        {
            cout << "Error: could not find value in range [" << bigv[i-1] << ',' << bigv[i] << "]" << endl;
            break;
        };
    cout << "Finished" << endl;

    return 0;
}

输出结果:

1
1
1
1
1
1
1
1
1
1
1
1
1
1
0
0
0
Sorting array of 2000000 random values.
Running 2000000 identity searches...
Finished

【讨论】:

  • 恭喜,你得到了一个非终止递归;)
  • 不仅限于@bitmask。如果这里有一个无限案例,我真的很想知道我错过了什么。我的递归有点生疏,这也是我提供测试用例的原因。
  • 抱歉,我误读了一个条件,这不是无限递归,但您仍然会超出空数组的数组边界。一个小问题。
  • @bitmask 啊。好的。我很喜欢wth?我以为我把他们都解释了。你是对的,没有零案例。应该在进入时考虑到这一点。谢谢。
  • @bitmask 感谢您发现零长度 A[] 的情况。它允许删除两个三级检查。非常赞赏。就像我说的;生锈的=P
【解决方案2】:

如果您假设要对数组进行排序,这实际上非常简单。您可以通过始终查看序列的左侧或右侧来避免对数复杂性:

#include <iterator>

template <typename Limit, typename Iterator>
bool inRange(Limit lowerBound, Limit upperBound, Iterator begin, Iterator end) {
  if (begin == end) // no values => no valid values
    return false;
  Iterator mid = begin;
  auto const dist = std::distance(begin,end);
  std::advance(mid,dist/2); // mid might be equal to begin, if dist == 1
  if (lowerBound < *mid && *mid < upperBound)
    return true;
  if (dist == 1) // if mid is invalid and there is only mid, there is no value
    return false;
  if (*mid > upperBound)
    return inRange(lowerBound, upperBound, begin, mid);
  std::advance(mid,1); // we already know mid is invalid
  return inRange(lowerBound, upperBound, mid, end);
}

您可以通过以下方式为普通数组调用它:

inRange(2,25,std::begin(A),std::end(A));

【讨论】:

  • 感谢您的回复,我的 c++ 编译器不喜欢这个,而且它比我目前正在做的要先进得多。不过,我了解您所写内容的基本知识,我会看看我能适应什么,谢谢您的回复!
  • @ArronFitt:您必须使用 C++11 支持进行编译。如果您使用g++clang++,您可以通过在命令行发出-std=c++0x 来执行此操作。对 Windows 的东西一无所知。
  • @bitmask 不是只有std::beginstd::end的使用(使用AA+sizeof(A)/sizeof(A[0])很容易模仿)需要C++11吗?跨度>
  • @ChristianRau:你的意思是除了auto关键字?
  • @bitmask 对,忽略了这一点。好吧,模仿起来不太方便。必须改用typename std::iterator_traits&lt;Iterator&gt;::difference_type
【解决方案3】:

据我了解,针对您的具体问题使用分而治之 不会产生优势。但是,至少在您的示例中,输入是 排序;应该可以通过跳过值直到达到下限来提高一点。

【讨论】:

  • 好的,你能解释一下我应该怎么做吗?提前致谢
猜你喜欢
  • 1970-01-01
  • 2014-12-08
  • 2013-02-12
  • 2020-08-02
  • 2011-12-31
  • 2018-08-12
  • 2020-01-30
  • 2021-05-06
  • 2017-04-07
相关资源
最近更新 更多