简体   繁体   English

检查2d数组的所有元素是否相等的最快方法

[英]Fastest method to check if all elements of 2d array are equal

I have a 2d array houses[5][2] = {{1,1},{1,1},{1,1},{1,1},{1,1}} What is the fastest way to check if all the elements inside that array are equal? 我有一个2d数组的houses[5][2] = {{1,1},{1,1},{1,1},{1,1},{1,1}}什么是最快的方法检查该数组中的所有元素是否相等? Here is what I have tried so far: ``` 这是我到目前为止所尝试的:```

for(int j=0;j<5;j++){
 for(int k=0;k<6;k++){
   if(houses[j][k] == houses[j+1][k+1] && j+1 != 5 && k + 1 != 6)
     equal = true;
    else{
     equal = false;
     break;
     }
}
}

This won't compare all the elements tho, I know how to compare all of them, but it seems to be a very long loop .. is there a faster way to do that? 这不会比较所有元素,我知道如何比较所有元素,但它似乎是一个非常长的循环..有更快的方法吗?

Your current code will fail because break will only take you out of one loop. 您当前的代码将失败,因为break只会让您退出一个循环。 You must exit both, which requires a second check, like so: 你必须退出两个,这需要第二次检查,如下所示:

auto the_value = houses[0][0];
bool equal     = true;

for(int j=0;j<5;j++){
  for(int k=0;k<6;k++){
    if(houses[j][k]!=the_value){
      equal = false;
      goto done;
    }
  }
  if(!equal)
    break
}

(Storing the first element in a variable and then looping over all of the elements to check to see if they are equal to that variable obviates the mess you invoke by checking adjacent elements.) (将第一个元素存储在变量中,然后循环遍历所有元素以检查它们是否等于该变量,通过检查相邻元素来避免调用的混乱。)

Breaking out of both loops simultaneously requires the Dark Arts ( goto ), but may be more readable/maintainable if you are disciplined and may be slightly faster, depending on your compiler: 同时打破两个循环需要黑暗艺术( goto ),但如果你受到纪律处分可能更具可读性/可维护性,并且可能稍快一些,具体取决于你的编译器:

auto the_value = houses[0][0];
bool equal     = true;

for(int j=0;j<5;j++)
for(int k=0;k<6;k++)
  if(houses[j][k]!=the_value){
    equal = false;
    goto done; //Danger, Will Robinson!
  }

done:
//More stuff

You may find a flat array to be faster: 您可能会发现平面阵列更快:

auto the_value = houses[0][0];
bool equal     = true;
for(int i=0;i<5*6;i++)
  if(houses[i]!=the_value){
    equal = false;
    break;
  }

The 2D array is stored as a 1D contiguous array in memory. 2D阵列作为1D连续阵列存储在存储器中。 Using flat array addressing accesses the same memory locations, but explicitly avoids forcing the internal arithmetic. 使用平面阵列寻址访问相同的内存位置,但显式避免强制内部算法。 For highly performant code you may wish to consider using flat arrays by default. 对于高性能代码,您可能希望默认使用平面数组。

Since you might use a function such as this a number of times or have it embedded in otherwise complex code, perhaps you'd like to abstract it: 由于您可能会多次使用此类函数或将其嵌入到其他复杂代码中,您可能希望将其抽象化:

template<class T>
bool AllEqual(const T& arr, size_t N){
  T the_value = arr[0];
  for(int i=0;i<N;i++)
    if(arr[i]!=the_value)
      return false;
  return true;
}

AllEqual(houses, 5*6);

Since you're coding in C++, you probably don't want to be using raw arrays anyway. 由于您使用C ++进行编码,因此您可能不希望使用原始数组。 Let's rewrite your code using the STL, assuming flat arrays: 让我们使用STL重写您的代码,假设平面数组:

template<class T>
bool AllEqual(const std::vector<T>& arr){
  return std::all_of(arr.begin(), arr.end(), [&](const T& x){ return x==arr[0]; });
}

