Tải bản đầy đủ (.doc) (9 trang)

chuong trinh con

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (135.15 KB, 9 trang )

<span class='text_page_counter'>(1)</span><div class='page_container' data-page=1>

<b>chơng trình con</b>



<b>1. Ch ơng trình con và vai trò của ch ơng trình con</b>


Chng trình là một dãy lệnh đợc xây dựng cho máy tính thực hiện một cơng việc nào đấy.
Cơng việc này có thể gồm nhiều cơng việc nhỏ và đến lợt chúng lại đợc tổ chức thành chơng
trình. Lời gọi của các chơng trình này sẽ đợc xuất hiện trong các lệnh của chơng trình ban
đầu. Chúng đợc gọi là các chơng trình con.


Nh vậy, chơng trình con là một chơng trình, mà nó đợc gọi trong lịng một chơng trình khác.
Trong chơng trình con có thể có chơng trình con khác. Vì vậy, khái niện chơng trình con
mang tính chất tơng đối: một chơng trình có thể là chơng trình con của một chơng trình khác.
Ngời ta thờng dùng thuật ngữ chơng trình chính để chỉ chơng trình ở mức ngoi cựng.


Vai trò của chơng trình con:


Cho phộp phõn rã bài toán phức tạp thành nhiều bài toán đơn giản hơn, từ đó cho phép
kiểm sốt tồn bộ chơng trình, dễ dàng sửa chữa và phát triển.


 Nâng cao tính độc lập trong thiết kế, che dấu nội tại. Cho phép xây dựng các chơng trình
lớn, có nhiều ngời tham gia.


 Là phơng thức thực hiện kỹ thuật lập trình Top-Down (từ tổng thể đến chi tiết), thích hợp
với hầu hết các thiết kế trong lập trình cấu trúc.


 Cho phép xây dựng th viện lập trình, kế thừa các kết quả trớc đấy, giảm chi phí và cơng
sức trong vic vit chng trỡnh.


<b>2. Cách tổ chức ch ơng tr×nh con</b>


Turbo Pascal cung cấp sẵn cho ngời dùng những chơng trình con có sẵn, đã đợc biên dịch đợc


gọi là chơng trình con chuẩn và đợc liên kết với chơng trình của ngời sử dụng. Các chơng
trình con này đợc phân loại và chứa trong các đơn vị chơng trình (unit) nh: crt, dos, graph, ...
Bên cạnh các chơng trình con chuẩn, Turbo Pascal cho phép tự tổ chức các chơng trình con
cho riêng mình, ngời dùng phải khai bỏo.


Cách tổ chức chơng trình con:


Ngay trong lòng chơng tr×nh chÝnh.


 Ta dịch nó độc lập và liên kết nó với chơng trình, coi nó nh chơng trình con chuẩn (unit).
Trong Pascal có 2 loại chơng trình con: procedure (thủ tục) và function (hàm).


<b>3. Thđ tơc (procedure)</b>


Thủ tục là một chơng trình con nhằm thực hiện một cơng việc nào đấy. Cũng giống nh một
chơng trình độc lập, một thủ tục gồm 3 phần: phần đầu (tiêu đề), phần khai bỏo v phn thõn:


procedure tên_thủ_tục(các lệnh khai báo tham số); { phần đầu }
{ các khai báo const,type,var của riêng procedure,nếu cần }
...


begin


{ phần thân }
...


end;


Trong đó:



 tên_thủ_tục: là tên do ngời dùng tự đặt, theo qui tắc giống tên biến (nên đặt gợi nhớ).


Nếu thủ tục có chứa tham số thì sau phần tên là dãy các lệnh khai báo tham số đợc viết
giới hn trong cp ngoc n.


Khai báo tham số:


tên_tham_số_1: kiểu_tham_số; tªn_tham_sè_2: kiĨu_tham_sè;...


