Professional Documents
Culture Documents
Gioi Thieu Ve de Qui
Gioi Thieu Ve de Qui
Kyõ thuaät laäp trình ñeä qui coù yù nghóa raát lôùn trong khoa hoïc maùy tính, coù raát
nhieàu thuaät toaùn ñoøi hoûi caøi ñaët raát phöùc taïp vaø caàu kyø neáu khoâng duøng kyõ thuaät
ñeä qui. Ñoái vôùi moät soá thuaät toaùn do baûn chaát töï nhieân cuûa chuùng ñaõ mang tính ñeä
qui, vieäc caøi ñaët ñeä qui laø goïn vaø ñeïp nhaát. Khuyeát ñieåm lôùn nhaát cuûa kyõ thuaät ñeä
qui laø: lôøi giaûi ñeä qui cho moät soá baøi toaùn coù theå bò chaïy raát chaäm do söï buøng noã toå
hôïp.
I. KHAÙI NIEÄM VEÀ CHÖÔNG TRÌNH ÑEÄ QUI
Moät thuû tuïc (hay haøm) ñöôïc goïi laø coù tính ñeä qui neáu trong thaân cuûa thuû tuïc
(hay haøm) ñoù coù leänh goïi laïi chính noù moät caùch töôøng minh hay tieàm aån.
Ví duï 1. Vôùi n laø soá nguyeân khoâng aâm, ta ñònh nghóa n! nhö sau:
0!=1,
n!=n.(n-1)! neáu n≥1.
Haõy caøi ñaët chöông trình tính n!.
Ñaây laø moät ví duï coù theå caøi ñaët deã daøng baèng phöông phaùp thoâng thöôøng, tuy
nhieân neáu döïa vaøo ñònh nghóa cuûa n! chuùng ta coù theå caøi ñaët moät caùch töï nhieân
baèng phöông phaùp ñeä qui nhö sau.
#include <stdio.h>
#include <math.h>
double sqrt3(double x)
{
double ret;
if(x==0) /* ñieàu kieän döøng */
ret = 0;
else
if(x<0) /* goïi ñeä qui */
ret = sqrt3(-x);
else /* moät ñieàu kieän döøng khaùc */
ret = exp(log(x)/3);
return ret;
}
Ví duï 3. Caøi ñaët caùc haøm in, thoâng baùo loãi trong cheá ñoä vaên baûn. Caùch caøi ñaët sau
ñaây laø moät daïng goïi ñeä qui tieàm aån, chính xaùc hôn ñaây laø caùch goïi xoay voøng,
haøm InChuoi goïi haøm BaoLoi ñeå thoâng baùo loãi khi toïa ñoä in khoâng hôïp leä, ngöôïc
laïi haøm BaoLoi goïi haøm InChuoi ñeå in caâu thoâng baùo loãi taïi doøng cuoái cuøng cuûa
maøn hình
#include <conio.h>
#include <string.h>
void BaoLoi();
void InChuoi(int x, int y, char *ch);
#define MAXROW 25
#define MAXCOL 80
void BaoLoi()
{
InChuoi(1, 25, "Toa do in sai !");
printf("%c%c%c", 7, 7, 7);
Kyõ thuaät ñeä qui - Trần Đan Thư, Khoa CNTT, Trường ĐHKHTN, ĐHQGTP HCM 15
Ñeä qui nhò phaân ñoùng vai troø raát quan troïng, chuùng ta thöôøng duøng phöông
phaùp naày ñeå caøi ñaët caùc thuaät toaùn "chia ñeå trò", thuaät toaùn duyeät caây nhò phaân...
Ví duï: Daõy Fibonaci {Fn} ñöôïc ñònh nghóa truy hoài nhö sau:
Fo=F1=1,
Fn=Fn-1 + Fn-2 neáu n ≥ 2.
Haøm ñeä qui nhò phaân sau ñaây seõ tính giaù trò cuûa Fn, giaù trò phaàn töû thöù n trong
daõy Fibonaci, baèng caøi ñaët ñeä qui, ñaây laø moät caøi ñaët töï nhieân vaø ñôn giaûn nhaát
nhöng cuõng laø caùch caøi ñaët chaïy chaäm nhaát.
long Fibo(int n)
{
long ret, Fn_1, Fn_2;
if(n <= 1)
ret = 1;
else
{
Fn_1 = Fibo(n-1);
Fn_2 = Fibo(n-2);
ret = Fn_1 + Fn_2;
}
return ret;
}
Chöông trình treân laø moät ví duï veà ñeä qui nhò phaân coù theå deã daøng ñöa veà ñeä
qui tuyeán tính, trong tröôøng hôïp nhö vaäy thì caøi ñaët theo ñeä qui tuyeán tính seõ toát
hôn. Moät soá thuaät toaùn khaùc mang tính "chia ñeå trò" theo kieåu nhò phaân thì caøi ñaët
ñeä qui nhò phaân seõ theå hieän roõ tính töï nhieân cuûa thuaät vaø coù thôøi gian chaïy khaù toát.
Döôùi ñaây laø moät phieân baûn ñeä qui tuyeán tính ñeå tính phaàn töû thöù n cuûa daõy
Fibonaci.
void FiboLinear(int n, long* F_n_1, long* F_n)
/* F_n_1: Fn-1; F_n: Fn; F_n_2: Fn-2 */
{
long F_n_2;
if(n<=1)
{
*F_n_1 = 1;
*F_n = 1;
Kyõ thuaät ñeä qui - Trần Đan Thư, Khoa CNTT, Trường ĐHKHTN, ĐHQGTP HCM 17
}
else
{
FiboLinear(n-1, &F_n_2, &(*F_n_1) );
*F_n = *F_n_1 + F_n_2;
}
}
Ví du: Cho daõy {Xn} xaùc ñònh theo coâng thöùc truy hoài sau ñaây:
Xo=1,
Xn=n2Xo + (n-1)2X1 + ... + 12Xn-1 , neáu n ≥ 1.
Nhö caùc ví duï tröôùc, chuùng ta coù theå tính daõy naày baèng phöông phaùp ñeä qui,
bôûi vì baûn chaát ñöôïc ñònh nghóa ñeä qui cuûa daõy. Tröôøng hôïp naày vieäc goïi ñeä qui
ñöôïc thöïc hieän trong voøng laëp.
long Xn(int n)
{
int i;
long ret; /* gia tri tra ve */
if(n==0)
ret=1;
else
{
ret = 0;
Kyõ thuaät ñeä qui - Trần Đan Thư, Khoa CNTT, Trường ĐHKHTN, ĐHQGTP HCM 18
Ví duï: Xeùt hai daõy {Xn}, {Yn} ñöôïc ñònh nghóa nhö sau:
Xo=Yo=0
Xn = Xn-1 + Yn-1
Yn = n2Xn-1+ Yn-1
Hai daõy naày ñöôïc tính nhôø vaøo hai haøm TinhX vaø TinhY goïi hoã töông laãn nhau
ñöôïc minh hoïa qua caøi ñaët döôùi ñaây.
long TinhX(int n)
{
long ret; /* giaù trò traû veà */
if(n<=0)
ret = 1;
else
ret = TinhX(n-1)+TinhY(n-1);
return ret;
}
Kyõ thuaät ñeä qui - Trần Đan Thư, Khoa CNTT, Trường ĐHKHTN, ĐHQGTP HCM 19
long TinhY(int n)
{
long ret; /* giaù trò traû veà */
if(n<=0)
ret = 1;
else
ret = n*(long)n*TinhX(n-1)+TinhY(n-1);
return ret;
}
III. THEO DOÕI HOAÏT ÑOÄNG CUÛA CHÖÔNG TRÌNH ÑEÄ QUI
Do coù caáu truùc ñaëc bieät, caùc chöông trình ñeä qui khaùc haún vôùi caùc chöông trình
thoâng thöôøng. (Caùc chöông trình thoâng thöôøng chæ duøng caùc leänh tuaàn töï, caáu truùc
reû nhaùnh, leänh nhaûy, hay caáu truùc laëp). Vì vaäy ngöôøi laëp trình raát khoù khaên trong
vieäc theo doõi vaø kieåm tra caùc chöông trình ñeä qui, nhaát laø khi chöông trình coù loãi.
Vôùi caùc coâng cuï baét loãi chöông trình hieän nay, ngöôøi laäp trình chæ theo doõi ñöôïc
traïng thaùi hieän haønh trong moät laàn goïi ñeä qui chöù chöa hình dung ñöôïc toaøn boä
traïng thaùi cuûa chöông trình (chaúng haïn nhö ñang goïi ñeä qui ôû taàng thöù maáy vaø
ñang ôû laàn goïi naøo trong taàng naày, giaù trò cuûa caùc bieán cuïc boä ôû moãi laàn goïi laø bao
nhieâu, giaù trò cuûa caùc tham soá ...).
Trong phaàn naày chuùng ta seõ nghieân cöùu moät phöông phaùp theo doõi caùc
chöông trình ñeä qui, phöông phaùp naày coù theå duøng keát hôïp chaët cheõ vôùi caùc coâng
cuï baét loãi chöông trình.
Moãi chöông trình ñeä qui seõ ñöôïc bieåu dieãn baèng moät caây, goác cuûa caây ñaïi dieän
cho laàn goïi ñaàu tieân, caùc nuùt cuûa caây ñaïi dieän cho caùc laàn goïi ñeä qui, moãi nuùt löu
giaù trò hieän taïi cuûa caùc bieán cuïc boä hay caùc tham soá trong moät laàn goïi ñeä qui, caùc
nuùt laù öùng vôùi laàn goïi ñeä qui gaëp ñieàu kieän döøng. Tuøy theo loaïi ñeä qui maø caây coù
caáu truùc ñaëc tröng, ví duï ñeä qui nhò phaân seõ ñöôïc bieåu dieãn baèng caây nhò phaân, ñeä
qui tuyeán tính bieåu dieãn baèng moät caây suy thoaùi (thaønh moät xaâu ñôn).
Ví du: Bieåu dieãn cuûa haøm ñeä qui Fibo trong phaàn treân vôùi n=5, ta kyù hieäu Fibo(n)
laø Fn. Hình döôùi ñaây laø caây nhò phaân bieåu dieãn cuûa haøm Fibo. Chuùng ta cuõng
nhaän thaáy coù nhieàu nuùt laëp laïi trong caây. Ñieàu naày chöùng toû cuøng moät giaù trò ñöôïc
tính ñi, tính laïi nhieàu laàn. Ñieàu naày laøm cho chöông trình chaïy raát chaäm.
F5=F3+F4
F3=F1+F2 F4=F2+F3
Baøi toaùn Thaùp Haø noäi coù theå giaûi raát ñôn giaûn baèng phöông phaùp ñeä qui theo
thuaät toaùn sau.
Thuaät toaùn Thaùp haø noäi
Neáu soá ñóa n=1 thì hieån nhieân coù theå chuyeån theo yeâu caàu cuûa baøi toaùn. Neáu
ngöôïc laïi:
- Böôùc 1: Goïi ñeä qui ñeå chuyeån n-1 ñóa töø choàng thöù 1 sang choàng thöù 2
(choàng thöù 3 laøm trung gian).
- Böôùc 2: Chuyeån ñóa thöù n töø choàng 1 sang choàng 3.
- Böôùc 3: Goïi ñeä qui ñeå chuyeån n-1 ñóa töø choàng thöù 2 sang choàng thöù 3
(choàng thöù 1 laøm trung gian).
Thuaät toaùn treân ñöôïc caøi ñaët ñeä qui baèng haøm Tower döôùi ñaây. Haøm naày goïi
haøm MoveDisk ñeå chuyeån ñóa cuoái cuøng. Trong caøi ñaët naày haøm MoveDisk chæ
nhaèm höôùng daãn trình töï chuyeån ñóa. Baèng caùch söûa haøm MoveDisk thích hôïp,
chuùng ta coù theå giaû laäp quaù trình di chuyeån ñóa treân maøn hình cuûa maùy tính.
#include <stdio.h>
/* chuyeån n-1 ñóa töø col2 sang col3; col1 trung gian */
Tower(n-1, col2, col1, col3);
}
}
Chuùng ta seõ minh hoïa hoaït ñoäng cuûa thuaät toaùn baèng caùch veõ caây bieåu dieãn
cho thuaät toaùn vôùi n=3, thuaät toaùn treân thuoäc loaïi ñeä qui nhò phaân neân caây bieåu
dieãn seõ laø moät caây nhò phaân. Caùc nuùt laù öùng vôùi caùc leänh goïi Tower(0,?,?,?) ñöôïc
boû qua bôûi vì caùc leänh naày khoâng laøm gì caû.
Tower(3,1,2,3)
Töø 1 Ñeán 3
Tower(2,1,3,2) Tower(2,2,1,3)
Döïa vaøo hình veõ treân chuùng ta laäp ñöôïc baûng moâ taû traïng thaùi hoaït ñoäng cuûa
thuaät toaùn vôùi n=3, caùc ñóa ñöôïc kyù hieäu laø a, b, c vôùi giaû söû a > b > c, caùc ñóa treân
hình veõ töø döôùi leân treân seõ ñöôïc kyù hieäu töø traùi qua phaûi.
Töø 1 Ñeán 3 bc a
Töø 2 Ñeán 1 c b a
Töø 2 Ñeán 3 c ab
Töø 1 Ñeán 3 abc
Ví duï:
- Neáu Ω={a,b,c} thì a b c vaø b a c laø hai hoaùn vò cuûa Ω.
- Neáu Ω={1, 2, 3} thì coù taát caû 3!=1x2x3=6 hoaùn vò cuûa Ω laø 123, 132, 231, 213,
312, 321.
Cho moät taäp hôïp n phaàn töû Ω={1, 2, ..., n} vaø moät soá nguyeân k (1 ≤ k ≤ n). Moät
chænh hôïp chaäp k cuûa Ω laø moät daõy μ coù k phaàn töû ñöôïc laáy ra töø Ω vaø caùc phaàn töû
cuûa μ ñoâi moät khaùc nhau.
Ví duï:
Vôùi Ω={1, 2, 3} thì 1 2, 2 1, 1 3, 3 1, 2 3, 3 2 laø caùc chænh hôïp chaäp 2 cuûa Ω.
Ta thaáy ngay moät chænh hôïp chaäp n cuûa moät taäp hôïp Ω (coù n phaàn töû) chính laø
moät hoaùn vò cuûa Ω. Soá caùc chænh hôïp chaäp k cuûa n phaàn töû ñöôïc kyù hieäu laø: A n , ta
k
coù A n = n !, hôn nöõa A n coù theå tính theo coâng thöùc sau ñaây.
n k
Soá löôïng caùc chænh hôïp chaäp k cuûa n phaàn töû ñöôïc xaùc ñònh theo coâng
thöùc:
n!
A kn =
( n − k )!
Ví duï:
Coù 4 ñôït söûa xe vaø 3 khaùch haøng teân Lan, Huøng, Chaâu. Caùc thoâng tin lieân quan
ñöôïc cho trong hai baûng nhö sau:
Coù theå nhaän söûa ñeå ñaùp öùng yeâu caàu cho caû 3 khaùch haøng treân hay khoâng?
Chuùng ta coù theå laäp baûng cho moãi tröôøng hôïp cuûa chænh hôïp chaäp 3 cuûa 4
phaàn töû ñeå xeùt xem moãi tröôøng hôïp coù bao nhieâu khaùch haøng ñöôïc thoûa maõn.
Khaùch Phöông Phöông Phöông ...
haøng aùn 1 aùn 2 aùn 3
Lan ñôït 1 ñôït 1 ñôït 3
Huøng ñôït 2 ñôït 3 ñôït 2
Chaâu ñôït 3 ñôït 2 (treå) ñôït 1
(treå)
IV.2.2 Thuaät toaùn phaùt sinh chænh hôïp
Do hoaùn vò laø moät tröôøng hôïp ñaëc bieät cuûa chænh hôïp (khi k=n) neân chuùng ta
chæ baøn ñeán thuaät toaùn phaùt sinh taát caû caùc chænh hôïp chaäp k cuûa n phaàn töû. Ñaây
cuõng laø thuaät toaùn duyeät qua taát caû caùc chænh hôïp trong caùc baøi toaùn toå hôïp nhö ví
duï treân. Thuaät toaùn coù moät tham soá i, khi goïi ñeä qui thì giaù trò tham soá naày thay ñoåi,
khôûi ñaàu i nhaän giaù trò 1.
- Goïi haøm: Phatsinh(a, n, k, 1)
- Haøm ñeä qui Phatsinh(a, n, k, i)
Laëp j=i ñeán n laøm
Ñoåi choã aj vaø ai
Neáu j<k thì
goïi ñeä qui Phatsinh(a, n, k, i+1)
Ngöôïc laïi
xöû lyù a1 a2 ... ak
Ñoåi choã aj vaø ai
Cuoái laëp
Thuaät toaùn sau phaùt sinh taát caû caùc toå hôïp chaäp k cuûa taäp {1, 2, ..., n}. Töông
töï thuaät toaùn phaùt sinh chænh hôïp, thuaät toaùn naày goïi ñeä qui vôùi tham soá i, khôûi ñaàu
i=1 vaø ao=0.
V.2 Tìm phaàn töû lôùn nhaát, phaàn töû nhoû nhaát
Thuaät toaùn ñeä qui sau ñaây tìm chæ soá cuûa phaàn töû lôùn nhaát trong caùc soá a[0],
a[1], …, a[n-1]. (Bieán csmax löu chæ soá caàn tìm.) Tröôøng hôïp tìm phaàn töû nhoû nhaát
coù theå laøm hoaøn toaøn töông töï.
- Neáu n<1 thì csmax=-1 (maûng khoâng coù phaàn töû);
- Ngöôïc laïi neáu n=1 thì csmax=0;
- Ngöôïc laïi neáu n>1 thì laøm
tính csmax baèng ñeä qui cho a[0], a[1], …, a[n-2]
neáu a[csmax]<a[n-1] thì caäp nhaät csmax=n-1
Cuoái ngöôïc laïi
Sau ñaây laø caøi ñaët cho tröôøng hôïp tìm soá lôùn nhaát trong moät maûng caùc soá
nguyeân. Haøm ChiSoMax traû veà moät chæ soá cuûa phaàn töû lôùn nhaát cuûa maûng.
if(n<1)
csmax=-1;
else if(n==1)
csmax = 0;
else
{
csmax = ChiSoMax(a, n-1);
if(a[csmax] < a[n-1])
csmax = n-1;
}
return csmax;
}
Thuaät toaùn coù theå ñöôïc caøi ñaët baèng haøm ñeä qui SapXep nhö sau.
void SapXep(int a[], int n)
{
int x;
if(n>1)
{
SapXep(a, n-1);
if(a[n-2]>a[n-1])
{
x = a[n-2];
a[n-2] = a[n-1];
a[n-1] = x;
SapXep(a, n-1);
}
}
}
Thuaät toaùn coù theå ñöôïc caøi ñaët baèng haøm ñeä qui SapXep_1 nhö sau.
void SapXep_1(int a[], int n)
{
int x, csmax;
if(n>1)
{
csmax = ChiSoMax(a, n-1);
if(a[csmax]>a[n-1])
{
Kyõ thuaät ñeä qui - Trần Đan Thư, Khoa CNTT, Trường ĐHKHTN, ĐHQGTP HCM 27
x = a[csmax];
a[csmax] = a[n-1];
a[n-1] = x;
}
SapXep_1(a, n-1);
}
}
Thuaät toaùn coù theå ñöôïc caøi ñaët baèng haøm ñeä qui DemPhanBiet nhö sau.
int XuatHienTrong(int a[], int n, int x)
{
int i=0;
else if(n==1)
ketqua = 1;
else
{
kq1 = DemPhanBiet(a, n-1);
if(XuatHienTrong(a, n-1, a[n-1]))
ketqua = kq1;
else
ketqua = kq1+1;
}
return ketqua;
}
Thuaät toaùn coù theå ñöôïc caøi ñaët baèng haøm ñeä qui DemPhanBiet_1 nhö sau. Haøm
traû veà keát quaû ñeám. Vieäc ñeám soá phaàn töû phaân bieät trong n-1 phaàn töû a[0], …, a[n-
3], a[n-1] vaãn duøng maûng a: giaù trò a[n-2] ñöôïc ghi nhôù vaøo bieán x (gaùn x=a[n-2]),
thay taïm a[n-2] bôûi a[n-1] (gaùn a[n-2]=a[n-1]), goïi ñeä qui haøm ñeám kq3 :=
DemPhanBiet_1(a, n-1), sau ñoù traû laïi giaù trò cuõ cho a[n-2] (gaùn a[n-2]=x).
if(n<1)
ketqua = 0;
Kyõ thuaät ñeä qui - Trần Đan Thư, Khoa CNTT, Trường ĐHKHTN, ĐHQGTP HCM 29
else if(n==1)
ketqua = 1;
else /* n >= 2; a[n-2], a[n-1] hop le */
{
kq1 = DemPhanBiet_1(a, n-1);
if(a[n-1]==a[n-2])
ketqua = kq1;
else
{
kq2 = DemPhanBiet_1(a, n-2);
if(n<0)
ret = 1/LuyThua(x, -n);
else if(n==0)
ret = 1;
else if(n==1)
ret = x;
else /* n > 1 */
{
if(n%2==0)
Kyõ thuaät ñeä qui - Trần Đan Thư, Khoa CNTT, Trường ĐHKHTN, ĐHQGTP HCM 30
{
xlast = LuyThua(x, n/2);
ret = xlast*xlast;
}
else
{
xlast = LuyThua(x, (n-1)/2);
ret = xlast*xlast*x;
}
}
return ret;
}