std::vector<int> houses = {}; //Replace with appropriate initialization
if(AllEqual(houses))
  //Do stuff

(Also: as another answerer mentioned, the way you are adding data to your array seems to imply that it should be 2x6/6x2 array instead of 5x6/6x5.) (另外:正如另一位回答者所提到的,你向阵列添加数据的方式似乎暗示它应该是2x6 / 6x2阵列而不是5x6 / 6x5。)

First, do you understand what your array looks like? 首先,你了解你的阵列是什么样的? You have 6 times of two ones, but you used houses[5][6] . 你有两次6次,但是你用过houses[5][6] That's it 5 rows and 6 columns. 这是5行6列。 You should have gotten an error for that: 你应该得到一个错误:

main.cpp:5:55: error: excess elements in array initializer
    int houses[5][6] = {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}};
                                                      ^~~~~

What you really wanted was 6 rows and 2 columns. 你真正想要的是6行和2列。


As for the way of checking whether all elements of a 2D array are equal, I would follow a simple approach; 至于检查二维阵列的所有元素是否相等的方法,我会采用一种简单的方法; store the first element of your array to a variable, eg named v , and check that value versus all the other elements. 将数组的第一个元素存储到一个变量,例如名为v ,并检查该值与所有其他元素的对比。 If it is not equal to just one element, then it is enough to take a decision and say that not all elements are equal, like in the following example: 如果它不等于只有一个元素,那么就足以做出决定并说并非所有元素都相等,如下例所示:

#include <iostream>

bool allEqual(int arr[][2], int rows)
{
    int v = arr[0][0];
    for(int i = 0; i < rows; ++i)
        for(int j = 0; j < 2; ++j)
            if(v != arr[i][j])
                return false;
    return true;
}

int main(void)
{
    int houses[6][2] = {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}};
    allEqual(houses, 6) ? std::cout << "All " : std::cout << "Not all ";
    std::cout << "elements are equal\n";
    return 0;
}

If I emulate a 2D array with an 1D, will it be faster? 如果我使用1D模拟2D数组,它会更快吗?

I doubt it. 我对此表示怀疑。 They idea is that the memory locations will be contiguous, but this is what happens pretty most in the 2D case, given that the rows are more than the columns. 他们的想法是内存位置是连续的,但这是在2D情况下最常发生的情况,因为行多于列。

Here is my experiment: 这是我的实验:

Georgioss-MacBook-Pro:~ gsamaras$ g++ -Wall -std=c++0x -O3 -o 2d 2d.cpp
Georgioss-MacBook-Pro:~ gsamaras$ ./2d
2D array took 1.48e-10 seconds.
Georgioss-MacBook-Pro:~ gsamaras$ g++ -Wall -std=c++0x -O3 -o 1d 1d.cpp
Georgioss-MacBook-Pro:~ gsamaras$ ./1d
Emulating 2D array with 1D array took 1.5e-10 seconds.

and my code, based on my Time measurements (C++) : 和我的代码,基于我的时间测量(C ++)

#include <iostream>

#define ROWS 10000
#define COLS 20
#define REPEAT 1000

#include <iostream>
#include <ctime>
#include <ratio>
#include <chrono>

bool allEqual(int* arr, const int size)
{
    int v = arr[0];
    for(int i = 0; i < size; ++i)
        if(v != arr[i])
            return false;
    return true;
}

void fill(int* arr, const int size)
{
    for(int i = 0; i < size; ++i)
        arr[i] = 1;
}

int main(void)
{
    const int size = ROWS * COLS;
    int houses[size];
    fill(houses, size);

    bool equal;

    using namespace std::chrono;
    high_resolution_clock::time_point t1 = high_resolution_clock::now();
    for(int i = 0; i < REPEAT; ++i)
        equal = allEqual(houses, size);
    high_resolution_clock::time_point t2 = high_resolution_clock::now();
    duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
    std::cout << "Emulating 2D array with 1D array took " << time_span.count()/(double)REPEAT << " seconds.\n";

    return 0;
}