Các tham số này gọi là tham số hình thức (cha có nội dung). Kiểu của tham số là tất cả
các kiểu mà ta đã biết: có thể là kiểu chuẩn và kiểu định danh trớc. Nếu có 2 tham số có
cùng kiểu thì khai báo chung:


</div>
<span class='text_page_counter'>(2)</span><div class='page_container' data-page=2>

 Phần khai báo thủ tục (nh khai báo chơng trình): những đối tợng nào khơng phải là chuẩn,
tức là các biến, hằng, ... dùng ở chơng trình con thì phải khai báo.


Cách gọi thủ tục giống nh lời gọi thủ tục chuẩn. Khi truyền tham số phải tơng ứng 1-1, đúng
kiểu, đúng thứ tự và giữa các tham số truyền vào phải cách nhau bởi dấu phẩy.


<i>VÝ dô 1. Chơng trình sau sẽ in một đoạn thơ trong truyện Kiều ra giữa màn hình.</i>


program vd1;
uses crt;


procedure center(s : string);
{ in xâu s vào giữa màn hình }


begin


writeln(' ' : (80-length(s)) div 2, s);


end;


begin
clrscr;


center('Tram nam trong coi nguoi ta');


center('Chu tai chu menh kheo la ghet nhau');
center('Trai qua mot cuoc be dau');


center('Nhung dieu trong thay ma dau don long');
readln;


end.


<b>4. Hµm (function)</b>


Hàm là một chơng trình con nhằm tính tốn và trả lại một giá trị. Cũng giống nh thủ tục, một
hàm gồm 3 phần: phần đầu (tiêu ), phn khai bỏo v phn thõn:


function tên_hàm(các lệnh khai báo tham số): kiểu_hàm;
{ các khai báo const,type,var của riêng function, nếu cần }
...


begin


{ thân hàm }
...


tên_hàm := <biểu_thức>;


end;


Trong ú:


tờn_hm: do ngi dựng tự đặt, theo qui tắc giống tên biến (nên đặt gợi nhớ). Nếu hàm có


chứa tham số thì sau phần tên là dãy các lệnh khai báo tham số đợc viết giới hạn trong cặp
ngoặc đơn.


 kiểu_hàm: là kiểu đơn giản chuẩn (integer, real, char, boolean) và kiểu phức hợp:


string, pointer.


Phần khai báo của hàm: giống phần khai báo cđa thđ tơc.


 Thân hàm: nằm trong khối begin và end; và đảm bảo rằng trớc khi ra khỏi hàm phải có
câu lệnh gán giá trị cho tên hàm: tên_hàm := <biểu_thức>; Kiểu giá trị gán cho tên


hµm phải cùng kiểu với kiểu hàm.
Lời gọi hàm phải tham gia vµo biĨu thøc.


<i>Ví dụ 2. Chơng trình sau sẽ đọc 2 số nguyên dơng từ bàn phím và đa ra màn hình ớc chung</i>
lớn nhất của chúng. Chơng trình có thiết kế hàm:


function ucln(a, b : integer) : integer;


để tính ớc chung lớn nhất của 2 số nguyên dơng a, b theo thuật tốn Ơ-cơlít.


program vd2;
uses crt;


var


a, b : integer;


function ucln(a, b : integer) : integer;
var


</div>
<span class='text_page_counter'>(3)</span><div class='page_container' data-page=3>

begin


r := a mod b;
while r <> 0 do
begin


a := b; b := r;
r := a mod b;
end;


ucln := b;
end;


begin
clrscr;


write('a, b = ');
readln(a, b);


writeln('ucln(', a, ',', b, ')=', ucln(a, b));
readln;


end.



<b>5. Địa ph ¬ng vµ toµn cơc</b>


Cấu trúc của Pascal là chơng trình chứa chơng trình con gọi là khối ngồi, cịn chơng trình
con gọi khối trong. Đối với mỗi khối có những đối tợng (biến, hằng, kiểu dữ liệu, ...) của
riêng từng loại. Vì vậy:


 Những đối tợng khai báo ở ngồi thì có thể dùng cho tất cả các khối khai báo ở bên trong
nó (ví dụ nh việc lấy thơng tin, cập nhật thơng tin, ...). Những đối tợng đó gọi là toàn cục.


 Những đối tợng khai báo ở một khối chỉ có tác dụng trong khối đó, cịn ở ngồi khơng tác
dụng. Đó là những đối tợng địa phơng.


Hai khái niệm địa phơng và toàn cục chỉ mang tính chất tơng đối. Nó có thể là tồn cục đối
với khối này, nhng lại là địa phơng của khối khác.


Vì trong Pascal có tính chất địa phơng nên chơng trình con mới có tính độc lập (khơng phải
ngơn ngữ nào cũng có tính địa phơng và tồn cục nh Pascal). Các biến của chơng trình con
khác nhau mang tính chất khác nhau.


Giả sử ở khối ngồi và khối trong có cùng tên biến (tồn cục = địa phơng) thì trong khối địa
phơng ln dùng biến địa phơng mà khơng dùng biến ngồi (biến địa phơng đợc u tiên). Cịn
khi ra khỏi khối thì biến địa phơng mất tác dụng, nhờng chỗ cho biến ngoài. Một khối nào
muốn dùng biến ngồi thì khi khai báo biến ở bên trong khối khơng đợc trùng tên với biến
ngồi.


Nh vậy những đối tợng (hằng, biến, kiểu, ...) khai báo ở chơng trình chính có thể dùng đợc ở
mọi nơi trong chơng trình. Các đối tợng khai báo ở chơng trình con chỉ có tác dụng trong
phạm vi chơng trình con. Khi kết thúc chơng trình con các biến này cũng hết tác dụng.



Cách dùng biến địa phơng và toàn cục:


 Những đối tợng nào mang tính chất dùng chung cho mọi khối thì khai báo là biến tồn
cục (khai báo ở khối ngồi). Chẳng hạn, với chơng trình cộng 2 ma trận: C = A + B và in
ma trận C, bao gồm 3 khối:


+ NhËp A, B
+ Céng C = A + B
+ In C


th× ma trËn A, B, C vµ n (kÝch thíc ma trËn) lµ biÕn toµn cơc.


 Những đối tợng phát sinh trong q trình thao tác của một khối (chẳng hạn: biến trung
gian, biến đếm, biến điều khiển vịng for, ...) chỉ có ý nghĩa trong chơng trình con thì khai
báo là biến địa phơng.


<i>Ví dụ 3. Chơng trình sau sẽ cho thấy phạm vi và tầm tác dụng của biến địa phơng, toàn cục.</i>


program vd3;
uses crt;
var


</div>
<span class='text_page_counter'>(4)</span><div class='page_container' data-page=4>

procedure dia_phuong;
var


i : integer; { biến i địa phơng }


begin


i := 5; j := 7;



writeln('i=', i, ', j=', j);
end;


begin
clrscr;


i := 2; j := 3;


writeln('i=', i, ', j=', j);
dia_phuong;


writeln('i=', i, ', j=', j);
readln;


end.


Chơng trình chạy và cho kết quả sau:


i=2, j=3
i=5, j=7
i=2, j=7


<b>6. C¸c c¸ch trun tham sè</b>
<b>a. Trun theo trị (giá trị)</b>


Vic truyn tham s theo tr l truyn bản sao (tạo một bản sao của tham số truyền vào, rồi
chuyển cho chơng trình con), do đó mọi thao tác trên chơng trình con là thao tác trên bản sao.
Ví dụ, đối với thủ tục procedure center(s : string); việc truyền dữ liệu cho tham số
hình thức s là truyền theo trị. Và đối với hàm function ucln(a, b : integer) :


integer; thì tham số hình thức a, b đợc truyền theo trị.


Việc truyền theo trị có các đặc điểm sau:


 Nếu trong chơng trình con có những lệnh làm thay đổi tham số hình thức đầu vào thì
