我需要找到一个替代递归来解决这个问题

时间:2021-03-19 15:10:54

标签: c algorithm multidimensional-array

注意:我更喜欢c语言的算法或代码,提前谢谢。

假设我有一个 5x5 的二​​维数组。

00, 00, 01, 01, 00 
01, 00, 01, 01, 00 
01, 00, 00, 01, 01 
01, 01, 00, 00, 00 
01, 00, 00, 01, 01

分组标准 :- 阵列中所有从上、下、左、右或对角线相互连接的1(01)属于同一组。

现在,我想不递归地将所有 1 (01) 组合在一起,使我的数组看起来像:-

00, 00, 02, 02, 00 
01, 00, 02, 02, 00 
01, 00, 00, 02, 02 
01, 01, 00, 00, 00 
01, 00, 00, 03, 03

最后我输出有多少组。在这里,我输出 3。

假设我从一个索引位置找到连接,假设我在 i=1 和 j=0。 现在使用嵌套循环,我可以找到我所在位置的所有连接。

for(int i=-1; i<2; i++){
    for(int j=-1; j<2; j++){
}}

但是我如何从一个连接中找到连接呢?假设我找到了来自 i=1, j=0 的所有连接。如果我在 i=1,j=1 处找到了 1,那么我如何再次继续搜索?这里的递归看起来很简单,但我应该如何在没有递归的情况下做到这一点?

这是我目前所拥有的。我没有时间限制,所以我这样做很愚蠢。

void printImgArray(int array[L][L])
{
  
    printf("------ Image Contents -------\n");
    int i, j;
    for (i=0; i<L; i++)
    {
    for (j=0; j<L; j++)
        printf("%02d, ",array[i][j]);
    printf("\n");
    }
    printf("-----------------------------\n");
}

int checkIndex(int i, int j){
    return i >= 0 && j>=0 && i< L && j< L;
}

int colorNonRecursively(int image[L][L]) {
  int copyArray[L][L] = {0};
  int i, j, new_i, new_j;
  int counter = 1;

  for(i=0; i<L; i++){
    for(j=0; j<L; j++){
      for(new_i=-1; new_i<2; new_i++){
        for(new_j=-1; new_j<2; new_j++){
          if(copyArray[i][j] != 1 && image[i][j] != 0){
            copyArray[i][j] = 1;
            image[i][j] = counter;

            if(checkIndex(i+new_i, j+new_j)){
              if(copyArray[i+new_i][j+new_j] != 1 &&
                image[i+new_i][j+new_j] != 0){
                copyArray[i+new_i][j+new_j] = 1;
                image[i+new_i][j+new_j] = counter;
              }
            }
          }
        }
      }
      counter++;
    }
  }

int main(){

    int cellImg[L][L]={{0,0,1,1,0},\
                     {1,0,1,1,0},\
                     {1,0,0,1,1},\
                     {1,1,0,0,0},\
                     {1,0,0,1,1}};
    printImgArray(cellImg);
    colorNonRecursively(cellImg);
    printImgArray(cellImg);
    return 0;
}

输入二维数组:-

00, 00, 01, 01, 00 
01, 00, 01, 01, 00 
01, 00, 00, 01, 01 
01, 01, 00, 00, 00 
01, 00, 00, 01, 01

输出二维数组:-

00, 00, 03, 04, 00 
06, 00, 08, 09, 00 
11, 00, 00, 14, 15 
16, 17, 00, 00, 00 
21, 00, 00, 24, 25 

在这里我可以看到我的计数器放置在正确的位置,但分组没有正确完成。我知道这段代码的运行时间为 N^4,但在我的情况下这无关紧要,所以请忽略它。 我如何正确地将这些分组以便我将此数组作为输出?

输出二维数组(应该是):-

00, 00, 02, 02, 00, 
01, 00, 02, 02, 00, 
01, 00, 00, 02, 02, 
01, 01, 00, 00, 00, 
01, 00, 00, 03, 03, 

3 个答案:

答案 0 :(得分:2)

您可以创建该数组的图形表示,这样 1 是节点,边是相邻的 1。之后,您可以对这些节点进行 DFS 搜索,并将它们标记为已完成的 DFS 搜索。因此,如果是第一次 DFS 搜索,则标签为 1,如果是第二次 DFS/BFS 搜索,则为 2,依此类推。请注意,DFS/BFS 搜索的数量是连接组件的数量。这样你就有了一个带有你想要的标签的图表。之后,您可以根据需要将图形转换为数组。这也可以扩展到 n 维。您可以使用迭代方法进行图搜索。

答案 1 :(得分:2)

使用愚蠢的迭代和数据结构:

构建坐标集列表(数组中的索引):List<Set<Pair<Integer,Integer>>>List<Set<Integer[]>>

在第一轮中,为列表中每个值为 1 的数组元素添加一个 Set。

在下一次迭代中循环遍历集合并检查 2 是否可以加入(更多循环)。删除 2 个集合并添加连接的集合。下一次迭代。

如果列表不再更改,您准备好组列表。

实施会很有趣,但我认为您想尝试一下...

我是对的,这很有趣(对不起,Java,但没有流):

public class Groups
{

    public static void main(String[] args)
    {
        Integer[][] table = {
                    {00, 00, 01, 01, 00},
                    {01, 00, 01, 01, 00},
                    {01, 00, 00, 01, 01},
                    {01, 01, 00, 00, 00},
                    {01, 00, 00, 01, 01},
                };

        List<Set<Integer[]>> groups = createInitial(table);

        groups = findgroups(groups);
        print(table,groups);
    }

    private static void print(Integer[][] table, List<Set<Integer[]>> groups)
    {
        int groupid = 0;
        for (Set<Integer[]> group : groups) {
            groupid++;
            for (Integer[] element : group) {
                table[element[0]][element[1]] = groupid;
            }
        }
        for (int i = 0; i < table.length; i ++) {
            for (int j = 0; j < table[i].length; j ++) {
                System.out.print(table[i][j]+ " ");
            }
            System.out.println();
        }

    }

    private static List<Set<Integer[]>> findgroups(List<Set<Integer[]>> groups)
    {
        int before;
        int after;
        do {
            before = groups.size();
            join(groups);
            after = groups.size();

        } while (before != after);
        return groups;
    }

    private static void join(List<Set<Integer[]>> groups)
    {
        for (int i = 0; i < groups.size(); i++) {
            for (int j = i+1; j < groups.size(); j++) {
                if (joins(groups.get(i),groups.get(j))) {
                    groups.get(i).addAll(groups.get(j)); // the joined group
                    groups.remove(j);                    // delete the other 
                    return;
                }
            }
        }
    }

    private static boolean joins(Set<Integer[]> group1, Set<Integer[]> group2)
    {
        for (Integer[] element1 : group1) {
            for (Integer[] element2 : group2) {
                if (adjacent(element1,element2)) {
                    return true;
                }
            }
        }
        return false;

    }

    private static boolean adjacent(Integer[] element1, Integer[] element2)
    {
        return ((Math.abs(element1[0] - element2[0]) < 2) && (Math.abs(element1[1] - element2[1]) < 2));
    }

    private static List<Set<Integer[]>> createInitial(Integer[][] table)
    {
        List<Set<Integer[]>> init = new ArrayList<>();
        for (int i = 0; i < table.length; i ++) {
            for (int j = 0; j < table[i].length; j ++) {
                if (table[i] [j] > 0) {
                    Set<Integer[]> single = new HashSet<>();
                    Integer[] element = {i,j};
                    single.add(element);
                    init.add(single);
                }
            }
        }
        return init;
    }

}

输出:

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

答案 2 :(得分:1)

循环遍历你的二维数组,每次遇到 1 并且索引未被访问时,运行 bfs。

在 bfs 期间,记住您已经访问过哪些索引(通过 bfs 或主循环)。这可以通过布尔数组来完成。

以下是一些c++代码。可以找到队列的 C 实现here

from multipledispatch import dispatch

@dispatch(int, int)
def add(x, y):
    ...

@dispatch(str, str)
def add(x, y):
    ...