• 【原创】颜色替换的递归算法


        假设以二维数组g[1..m][1..n]表示一个图像区域,g[i][j]表示该区域中点(i,j)所具颜色,其值为从0到k的整数。试编写递归算法,将点(i0,j0)所在区域的颜色置换为颜色c。约定与(i0,j0)同色的上、下、左、右的邻接点为同色区域的点。
    表示图像区域的类型定义如下:
    /* 在g[1..m][1..n]中,将元素g[i0][j0] */
    /* 所在的同色区域的颜色置换为颜色c */
    typedef char GTYPE[m+1][n+1];
     
     1     voidChangeColor(GTYPE g,int m,int n,char c,int i0,int j0)
     2     {
     3         char temp;
     4      
     5         //判断是否在合法区域内    
     6         if(i0 <1|| i0 > m || j0 <1|| j0 > n)
     7             return;
     8      
     9         //防止进入死递归
    10         temp = g[i0][j0];
    11         if(c == temp)
    12             return;
    13 14           g[i0][j0]= c; 
    15           //依次判断上、下、左、右点
    16         if(i0 -1>=1&& g[i0-1][j0]== temp)
    17             ChangeColor(g,m,n,c,i0-1,j0);
    18         if(i0 +1<= m && g[i0+1][j0]== temp)
    19             ChangeColor(g,m,n,c,i0+1,j0);
    20         if(j0 -1>=1&& g[i0][j0-1]== temp)
    21             ChangeColor(g,m,n,c,i0,j0-1);
    22         if(j0+1<= n && g[i0][j0+1]== temp)
    23             ChangeColor(g,m,n,c,i0,j0+1);
    24     }
     
     
    思路:总体思路是先替换再查找。从指定的点开始,先保存该点的颜色值temp再替换成c颜色值;然后再分别判断区域内上下左右的颜色值是否等于temp,如果等于,则利用相同的方法,递归地判断下一个点;直到所有符合要求的点被替换成c颜色值为止。
     
        有些读者会提出:可不可以把替换颜色值的操作放在其中一个if语句之后,也就是让函数先查找下一个点,再替换指定点的颜色值?
     
        我们假设将替换颜色值的语句放在最后一个if之后(其他情况类似),代码如下
     1     voidChangeColor(GTYPE g,int m,int n,char c,int i0,int j0)
     2     {
     3         char temp;
     4      
     5         //判断是否在合法区域内    
     6         if(i0 <1|| i0 > m || j0 <1|| j0 > n)
     7             return;
     8      
     9         //防止进入死递归
    10         temp = g[i0][j0];
    11         if(c == temp)
    12             return;
    13      
    14         //依次判断上、下、左、右点
    15         if(i0 -1>=1&& g[i0-1][j0]== temp)
    16             ChangeColor(g,m,n,c,i0-1,j0);
    17         if(i0 +1<= m && g[i0+1][j0]== temp)
    18             ChangeColor(g,m,n,c,i0+1,j0);
    19         if(j0 -1>=1&& g[i0][j0-1]== temp)
    20             ChangeColor(g,m,n,c,i0,j0-1);
    21         if(j0+1<= n && g[i0][j0+1]== temp)
    22             ChangeColor(g,m,n,c,i0,j0+1);
    23      
    24         g[i0][j0]= c;
    25     }
     
        我们知道函数每调用一次都会将函数实参、函数里的局部变量都压栈保存,所以当你调用ChangeColor函数时都会在栈中保存g(二维函数指针,占4个字节)、数组范围m和n、替换的颜色值c、指定点坐标i0和j0以及函数里的局部变量temp;而且每个函数栈在一般情况下都是独立、互不影响的,这样才能保证函数的正常运行。
     
        当我们调用ChangeColor(g,6,4,2,4,3)想要将(4,3)点同色区域替换成颜色值2时,此时会将函数的实参和局部变量temp压栈,我们简单用(4,3)表示。根据函数代码,会先查找指定点的上面的点(3,3),因为(3,3)颜色值为1,将(3,3)压栈,继续在(3,3)指定点的基础上查找上面的点,此时该点颜色值为0不符合;接下来指定点(3,3)会继续查找下面的点,此时由于(4,3)的颜色值为1,还没被替换为颜色值2,符合替换要求,将(4,3)压栈,那么问题来了,兜了一圈又回到了原来的点,这样便会无限地递归下去。因为栈的空间是有限的,每次函数调用都会压栈,从而出现栈溢出。
     
        当一个点跳到另一个点之前没被替换,而跳回来时也没改变便会进入死递归中,直到栈溢出发生错误,所以需要在所有跳转之前,执行颜色值替换操作。
     
        细心的读者可能会问:如果替换的颜色值c和开始指定点的颜色一样,那会发生什么?
     
     毫无疑问是死递归最后栈溢出。上面已经说过为了防止“一个点跳到另一个点之前没被替换,而跳回来时也没改变”这种情况,需要在所有跳转之前,执行颜色值替换操作。但是此时替换的颜色值和指定点的颜色值一样,那根本和没替换没什么区别,当一个点跳到另一个点后,之后也一定会跳回来,从而进入特殊的死递归。
     
        最后通过以上一个简单的递归例子总结一句话:语言再高级,算法不严谨也没用!
     
        延伸阅读:http://www.nowamagic.net/librarys/veda/detail/2314

    本文链接:http://www.cnblogs.com/cposture/p/4487417.html

  • 相关阅读:
    MySQL图形化管理工具之Navicat安装以及激活
    切换路由时取消全部或者部分axios请求,并将一些从不需要取消的加入白名单
    使用node-static运行vue打包文件dist
    elementUI使用本地变量进行验证,监测不到本地变量的变化 的问题
    vue-cli3打包时webpack优化
    实现两个对象的深度合并
    第一章:操作系统概述
    IDEA 2020.1 安装教程
    常用DOS命令
    Listener:监听器
  • 原文地址:https://www.cnblogs.com/cposture/p/4487417.html
Copyright © 2020-2023  润新知