những thay đổi này khơng ảnh hởng gì đến giá trị của biến đợc truyền vào, vì việc tác
động là lên bản sao.


 Việc truyền theo tham trị sẽ gây ra một ít tốn kém về bộ nhớ, cũng nh về thời gian sao
chép để tạo bản sao cho tham số truyền vào. Việc tốn kém là tuỳ theo kích th ớc của kiểu
tham số.


 Do viƯc sao chÐp nên tham số đầu vào phong phú, có thể là: h»ng, biÕn, biĨu thøc. VÝ dơ:


ucln(9, 12), ucln(a, b), ucln(a+3, b), ...


<b>b. Truyền theo biến (địa chỉ)</b>


Truyền theo biến là truyền địa chỉ của đối tợng đầu vào. Vì vậy các thao tác trên chơng trình
con chính là thao tác trên đối tợng đầu vào.


Để biết đợc chơng trình con này truyền theo biến hay theo trị là nằm trong phần khai báo
tham số của chơng trình con:


 C¸ch khai báo theo tham trị:


tên_tham_số : kiểu_tham_số;
Cách khai báo theo tham biÕn:


var tªn_tham_sè : kiĨu_tham_sè;



Việc truyền theo biến có các đặc điểm sau:


 Nếu trong chơng trình con có những lệnh làm thay đổi tham số hình thức thì những thay
đổi này cũng chính là những thay đổi của chính biến đợc truyền vào.


 Kh«ng tèn kÐm vỊ bé nhí và thời gian do không phải sao chép.


Chỉ có một phơng thức là truyền theo biến: ở đầu vào chỉ có biến, không thể là hằng hoặc
biểu thức.


</div>
<span class='text_page_counter'>(5)</span><div class='page_container' data-page=5>

Tuỳ theo mục đích của cơng việc mà việc khai báo phải phù hợp theo nguyên tắc sau:


 Nếu trong chơng trình con mà khơng có lệnh nào làm thay đổi tham số hình thức thì việc
truyền theo biến hay theo trị cho cùng một kết quả.


 Nếu trong chơng trình con có những lệnh làm thay đổi tham số hình thức thì cần căn cứ
vào chức năng:


- Cần thay đổi đầu vào: bắt buộc truyền theo biến. Ví dụ, thủ tục hốn chuyển giá trị
của hai biến procedure doi_cho(var a, b : integer);


- Ngợc lại có những chơng trình con cấm khơng đợc thay đổi đầu vào thì phải truyền
theo trị.


 Việc khơng thay đổi hay thay đổi đầu vào mà không ảnh hởng đến kết quả thì việc truyền
theo trị hay theo biến là tuỳ ý. Nhng trong trịng hợp này nên:


- Tham sè h×nh thøc kích thớc bé (dữ liệu chuẩn): truyền theo trị.



- Tham số hình thức kích thớc lớn (mảng, bản ghi, ...): trun theo biÕn.
<i>VÝ dơ 4. Cho biÕt kÕt qu¶ thùc hiện chơng trình sau:</i>


program vd4;
uses crt;
var


a, b : integer;


procedure doi_cho(a, b : integer);
var


t : integer;
begin


t := x; x := y; y := t;
end;


begin
clrscr;


a := 5; b := 7;
doi_cho(a, b);


writeln('a=',a,', b=',b);
readln;


end.


<i>Giải</i>



- Chơng trình này sau khi chạy sẽ in ra màn hình:


a=5, b=7


Vỡ cỏc tham số của chơng trình con truyền theo trị, do đó nó chỉ đổi giá trị hai bản sao.


- Để đổi giá trị của hai biến a, b thì cần sửa ở chơng trình con nh sau:


procedure doi_cho(<b>var</b> a, b : integer);


<i>Ví dụ 5. Chơng trình phân số tối giản:</i>


- Đầu vào nhập tử số, mẫu số là 2 số nguyên dơng.


- Đầu ra in ra dạng tối giản của phân sè.
<i>Gi¶i</i>


program vd5;
uses crt;
var


tu, mau, d : integer;


