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

    假设以二维数组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

原文地址:https://www.cnblogs.com/cposture/p/4487417.html