尹蘭蘭 磨峰 熊水平
摘? 要:C語言課程中有眾多的算法,各種算法抽象且難以理解。如果能把幾個(gè)重要的算法以具體的圖形來呈現(xiàn),則對(duì)于算法的理解掌握更為容易。本文主要介紹了在C語言課程中進(jìn)行幾種算法的可視化圖形呈現(xiàn)。具體來說,即在C語言編譯環(huán)境中安裝插件easyX以獲得可視化圖形。通過幾種算法的可視化編程,產(chǎn)生具體直觀的圖形圖像。透過這種算法和圖形相結(jié)合的形式,激發(fā)了學(xué)生對(duì)學(xué)習(xí)C語言的熱情,同時(shí)加深了學(xué)生對(duì)算法的理解。
關(guān)鍵詞:easyX;可視化教學(xué);斐波那契數(shù)列;笛卡爾函數(shù)
中圖分類號(hào):TP399? ? ?文獻(xiàn)標(biāo)識(shí)碼:A
Visual Teaching of Algorithms by Using easyX in the C Language Course
YIN? Lanlan,MO Feng,XIONG Shuiping
(College of Computer and Information Engineering,Hechi University,Hechi 546300,China)
Abstract:Many algorithms in C language are abstract and difficult to understand.Several important algorithms will be much easier to understand if presented in specific graphics.This paper describes the visual teaching of the algorithms in C language and proposes to install easyX software in C language compiler environment to obtain the graphics of algorithms.The visual programming of algorithms stimulates students' enthusiasm for learning C language and deepens the understanding of the algorithms.
Keywords:easyX;visual teaching;Fibonacci sequence;Cartesian function
1? ?引言(Introduction)
C語言是一門面向過程、抽象化的計(jì)算機(jī)程序設(shè)計(jì)語言。一直以來,它是高等院校計(jì)算機(jī)專業(yè)必修的一門基礎(chǔ)課程[1]。
在這門課程中,算法是最重要的知識(shí)點(diǎn)。它被稱為是程序設(shè)計(jì)的靈魂,也是學(xué)習(xí)編程的必備知識(shí)。一個(gè)優(yōu)秀的程序需要高效、清晰的算法,但是,算法并不容易被學(xué)生掌握,因?yàn)樗橄箅y懂。如何能讓學(xué)生快速有效的學(xué)習(xí)算法?如何能讓學(xué)生對(duì)算法編程感興趣?如何能增強(qiáng)學(xué)生在算法編程中的自主思維和實(shí)踐創(chuàng)新精神?這一直是學(xué)生在學(xué)習(xí)程序設(shè)計(jì)過程中遇到的重點(diǎn)和難點(diǎn)問題。
本文作者在實(shí)際教學(xué)過程中發(fā)現(xiàn),在C語言課程設(shè)計(jì)中進(jìn)行算法的可視化教學(xué)可以很好地解決上述問題。
如何在C語言中引入可視化學(xué)習(xí)?作為C語言的圖形庫(kù), easyX可以很好地完成這樣的任務(wù)。
2? ?easyX簡(jiǎn)介(Brief introduction of easyX)
easyX是C語言進(jìn)行圖形化編程和游戲編程的一種圖形庫(kù)。它主要提供了用于繪制圖形的常用函數(shù)庫(kù)及相應(yīng)的頭文件。使用easyX非常簡(jiǎn)單,只要從官方網(wǎng)站下載安裝包,解壓,并將其中的lib文件夾和include文件夾下的內(nèi)容分別拷貝到Visual C++相應(yīng)的目錄下即可開始使用[2]。EasyX庫(kù)采用動(dòng)態(tài)鏈接的方式,不會(huì)增加任何額外的DLL依賴。
在使用easyX提供的函數(shù)前需要使用initgraph(int? width,int height,int flag=NULL)來初始化繪圖環(huán)境,設(shè)置顯示屏的寬度和高度。結(jié)束后使用closegraph()函數(shù)關(guān)閉圖形環(huán)境[3]。
3? ?算法介紹(Introduction of algorithms)
為了增加C語言課程的趣味性,這里我們?cè)O(shè)計(jì)了三種算法:階乘(Factorial)、斐波那契數(shù)列(Fibonacci sequence)和笛卡爾心形函數(shù)。其中前兩種算法用到了遞歸函數(shù)。編程語言中,函數(shù)Func(Type a,……)直接或間接調(diào)用函數(shù)本身,則該函數(shù)稱為遞歸函數(shù)。遞歸函數(shù)不能定義為內(nèi)聯(lián)函數(shù)。在數(shù)學(xué)上,關(guān)于遞歸函數(shù)的定義如下:對(duì)于某一函數(shù)f(x),其定義域是集合A,那么若對(duì)于A集合中的某一個(gè)值X0,其函數(shù)值f(x0)由f(f(x0))決定,那么就稱f(x)為遞歸函數(shù)。
3.1? ?階乘
階乘派生于排列。比如3個(gè)人排隊(duì),那么就有3!種排列。一個(gè)正整數(shù)的階乘是所有小于及等于該數(shù)的正整數(shù)的積,并且有0的階乘為1。自然數(shù)n的階乘可以寫作n!。
n!=1*2*3*...*n
5的階乘可以表示為:5!=5*4*3*2*1。
階乘的函數(shù)可以寫成:
int factorial (int x)
{
int y;
if (x<=1)
{
y=1;
}
else
{
y=x*factorial(x-1);
}
return y;
}
如何才能將階乘函數(shù)用easyX繪制出的圖形進(jìn)行可視化教學(xué)?在easyX環(huán)境下,繪制圖形首先需要找到每個(gè)點(diǎn)的位置,即y=factorial(x),對(duì)應(yīng)的坐標(biāo)點(diǎn)為(x,y)也即(x,factorial(x))。5的階乘即x的值是5,y的值是factorial(5),計(jì)算出數(shù)值為
5!=120,所以在x=5時(shí)對(duì)應(yīng)的坐標(biāo)點(diǎn)為(5,120)。依次求出所有點(diǎn)的坐標(biāo)如下:(0,1),(1,1),(2,2),(3,6),(4,24)。如何將所有的點(diǎn)在easyX環(huán)境下連成一條線表示出來呢?我們只需要在相鄰的兩個(gè)點(diǎn)之間畫一條直線,用easyX中的line函數(shù)可以實(shí)現(xiàn)。Line函數(shù)用于畫直線。它的定義為:
void line (int x1,int y1,int x2,int y2);
其中,x1為直線的起始點(diǎn)的x坐標(biāo);
y1為直線的起始點(diǎn)的y坐標(biāo);
x2為直線的終止點(diǎn)的x坐標(biāo);
y2為直線的終止點(diǎn)的y坐標(biāo)。
畫出所有的線條,首尾相連,代碼如下:
initgraph(30,130);
for (int i=0;i<5;i++)
{
setcolor(GREEN);
line(i,factorial(i),(i+1),factorial(i+1));
Sleep (20);
}
做出的圖形如圖1所示。
圖1 0—5的階乘函數(shù)圖形
Fig.1 Graphics of factorial functions of 0—5
為了獲得更好的效果,可以適當(dāng)調(diào)整x、y的參數(shù),并且調(diào)整窗口大小,讓圖形更好地適應(yīng)easyX的畫圖環(huán)境[4]。例如,y值不變,將x值的參數(shù)調(diào)整擴(kuò)大100倍,窗口大小從(30,130)變成(630,730),另外設(shè)置顏色為藍(lán)色,x的取值范圍為0<=x<=5,代碼變?yōu)椋?/p>
line(i*100,factorial(i),(i+1)*100,factorial(i+1));
畫出的圖形如圖2所示。
圖2 X參數(shù)調(diào)整后的階乘圖形
Fig.2 Factorial graphics with adjusted X parameters
階乘函數(shù)廣泛地應(yīng)用在金融、計(jì)算機(jī)、建筑等行業(yè)。機(jī)器學(xué)習(xí)、AI技術(shù)中也有很多階乘的應(yīng)用。
3.2? ?斐波那契數(shù)列
斐波那契數(shù)列又稱為黃金分割數(shù)列。它的定義為:F(0)=1,F(xiàn)(1)=1,F(xiàn)(n)=F(n-1)+F(n-2),其中,n>=2。
如果要求5的斐波那契數(shù)列,可以這樣計(jì)算:F(0)=1,
F(1)=1,F(xiàn)(2)=2,F(xiàn)(3)=3,F(xiàn)(4)=5,F(xiàn)(5)=8。它的函數(shù)可以寫成:
int fibonaci(int i)
{
int y=0;
if(i==0)
{
y=0;
}
else if(i==1)
{
y=1;
}
else
{
y=fibonaci(i-1)+fibonaci(i-2);
}
return y;
}
要畫出它的圖形,需要做如上分析:
1.計(jì)算每個(gè)坐標(biāo)點(diǎn)的位置,如:(0,1),(1,1),(2,2),(3,3),(4,5),(5,8)。
2.用easyX的line函數(shù)將相鄰的點(diǎn)畫一條直線。
3.將所有的線條收尾相接,畫出easyX環(huán)境下的曲線。
代碼如下:
initgraph(30,130);
for (int k=0;k<5;k++)
{
setcolor(BLUE);
line(k,fibonaci(k),(k+1),fibonaci(k+1));
Sleep (20);
}
做出的圖形如圖3所示。
圖3 0—5的斐波那契數(shù)列圖形
Fig.3 Fibonacci sequence graphics of 0—5
這個(gè)圖形在0—5的x區(qū)間值的變化幅度不是很大,畫出的圖形效果不夠明顯。為了獲得更好的效果,可以適當(dāng)調(diào)整x,y的參數(shù),同時(shí)調(diào)整窗口的大小從(30,130)變?yōu)椋?30,730),讓圖形更好地適應(yīng)easyX的畫圖環(huán)境。例如,將x值的參數(shù)調(diào)整擴(kuò)大100倍,y值保持不變,代碼變?yōu)椋?/p>
line(i*100,fibonaci(i),(i+1)*100,fibonaci(i));
畫出的圖形如圖4所示。
圖4 X參數(shù)調(diào)整后的斐波那契圖形
Fig.4 Fibonacci figure adjusted by X parameter
圖4的圖形y值變化不夠明顯。如何進(jìn)一步調(diào)整y值,使其變化率高一些,不能被忽視?根據(jù)計(jì)算,x值越大,數(shù)列的變化率越大。窗口的高度是730,而斐波那契數(shù)列在5這個(gè)點(diǎn)的坐標(biāo)是(5,8),列的值是8,列的變化率可以用下列公式計(jì)算出來:
(y2-y1)/(x2-x1)
0—5這6個(gè)點(diǎn)列的變化率可以計(jì)算出來分別為:0,1,1,2,3,……它同樣為一個(gè)斐波那契數(shù)列。經(jīng)過計(jì)算,將y值的結(jié)果向右移9位可以獲得變化率更大,更適合easyX窗口的數(shù)據(jù)。即將代碼變?yōu)椋?/p>
line(i*100,fibonaci(i+9),(i+1)*100,fibonaci(i+1+9));
所畫出的圖形如圖5所示。
圖5 X、Y參數(shù)調(diào)整后的斐波那契數(shù)列圖形
Fig.5 Fibonacci sequence graphics adjusted by X and Y
parameters
在我們?nèi)粘I钪校巢瞧鯏?shù)列無處不在。比如松果、鳳梨、樹葉的排列;某些花朵的花瓣數(shù)(如向日葵);蜂巢;蜻蜓翅膀、超越數(shù)e、等角螺線、十二平均律等;在現(xiàn)代物理、準(zhǔn)晶體結(jié)構(gòu)、化學(xué)等領(lǐng)域也有應(yīng)用廣泛。
以上兩種算法在程序設(shè)計(jì)中都用到了遞歸函數(shù)。為了將上述兩個(gè)圖形畫在同一個(gè)坐標(biāo)系中,可以調(diào)整代碼如下:
initgraph(630,730);
for (int i=0; i<=5; i++)
{
setcolor(YELLOW);
line(i*100,factorial(i),(i+1)*100,factorial(i+1));
setcolor(RED);
line(i*100,fibonaci(i+9),(i+1)*100,fibonaci(i+1+9));
Sleep(85);
}
Sleep(50);
此處的factorial()函數(shù)和fibonaci()函數(shù)為自己編程實(shí)現(xiàn)的C語言函數(shù)代碼。根據(jù)重新調(diào)整后的代碼,可以獲得如圖6所示。其中黃色的線為數(shù)列函數(shù)畫出來的,紅色的線是斐波那契函數(shù)畫出來的。
圖6 階乘函數(shù)和斐波那契數(shù)列圖形
Fig.6 Factorial functions and Fibonacci sequence graphics
為了增加學(xué)生學(xué)習(xí)編程的興趣,我們接下來準(zhǔn)備探討笛卡爾函數(shù)的可視化實(shí)現(xiàn)。
3.3? ?笛卡爾心形曲線
笛卡爾是大家都熟悉的著名數(shù)學(xué)家。他是法國(guó)著名的哲學(xué)家、物理學(xué)家、數(shù)學(xué)家、神學(xué)家。他對(duì)現(xiàn)代數(shù)學(xué)的發(fā)展做出了重要貢獻(xiàn)。他因?yàn)閷缀巫鴺?biāo)體系公式化而被認(rèn)為是解析幾何之父。在他眾多的數(shù)學(xué)理論中,笛卡爾心形曲線尤為著名,也被稱為“學(xué)霸的表白”,很多同學(xué)對(duì)這種心形曲線十分感興趣。
笛卡爾用運(yùn)動(dòng)的觀點(diǎn)把曲線看成點(diǎn)的運(yùn)動(dòng)的軌跡。笛卡爾函數(shù)即笛卡爾心形曲線。心形線即一個(gè)圓上固定一點(diǎn)在它繞著與其相切且半徑相同的另外一個(gè)圓周滾動(dòng)時(shí)所形成的軌跡。它的極坐標(biāo)表達(dá)式可以寫成:水平方向r=a(1-cosθ)或r=(1+cosθ)(a>0);或垂直方向r=a(1-sinθ)或r=a(1+sinθ)(a>0)。它的平面直角坐標(biāo)表達(dá)式分別為:x^2+y^2+a*x=a*sqrt(x^2+y^2)和x^2+y^2-a*x=a*sqrt(x^2+y^20)。為了畫出動(dòng)態(tài)圖形,需要先根據(jù)平面直角坐標(biāo)的表達(dá)式求解出x、y的值,然后進(jìn)行easyX畫圖。根據(jù)平面直角坐標(biāo)表達(dá)式,獲得x、y參數(shù)方程為:y=a*(2*cos(t)–cos(2*t)),x=a*(2*sin(t)–sin(2*t)),(0<=t<=2*pi)。根據(jù)t的范圍,做出對(duì)應(yīng)(x,y)點(diǎn),然后將所有的點(diǎn)與原點(diǎn)(0,0)直接相連,合理地設(shè)置sleep時(shí)間,就可以看到動(dòng)態(tài)效果。為了更好地適應(yīng)easyX畫圖的窗口大小,這里我們選取了t的范圍為[0,720],x和y同時(shí)擴(kuò)大30倍。具體的程序代碼如下。
initgraph(720,730);
setorigin(360,300);
setbkcolor(BLUE);
for (int t=0; t<=720; t++)
{
int a=4;
double x=a*(2*sin(t)+sin(2*t));
double y=a*(2*cos(t)+cos(2*t));
line(0,0,x*30,y*30);
sleep(20);
}
這段代碼的功能是動(dòng)態(tài)地畫出笛卡爾心形圖形,每間隔20秒畫一條線,獲得的不同時(shí)間點(diǎn)的截圖如圖7和圖8所示。注意,這里截取了不同顏色的圖形。圖7藍(lán)色的圖形是中間過程中的一個(gè)瞬間,圖8綠色的圖形是完整的笛卡爾心形圖案。用動(dòng)態(tài)圖可以讓學(xué)生更好地理解算法的過程,增強(qiáng)學(xué)習(xí)語言及算法的趣味性。
圖7 中間過程的瞬間圖形
Fig.7 Transient graphics of intermediate process
圖8 完整的笛卡爾圖形
Fig.8 Complete Cartesian graphics
用不同顏色的曲線繪制心形圖可以獲得不同的效果。如圖9和圖10所用的顏色分別為:
setcolor(RGB(t/3,t/3,t/3)); #圖9
setcolor(RGB(t/3,t/3*60,t/3*100)); #圖10
根據(jù)不同的setcolor,設(shè)置畫出的圖形如圖9和圖10所示。
圖9 RGB(t/3,t/3,t/3)畫出的完整圖形
Fig.9 Complete graphics drawn by RGB(t/3,t/3,t/3)