function ucln(var a, b : integer) : integer;
var


r : integer;
begin



r := a mod b;
while r <> 0 do
begin


</div>
<span class='text_page_counter'>(6)</span><div class='page_container' data-page=6>

ucln := b;
end;


begin
clrscr;


write('Tu so = '); readln(tu);
write('Mau so = '); readln(mau);
d := ucln(tu, mau);


writeln('Phan so toi gian la: ', tu div d, '/', mau div d);
readln;


end.


- Khi chạy chơng trình cho kết quả khơng đúng (ví dụ, nếu tử số bằng 8, mẫu số bằng 12 thì
chơng trình cho kết quả là 2/1) là do khai báo tham số hình thức ở chơng trình con đã khai
báo tham biến. Sau khi thực hiện chơng trình xong chơng trình con thì giá trị của tử số và
mẫu số đều thay đổi.


- Để chơng trình chạy đúng, ta bỏ từ khố var trong khai báo tham số của chơng trình con:


function ucln(a, b : integer) : integer;


<i>Ví dụ 6. Chơng trình sau gồm một chơng trình con tính giá trị của hàm F(x) = x + 1. Sau đó </i>
đ-a kết quả (F(đ-a))2<sub> ra màn hình.</sub>



<i>Gi¶i</i>


program vd6;
uses crt;
var


a : integer;


function f(var x : integer) : integer;
begin


x := x + 1;
f := x;
end;
begin
clrscr;
a := 5;


writeln(f(a)*f(a));
readln;


end.


- Khi chạy chơng trình thì kết quả: 42 (= 6.7). Vì tham số đầu vào của chơng trình con là
truyền theo biến và trong chơng trình con có câu lệnh làm thay đổi giá trị tham số. Do đó
khi thực hiện nó sẽ gọi chơng trình con F(a) = 6 lần thứ nhất và lúc đó biến a = 6, quay lại
lần thứ hai: F(a) = 7. Do đó kết quả là 42.


- Để đạt đợc kết quả: 36 (= 6.6) cần bỏ từ khoá var trong phần khai báo tham số, khi đó


lệnh trong chơng trình con khơng làm thay đổi giá trị của a.


<b>7. CÊp ph¸t bé nhí cho ch ¬ng tr×nh con</b>


Việc cấp phát bộ nhớ cho chơng trình con (biến địa phơng) đợc thực hiện trong vùng bộ nhớ
Stack, trong khi việc cấp phát cho các biến trong chơng trình chính (biến tồn cục) đợc thực
hiện trong vùng bộ nhớ data. Trong quá trình chạy chơng trình, mỗi khi gọi chơng trình con,
các biến của nó đợc cấp phát và cho đến khi chơng trình con kết thúc, các biến này đợc tự
động giải phóng. Nh vậy vùng cấp phát cho chơng trình con đợc gọi ở mức trong cùng sẽ đợc
giải phóng đầu tiên. Nhờ vậy, các biến của chơng trình chính là độc lập với các biến của
ch-ơng trình con và các biến của chch-ơng trình con này là độc lập với các biến của chch-ơng trình con
khác, mặc dù chúng trùng tên.


</div>
<span class='text_page_counter'>(7)</span><div class='page_container' data-page=7>

{$M stackSize, HeapMin, HeapMax}


trong chơng trình để tăng giá trị stackSize hoặc vào chức năng Option/Memory size của môi
trờng Turbo Pascal đặt lại giá trị cho kích thớc stack.


<b>8. Ch ơng trình con đệ quy</b>


Chơng trình con đệ qui là chơng trình con mà trong lịng nó lại gọi chính nó. Khái niệm đệ
qui là đang xây dựng nó lại dùng chính nó. Thơng thờng để xây dựng khái niệm mới thì phải
dùng khái niệm cũ, do đó đệ qui phải có điểm dừng. Khái niệm đệ quy giống với khái niệm
quy nạp trong tốn học, ví dụ nh hàm n giai thừa:















0


)!1



(



0


1



!



<i>n</i>


<i>n</i>




nÕu




nÕu





<i>n</i>


<i>n</i>



<i>n</i>



Đối với các chơng trình con đệ qui thì chơng trình dịch sẽ làm việc vất vả. Nếu chơng trình
con đệ qui khơng có điểm dừng hoặc điểm dừng q sâu thờng dẫn đến lỗi tràn stack (stack
overflow error).


<i>VÝ dô 7. Thiết kế hàm giai thừa.</i>
<i>Giải</i>


Dựng hm cú tớnh qui:


function gt(n : integer) : integer;
begin


if n = 0 then gt := 1


else gt := n * gt(n-1);
end;


 Thiết kế hàm giai thừa mà không đệ qui:


function gt(n : integer) : integer;
var


i, t : integer;
begin


t := 1;


for i := 1 to n do t := t * i;


gt := t;


end;


Về mặt logíc, hai hàm trên đều cho kết quả nh nhau, nhng về mặt hệ thống, chúng hoàn toàn
đợc thực hiện khác nhau. Khi tính n! , hàm thứ nhất đợc gọi một số lần tỉ lệ với n, trong khi
hàm thứ hai gọi một lần không phụ thuộc vào n. Trớc khi nói về u điểm, nhợc điểm của chơng
trình con đệ quy, ta xét tiếp ví dụ sau.


<i>VÝ dơ 8. Thiết kế hàm tính số hạng thứ n của dÃy Fibonaci:</i>
<i>F1 = F2 = 1</i>


<i>Fn = Fn - 2 + Fn - 1</i> víi n > 2
<i>Gi¶i</i>


 Xây dựng hàm F đệ qui để tính:


function f(n : integer) : integer;
begin


if n < 3 then f := 1


else f := f(n-2) + f(n-1);
end;


Giả sử để tính F(5), thì lời gọi F(5) sẽ kéo theo các lời gọi sau:


7
<i>F(5)</i>



<i>F(3)</i> <i>F(4)</i>


<i>F(2)</i> <i>F(1)</i> <i>F(3)</i> + <i>F(2)</i>


</div>
<span class='text_page_counter'>(8)</span><div class='page_container' data-page=8>

Trong sơ đồ trên, số phép cộng là 4, trong đó F(3) đợc tính lại 2 lần, F(2) đợc tính lại 3 lần.
Các con số này cũng đợc lũy tiến theo n. Vùng nhớ stack đợc cấp phát tỷ lệ với giá trị n.


 Thiết kế hàm Fibonaci không đệ qui: cần dùng 3 biến (2 biến luân chuyển)


function f(n : integer) : integer;
var


x, y, z, i : integer;
begin


x := 1; y := 1;
for i := 3 to n do
begin


z := x + y;
x := y;
y := z;
end;
f := y;
end;


Về mặt hình thức, hàm này viết phức tạp hơn cách trớc, tuy nhiên về mặt tính tốn và sử dụng
bộ nhớ, nó hiệu quả hơn nhiều. Các giá trị đợc tính đúng một lần, số phép cộng phải thực hiện
bằng n-2 (tuyến tính theo n), bộ nhớ cấp phát không tăng theo n. Dới đây là một vài giá trị để
bạn so sánh:



<i>n</i> 31 32 33 34 35


Số phép + (không đệ quy) 29 30 31 32 33


Số phép + (đệ quy) 1.346.268 2.178.308 3.524.577 5.702.886 9.227.464
Nh vậy, một điểm lợi hiển nhiên khi dùng đệ quy là tiết kiệm công sức cho ngời lập trình.
Hàm gt, f trong cách cài đặt đệ quy trên là chép lại cơng thức quy nạp. Một bài tốn phát
biểu bằng quy nạp toán học dễ dàng đợc cài đặt bằng đệ quy. Tuy nhiên việc dùng đệ quy
th-ờng trả giá cho sự tốn kém về bộ nhớ và số phép toán cần thực hiện.


Trong kỹ thuật lập trình hiện nay, có cả một lĩnh vực chun nghiên cứu việc khử đệ quy
nhằm năng cao tính hiệu quả của chơng trình. Nói chung, bạn khơng nên lạm dụng đệ quy
trong những tình huống nh ví dụ vừa nêu.


Mặc dù vậy, đệ quy khơng phải là khơng có ích. Những bài tốn có tính quy nạp, nó tiết kiệm
cơng sức lập trình rất nhiều. Nhiều tình huống, nếu khơng dùng đệ quy thì việc cài đặt trở nên
rất phức tạp. Một ví dụ điển hình là bài tốn Tháp Hà Nội.


<i>Ví dụ 9 (bài tốn Tháp Hà Nội). Có 3 cọc đợc đánh số là 1, 2, 3. Trên một cọc đặt tại vị trí a</i>
có n đĩa kích thớc từ nhỏ đến lớn đợc xếp sao cho đĩa nhỏ nằm trên đĩa lớn. Cần phải chuyển
<i>n đĩa từ cọc đặt tại vị trí a sang cọc đặt tại vị trí b theo nguyên tắc:</i>


 Mỗi bớc chỉ di chuyển 1 đĩa;


 Trong q trình di chuyển khơng đợc để đĩa lớn trên đĩa bé;


 ViƯc di chun cho phép dùng một vị trí thứ 3 gọi là vị trí trung gian.
Chẳng hạn, với n = 3, a = 1, b = 2 ta cã 7 bíc chun nh sau:



1) 1  2 (Chuyển đĩa nhỏ nhất từ vị trí ban đầu sang vị trí tập kết)
2) 1  3