where the 2d.cpp is the straightforward way. 2d.cpp是直截了当的方式。

Using the equal method provided in this answer for a 2D array, the timings reported are similar. 使用本答案中提供的用于2D阵列的相等方法,报告的时序是相似的。

Moreover, there is std::equal , which is comparable in terms of performance to my code above, reporting a time of: 此外,还有std :: equal ,它在性能方面与我上面的代码相当,报告的时间为:

std::equal with 2D array took 1.63e-10 seconds.

It's complexity is: "Up to linear in the distance between first1 and last1: Compares elements until a mismatch is found." 它的复杂性是:“在first1和last1之间的距离上达到线性:比较元素直到找到不匹配。”


Summary : 摘要

std::equal does OK, and requires the less effort from the programmer, thus use it. std::equal正常,需要程序员减少工作量,因此使用它。

Multiple things: 多件事:

First, as others have pointed out, the line: 首先,正如其他人所指出的那样:

int houses[5][6] = {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}};

Is wrong, the left hand side declares an array with 5 rows and 6 columns, but the right hand side constitutes an array of 6 rows and 2 columns. 错了,左侧声明了一个包含5行和6列的数组,但右侧构成了一个包含6行和2列的数组。

On the general case comparing all elements of a 2d array (or even a 1d array) is in O(n) since for every element you must check all other elements. 在一般情况下,比较2d数组(或甚至是1d数组)的所有元素都在O(n)中,因为对于每个元素,您必须检查所有其他元素。 You can optimize it a little bit but it will still be an O(n) algorithm. 您可以稍微优化它,但它仍然是O(n)算法。 On the most general case: 在最一般的情况下:

A[n][m] is an array of n rows and m columns

for(int i=0; i<n*m; i++)
{
   if(A[0][0] != A[i/n][i%n])
     return false;
}
return true;

This may seem a little bit confusing so let me explain: 这可能看起来有点令人困惑,所以让我解释一下:

a 2d array has n*m elements, so an easy way to see all of them in a single loop is doing [i/n] (if i < n, then it's the first row, if n < i < 2n then it's the second row...) and doing [i%n] gives you the remainder. 一个2d数组有n * m个元素,所以在一个循环中看到所有这些元素的简单方法是做[i / n](如果i <n,那么它是第一行,如果n <i <2n那么它就是第二行......)并且做[i%n]给你余数。 This way we can iterate the entire array in a single loop. 这样我们就可以在一个循环中迭代整个数组。

Since we want all elements to be the same, if the first element is equal to all others then they are ll the same, if at least on is different then they are not all the same. 由于我们希望所有元素都相同,如果第一个元素与所有其他元素相同,那么它们将是相同的,如果至少在不同的情况下它们不是全部相同。

The fastest way: 最快的方法:

int houses[6][2] = {{1,1},{1,1},{1,1},{1,1},{1,1},{1,2}};

int equals()
{
    int *p = (int *)houses;
    int *end = p + 6*2;
    int v = *p++;
    for(; p < end; p++)
        if (*p != v)
            return 0;
    return 1;
}

I wrote it for fun, don't use that in production. 我写它是为了好玩,不要在生产中使用它。 Instead, iterate through them all: 相反,遍历它们全部:

int equals() {
   int v = houses[0][0];
   for(int j=0;j<5;j++)
      for(int k=0;k<6;k++)
         if (houses[i][j] != v)
            return false;
   return true;
}

We can simply way to check if all the elements inside that array are equal or not. 我们可以简单地检查该数组中的所有元素是否相等。 just assign the first row & column element in a variable. 只需在变量中指定第一行和列元素。 Then compare each element. 然后比较每个元素。 If not equal then return false. 如果不相等则返回false。

Code Snippet : 代码片段:


bool Equal(int **arr, int row, int col)
{
   int v = arr[0][0];
   for(int i=0; i<row; i++)
   {
      for(int k=0; k<col; k++)
      {
         if(arr[i][k]!=v)  return false;
      }
   }
   return true;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM