【问题标题】:I need to find an alternate for recursion to solve this problem我需要找到一个替代递归来解决这个问题
【发布时间】:2021-06-17 00:22:10
【问题描述】:

注意:我更喜欢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, 

【问题讨论】:

  • 您能详细解释一下分组是如何进行的吗?第一列中的01 怎么没有分组。我无法理解它。
  • 01 表示 1。1 和 0 用 2 个数字表示。 0 = 00 和 1 = 01。因此,只要任何 1 在其右左上或对角线处有另一个 1,它就会被计入同一组。我们会重新检查每一个连接的人及其周围环境。

标签: c algorithm multidimensional-array


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    构建坐标集列表(数组中的索引):List&lt;Set&lt;Pair&lt;Integer,Integer&gt;&gt;&gt;List&lt;Set&lt;Integer[]&gt;&gt;

    在第一轮中,为列表中每个带有 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 
    

    【讨论】:

    • @DavidRanieri 问题被标记为 C,但提到 java 就足够了。它(还)不是真正的代码,而是一个公式化的算法
    • 感谢java中的这个算法。我仍然更喜欢 c 而不是这个,因为它对我来说翻译有点复杂,但我正在努力!
    • @Nzed 发表你的努力,我会尽力提供帮助,在过去的 25 年里没有编程 C...
    【解决方案3】:

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

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

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

    #include<stdio.h>
    #include<queue>
    
    int arr[5][5] = {
        {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},
    };
    
    int output[5][5];
    
    // two arrays that help with directions
    int dx[8] = {-1, -1, -1, 0, 1, 1, 1, 0},
        dy[8] = {1, 0, -1, 1, 1, 0, -1, -1};
    
    int vis[5][5];
    
    int count = 1;
    
    std::queue<int> qx, qy;
    
    void bfs(int x, int y){
        // start bfs my pushing starting position into respective queues
        // and marking starting position as visited
        qx.push(x); qy.push(y);
        vis[x][y] = 1;
        output[x][y] = count;
    
        // loop until queue is empty
        while (!qx.empty()){
            int cur_x = qx.front(), cur_y = qy.front();
            qx.pop(); qy.pop();
    
            // loop 0..8, for 8 directions
            for (int i=0; i<8; i++){
    
                // make sure next node fits constraints
                if (cur_x + dx[i] >= 0 && cur_x + dx[i] < 5){
                    if (cur_y + dy[i] >= 0 && cur_y + dy[i] < 5){
    
                        // check if next node has not been visited
                        // and its position in arr is 1
                        if (vis[ cur_x + dx[i] ][ cur_y + dy[i] ] == 0 &&
                            arr[ cur_x + dx[i] ][ cur_y + dy[i] ] == 1){
    
                            // mark next node as visited
                            // and push into queue
                            vis[ cur_x + dx[i] ][ cur_y + dy[i] ] = 1;
                            qx.push(cur_x + dx[i]);
                            qy.push(cur_y + dy[i]);
                            output[ cur_x + dx[i] ][ cur_y + dy[i] ] = count;
                        }
                    }
                }
            }
        }
    }
    int main(){
        for (int i=0; i<5; i++){
            for (int j=0; j<5; j++){
                if (arr[i][j] == 1 && vis[i][j] == 0){
                    // bfs will fill one "section"
                    bfs(i, j);
                    count++;
                }
            }
        }
    
        // print output
        for (int i=0; i<5; i++){
            for (int j=0; j<5; j++){
                printf("%d ", output[i][j]);
            }
            printf("\n");
        }
        // printf("%d\n", count);
    }
    

    【讨论】:

    • 你愿意在c语言中添加一个代码sn-p吗?我知道如何在这里使用 BFS,但一些代码会非常有帮助。在此先感谢:)
    • 我对c不是最熟悉的,但是我在c++中添加了一些代码。希望对您有所帮助!
    • 帮助很大。我在 c 中实现了一个数组实现并且它有效。谢谢你的帮助,我真的很感激:)
    • @Nzed 但请注意,这是变相的递归。您使用自己的堆栈而不是调用堆栈(伪装成数组)...
    • @Turo 队列与堆栈非常不同,这就是 bfs 与 dfs 不同的原因。
    猜你喜欢
    • 2020-08-06
    • 1970-01-01
    • 1970-01-01
    • 2016-02-13
    • 2021-07-04
    • 1970-01-01
    • 2021-01-11
    • 1970-01-01
    • 2020-03-26
    相关资源
    最近更新 更多