3) 2  3
4) 1  2
5) 3  1
6) 3  2
7) 1  2
<i>Gi¶i</i>


Để xây dựng cách chuyển đĩa, ta dùng phơng pháp qui nạp:


 Với n = 1 đĩa  xong;


</div>
<span class='text_page_counter'>(9)</span><div class='page_container' data-page=9>

(i) Chuyển n-1 đĩa từ vị trí ban đầu đến vị trí trung gian.
(ii) Chuyển đĩa lớn nhất từ vị trí ban đầu đến vị trí tập kết.
(iii) Chuyển n-1 đĩa từ vị trí trung gian sang vị trí tập kết.


Ta có thể chứng minh bằng quy nạp đợc rằng: số bớc ít nhất để chuyển n đĩa từ vị trí ban đầu
đến vị trí tập kết là: 2<i>n</i><sub> - 1 (*).</sub>


ThËt vËy:


 Với n = 1 đĩa thì số bớc chuyển ít nhất là: 21<sub> - 1 = 1 bớc </sub><sub></sub><sub> (*) đúng với n = 1;</sub>


 Giả sử để chuyển n-1 đĩa thì ta phải mất ít nhất là: (2<i>n</i> - 1<sub> - 1) bớc. Khi đó theo cách giải bài</sub>
tốn tháp Hà Nội thì số bớc chuyển n đĩa ít nhất là tổng số bớc chuyển ít nhất của (i), (ii),
(iii) và bằng:


(2<i>n</i> - 1<sub> - 1) + 1 + (2</sub><i>n</i> - 1<sub> - 1) = 2</sub><i>n</i><sub> - 1</sub>


<b>Cài đặt:</b>


program thap_ha_noi;
uses crt;


var


n, a, b : integer;


procedure chuyen_dia(n, a, b : integer);


{ Chuyển n đĩa từ a sang b. Cọc trung gian sẽ là 6-a-b }


begin


if n = 1 then writeln(a,'-->',b)
else begin


chuyen_dia(n-1, a, 6-a-b);
chuyen_dia(1, a, b);


chuyen_dia(n-1, 6-a-b, b);
end;


end;
begin
clrscr;


write('n = '); readln(n);



write(‘a, b = ’); readln(a, b);
chuyen_dia(n, a, b);


</div>

<!--links-->

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×