2D数组仅包含0或1

时间:2014-10-22 11:26:29

标签: c arrays

我有一个二维数组,随机包含0或1的值。

我如何(最有效地)确定值1(最大行迭代i)和最右边元素(最高列迭代j)的最低元素?

例如:

 0  0  1  0 
 1  0  1  0 
 0  1  0  0 
 1  0  0  0

我的程序应该回答 i = 3 假设第一行是i = 0 )和 j = 2 首先假设列为0 )。

4 个答案:

答案 0 :(得分:3)

这是一个想法:

  1. 从最底部的行开始,使用memrchr查找每行中的最后一个1(我假设您将数字存储为char,而不是{8}}位整数)。
  2. 最终您会找到一行1。这是i的答案。我们使用缓存友好的一次一行操作来实现这一点,因为C使用行主要顺序。
  3. 上面,您现在也知道j的下限(因为您在最后一行找到了1的最后一个1
  4. 对于剩余的行,请使用memrchrj的下限开始到每行的末尾。如果您在那里找到任何1,请更新下限。重复,直到您检查了所有行。
  5. 当然,如果你在最后一栏找到1,你可以立即停止。

答案 1 :(得分:1)

使用普通循环,只需从头开始(或结束,根据您想要实现的目标)进行搜索,并检查每个元素。没有更有效的方法。

就C和C ++而言,实现的本质是什么是有效的,什么不是。例如,如果这是一个位字段矩阵,那么在开始搜索各个位之前,首先要将每个字节与0进行比较,然后稍微优化代码。

和往常一样,谈论效率而没有明确其含义是没有意义的。速度?内存消耗?程序大小?在没有给定系统的情况下谈论C或C ++中的有效实现也没有意义。

答案 2 :(得分:1)

这是天真的方法 - 只是遍历数组中的所有位置。最坏情况O(n * m):

#define WIDTH  4
#define HEIGHT 4

int main ()
{
    int i,j,col,row;
    int arr[HEIGHT][WIDTH] = set_Array();
    for (j=0;j<HEIGHT;j++){
        for (i = 0; i<WIDTH; i++){
            if (arr[j][i]){
                row = j>row?j:row;
                col = i>col?i:col;
    }}}
}

我们如何改善这一点?好吧,我们可以从最后开始并向后工作,但我们必须交替进行行和列,而不是依次访问每个单元格。我们可以查找列,然后排,但效率会降低。

   0. 1. 2. 3.
0. 0  0  1  0 
1. 1  0  1  0
2. 0  1  0  0
3. 1  0  0  0

在此示例中,我们首先搜索行3和列3,然后从搜索中删除它们。然后行2和列2最多但不包括已删除的列3和行3。然后排1 ...
当然,我们会在找到包含1的最底层的行时停止搜索行,并在找到包含1的最右边的列时停止搜索列。

代码:

#include <stdio.h>

#define WIDTH  4
#define HEIGHT 4

int main ()
{
    int i,j,col = 0, row = 0;
    int current_row = HEIGHT;
    int current_col = WIDTH;
    int arr[WIDTH][HEIGHT] = {{0,0,1,0},{1,0,1,0},{0,1,0,0},{1,0,0,0}};
    while (!(row && col))
    {
         current_row--;
         current_col--;
         if (!row){
             printf("searching row: %d\n",current_row);
             for (i = 0; i < current_col; i++){
                 if (arr[current_row][i]){
                      row = current_row;
         }}}
         if (!col){
             printf("searching col: %d\n",current_col);
             for (j = 0; j < current_row; j++){
                 if (arr[j][current_col]){
                     col = current_col;
         }}}
    }
    printf("col: %d, row: %d\n", col, row);
}

See it live

输出:

searching row: 3
searching col: 3
searching col: 2
col: 2, row: 3

最坏的情况仍然是O(m * n),实际上稍微差一点(从右下角开始两次测试对角线上的细胞),但平均情况更好。

我们浏览1的最低未搜索行,然后在最右边的未搜索列中搜索1
当您找到最低1时,您不再搜索每一行以获得更多1。当您找到最右侧的1时,您不再搜索每个列以获得更多1

这样我们就可以在找到答案后停止搜索,与天真的方法不同,这意味着我们通常不必遍历数组中的每个值。

答案 3 :(得分:0)

如果数组的行大小最多为32个数字,则可以使用单个int32_t来表示整行:数字的值是整行。 然后你的整个数组将是int32_t的一维数组:

int32_t matrix[nRows];

现在,您可以通过在O(nRows)时间内找到不等于0的matrix的最后一个数字来找到最下面的行,并且实现非常简单。

此外,你可以通过以下技巧找到最右边的1: 对于每个matrix[i],您通过计算matrix[i] & -matrix[i]来隔离最右边的1。然后计算此结果的log2将为您提供列数。所有matrix[i]数字的最大列数可为您提供所需的结果。 (同样是O(nRows)时间,实现非常简单)。

当然,如果行大小超过32个值,则每行必须使用更多int32_t个值,但原则保持不变。