書名:代碼本色:用編程模擬自然系統(tǒng)
作者:Daniel Shiffman
譯者:周晗彬
ISBN:978-7-115-36947-5
第8章目錄
8.3 用遞歸函數(shù)實現(xiàn)康托爾集
接下來罕容,我們要用遞歸函數(shù)實現(xiàn)康托爾集的可視化。從哪里開始长搀?
1袋哼、繪制線段的函數(shù)
- 我們知道康托爾集在開始時是一個線段描孟。因此,我們可以先實現(xiàn)一個用于繪制線段的函數(shù)弓柱。
void cantor(float x, float y, float len) {
line(x,y,x+len,y);
}
- 上面的cantor()函數(shù)在坐標(biāo)(x,y)處開始畫一個線段鼠哥,線段長度是len。
- (假設(shè)線段是水平的)因此露久,如果我們按以下方式調(diào)用cantor()函數(shù):
cantor(10, 20, width-20);
就會得到這條線段
2更米、繼續(xù)繪制下面兩條線段
-
從康托爾規(guī)則中可以看出,我們需要去掉線段中間的1/3毫痕,剩下兩條線段:一條線段從起點到1/3處征峦,另一個條線段從2/3處到終點迟几。
我們要分別繪制這兩條線段。我們沿y軸方向?qū)⑦@兩條線段下移幾個像素栏笆,讓它們顯示在原線段的下方类腮。
void cantor(float x, float y, float len) {
line(x,y,x+len,y);
y += 20;
line(x,y,x+len/3,y); 從起點到1/3處
line(x+len*2/3,y,x+len,y); 從2/3處到終點
}
- 盡管這是一個很好的開始,但重復(fù)地為每個線段調(diào)用line()函數(shù)并不是我們想要的實現(xiàn)方式蛉加。
線段的數(shù)量會很快地增長蚜枢,接下來我們要調(diào)用4次line()函數(shù),再接著是8次针饥,然后是16次……for循環(huán)曾經(jīng)是我們解決此類問題的常用方法厂抽,但嘗試之后你會發(fā)現(xiàn),用循環(huán)的方法解決這個問題是非常復(fù)雜的打厘。 - 在這時候修肠,遞歸就派上用場了,能拯救我們于水火之中户盯。
3嵌施、遞歸實現(xiàn)
- 回顧一下我們?nèi)绾卫L制第一個條線段,也就是從起點到1/3處的線段:
line(x,y,x+len/3,y);
我們可以把這里的line()替換成cantor()函數(shù)莽鸭。因為cantor()函數(shù)本來就會在(x,y)位置畫一條指定長度的線段吗伤!因此:
line(x,y,x+len/3,y); 替換成 -------> cantor(x,y,len/3); - 對于下面的line()函數(shù)調(diào)用,也有:
line(x+len2/3,y,x+len,y); 替換成 -------> cantor(x+len2/3,y,len/3); - 于是硫眨,我們就有了以下代碼:
void cantor(float x, float y, float len) {
line(x,y,x+len,y);
y += 20;
cantor(x,y,len/3);
cantor(x+len*2/3,y,len/3);
}
4足淆、退出條件
- 由于cantor()函數(shù)是遞歸調(diào)用的,在調(diào)用過程中礁阁,同樣的規(guī)則會作用于下一條線段巧号,再作用于下下條線段……別急著運(yùn)行代碼,我們還少了一個關(guān)鍵元素:退出條件姥闭。我們必須保證遞歸在某個點上能停下來——比如線段的長度小于1個像素丹鸿。
5、示例
示例代碼8-4 康托爾集
void setup() {
size(800, 200);
background(255);
// Call the recursive function
cantor(35, 0, 730);
}
void draw() {
// No need to loop
noLoop();
}
void cantor(float x, float y, float len) {
float h = 30;
// recursive exit condition
if (len >= 1) {
// Draw line (as rectangle to make it easier to see)
noStroke();
fill(0);
rect(x, y, len, h/3);
// Go down to next y position
y += h;
// Draw 2 more lines 1/3rd the length (without the middle section)
cantor(x, y, len/3);
cantor(x+len*2/3, y, len/3);
}
}