Hoc roi thay yeu tin hoc lien
Chia sẻ bởi Nguyễn Nguyễn Ngọc An |
Ngày 02/05/2019 |
54
Chia sẻ tài liệu: hoc roi thay yeu tin hoc lien thuộc Bài giảng khác
Nội dung tài liệu:
chương trình con
(CTC)
Nguyễn Minh Ngọc Lớp 11 Toán
Trường THPT Sơn Tây - Sơn Tây - Hà Nội
Khóa 48 (2007 - 2010)
Bạn đang đọc bài của Nguyễn Minh Ngọc - Lớp 11 Toán - THPT Sơn Tây về CHƯƠNG TRìNH CON. Chuyên đề này được chia làm phần:
Khái niệm và phân loại CTC, cách dùng các loại CTC, các loại biến trong CTC cũng như sự khác nhau giữa chúng
Cách dùng tham số và cấp phát bộ nhớ cho CTC
CTC đệ quy, thiết kế giao diệm Menu, Phương pháp Top-Down và một số bài tập
Mọi thắc mắc, đóng góp cin liên hệ theo địa chỉ:
[email protected]
KháI niệm:
?Chương trình là một dãy các lệnh được xây dựng cho máy tính nhằm hoàn thành một công việc nào đấy. Các chương trình như vậy được gọi là chương trình con
?Chương trình chính là chương trình ở mức ngoài cùng được gọi bởi người sử dụng
Vai trò của chương trình con
Cho phép phân rã những 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 tra toà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 việc thiết kế, che giấu nội tại. Cho phép xây dựng những chương trình lớn, có nhiều người tham gia.
Là phương tiện thực hiện 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ó cấu trúc.
Cho phép xây dựng thư việc 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 việc viết chương trình.
Khai báo chương trình con
Mỗi chương trình con đều phải đặt tên theo nguyên tắc chung của hệ thống.
Các chương trình con được gọi trong một chương trình cần được hệ thống nhận biết. Bất cứ 1 tên chương trình nào xuất hiện trong lời gọi mà hệ thống không hiểu, đều được nhận lỗi unknown identifier khi biên dịch
Những chương trình con được hệ thống nhận biết sẵn là những chương trình con của hệ thống và những chương trình con đã được biên dịch trong các thư viện đã liên kết với chương trình. Các chương trình con còn lại đều phải khai báo trước chương trình chính.
Phân loại chương trình con
Thủ tục (procedure)
Khái niệm: 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 đó.
Thành phần:
? Phần đầu (tiêu đề)
? Phần khai báo
? Phần thân (phần câu lệnh)
Thủ tục (procedure)
Phần đầu:
Procedure Tên thủ tục(dãy lệnh khai báo);
Ví dụ:
Thủ tục không có tham số:
Procedure nhap;
Thủ tục có tham số
Procedure Chuyen(x,y:integer);
Thủ tục (procedure)
Phần đầu
Procedure Tên thủ tục(dãy lệnh khai báo);
Lưu ý: Không được khai báo như sau:
Procedure nhap(var a: array[1..10] of byte);
Mà phải khai báo như sau:
Type mang = array[1..10] of byte;
Procedure nhap(var a: mang);
Phần khai báo:
Phần khai báo của thủ tục giống như phần khai báo của chương trình chính. Nó chứa các đối tượng riêng mà thủ tục đó dùng, bao gồm: Hằng, Biến, Kiểu, Các chương trình con (nếu có) của thủ tục
Thủ tục (procedure)
Phần thân
Phần thân của thủ tục cũng mô tả các công việc mà thủ tục đó thực hiện
Bắt đầu bằng từ khóa BEGIN và kết thúc bằng từ khóa END và dấu chấm phẩy `;`
Gọi thủ tục
Với thủ tục không có tham số, ta chỉ việc viết tên thủ tục trong câu lệnh
Ví dụ: Nhap;
Với thủ tục có tham số, ta phải truyền các giá trị tham số cho lời gọi thủ tục. Các giá trị này phân cách nhau bởi dấu phẩy, theo đúng thứ tự và đảm bảo tính tương thích kiểu như khai báo.
Ví dụ: Chuyen(2,1)
Nhập một xâu kí tự bất kì rồi hiện ra màn hình ở vị trí căn giữa màn hình.
Program Vidu1;
Type st=string[80];
PROCEDURE cangiua(s: st);
Begin
writeln(` `: (80-length(s)) div 2, s);
End;
BEGIN
cangiua(`XIN CHAO`);
cangiua(`NGUYEN MINH NGOC`);
cangiua(`11 TOAN - THPT SON TAY`);
readln;
END.
Hàm (function)
Khái niệm: Hàm là một chương trình con nhằm tính toán và trả lại một giá trị nào đó.
Thành phần:
? Phần đầu (tiêu đề)
? Phần khai báo
? Phần thân (phần câu lệnh)
Hàm (function)
Khai báo:
function Tên hàm(dãy lệnh khai báo):kiểu giá trị trả lại;
Lưu ý:
?Điểm khác biệt với thủ tục là phần khai báo của hàm cần khai báo thêm kiểu giá trị trả lại hàm, sau dấu hai chấm.
?Turbo Pascal chỉ cho phép kiểu giá trị của hàm là một trong những kiểu chuẩn của nó đã được định danh như byte, integer, longint, char, string, boolean, .không cho phép các kiểu phức hợp như record, array
Hàm (function)
Khai báo:
function Tên hàm(dãy lệnh khai báo):kiểu giá trị trả lại;
Lưu ý:
?Giá trị của hàm phải được xác định bằng 1 lệnh gán nào đó cho tên hàm
?Hàm có thể xuất hiện ở những chỗ thích hợp như giá trị của toán hạng trong biểu thức, giá trị ở vế phải trong 1 phép gán, giá trị truyền vào tham số của thủ tục, hàm, .
Tìm UCLN của 2 số nguyên a và b bằng thuật toán Euclide
Program vidu2;
Var a,b: integer;
FUNCTION UCLN(a,b:integer):integer;
Begin
WHILE a <> b DO
IF a > b THEN a:= a-b ELSE a:= b-a;
UCLN:= a;
End;
BEGIN
wrtieln(`Nhap cac so nguyen a,b = `);
readln(a,b);
writeln(`UCLN cua cac so da cho:`, UCLN(a,b));
readln;
END.
Khi cần thực hiện 1 công việc nào đó ta dùng thủ tục, còn khi cần tính 1 giá trị nào đó, ta dùng hàm, song điều này là không bắt buộc.
Bất cứ công việc nào được thực hiện bởi thủ tục đều thực hiện được bằng hàm và bất cứ công việc nào được thực hiện bởi thủ tục đều tính được nhờ thủ tục.
Lưu ý về thủ tục và hàm:
Thông thường, khi thực hiện hết các lệnh thì CTC tự kết thúc, song có thể thoát khỏi CTC ở bất kì chỗ nào trong phần câu lệnh bằng 1 trong các thủ tục sau:
EXIT; : Thoát khỏi chương trình con song vẫn còn nằm trong chương trình chính
HALT; : Thoát khỏi chương trình thực hiện (dừng hẳn tất cả các công việc đang thực hiện)
Thoát khỏi chương trình con
địa phương & toàn cục
Những đối tượng (hằng, biến, hàm, thủ tục) khai báo trong chương trình chính được dùng cho toàn bộ khối chương tình và các khối con khác của nó. Chúng được gọi là toàn cục (chung)
Nếu khai báo những đối tượng trên trong 1 chương trình con, thì những biến này chỉ được dùng trong CTC đó và trong các khối con của nó. Chúng được gọi là địa phương (riêng)
Khái niệm địa phương và toàn cục chỉ có tính tương đối
ví dụ về sự khác nhau giữa
địa phương và toàn cục
Program Vidu2;
Var i:integer;
PROCEDURE ktra;
Var i: integer;
Begin
i:= 5;
End;
BEGIN
i:=1;
ktra;
writeln(`i = `, i);
readln;
END.
ví dụ về sự khác nhau giữa
địa phương và toàn cục
Bạn hãy đoán xem kết quả chương trình trên biến i sẽ hiện ra màn hình là bao nhiêu ?
Chắc là nhiều bạn sẽ bất ngờ và không tin vào kết quả này. Biến i sẽ nhận giá trị là 1 mà không phải là 5. Đó chính là điểm khác biệt giữa biến toàn cục và biến địa phương. Lí do thủ tục ktra không gây ảnh hưởng gì đến giá trị i vì biến i trong ktra khác biến i của chương trình. Qua ví dụ này, ta thấy nếu biến riêng trùng tên với biến bên ngoài thì CTC luôn ưu tiên biến riêng của nó và như thế không thể truy cập biến bên ngoài được.
ví dụ về sự khác nhau giữa
địa phương và toàn cục
Program Vidu3;
Var a,b:integer;
PROCEDURE nhap;
Var a,b: integer;
Begin
writeln(`Nhap vao 2 so nguyen a,b:`);
readln(a,b);
writeln(`Cac gia tri da nhap: a=`,a,`;b=`,b);
End;
BEGIN
nhap;
writeln(`Tong cua 2 so da nhap: `, a+b);
readln;
END.
ví dụ về sự khác nhau giữa
địa phương và toàn cục
Còn giờ bạn nghĩ gì về chương trình này?
Chương trình này không đơn giản là thông báo tổng của 2 số nguyên được nhập từ bàn phím qua việc dùng thủ tục nhap, song kết quả không được như ý muốn. Lỗi ở đây là thủ tục nhpa khai báo các biến chứa các giá trị được nhập cũng như những biến riêng, trong khi chương trình chính cần dùng chúng như những biến toàn cục. Để kết quả như ý muốn thì chỉ cần bỏ dòng khai báo 2 biến a, b trong thủ tục nhap
Qua những ví dụ trên, ta thấy các ngôn ngữ lập trình có cấu trúc cao như Pascal thường đòi hỏi rất chặt chẽ về mặt khai báo. Điều này có vẻ nhiêu khê cho nhiều người, nhất là những người mới học lập trình.Việc cẩn thận trong quá trình khai báo sẽ giúp bạn dễ dàng nâng cao được chương trình, cũng như tránh được các hiểm họa của những lỗi logic rất khó phát hiện, tiết kiệm thời gian khi sửa đổi và phát triển chương trình, đặ biệt trong việc xây dựng các chương trình lớn, cần nhiều người tham gia.
Vai trò của tham số
Các tham số khai báo ở đầu CTC dùng để gửi các giá trị vào chương trình xử lý, cũng như là nơi lấy các kết quả ra mà chương trình đã xử lý xong.
Không được khai báo các biến riêng của CTC trùng với tên các tham số của nó
Tham số hình thức là các tham số chỉ được truyền giá trị từ bên ngoài vào khi xuất hiện lời gọi CTC và CTC sẽ được hoạt động với bộ giá trị đó.
Tham số thực là các tham số bên ngoài được truyền vào CTC (hay nói cách khác các tham số này tham gia chươngtirnfh con với tư các là một giá trị)
Khi truyền tham số cho CTC, cần phải đảm bảo việc truyền là tương ứng 1-1, đúng thứ tự vào tương thích kiểu
ví dụ các kiểu truyền tham số lỗi:
Thủ tục:
Procedure ve(i, j: integer; t, h: word);
Truyền tham số:
ve(5, -1, 7); {không tương ứng 1 -1}
ve(-1, 3, 4, 1.5) {không tương thích kiểu}
Phân loại các cách truyền tham số:
Truyền theo trị
Việc truyền theo trị được thực hiện qua bản sao. Giá trị bên ngoài được chép vào 1 vùng nhớ được cấp phát tương ứng với kích thước tham số.
CTC sẽ làm việc với dữ liệu chứa trong bản sao
Truyền theo trị
Việc truyền theo trị được thực hiện qua bản sao.
Nếu trong CTC có những lệnh làm thay đổi giá trị của tham số hình thức thì những thay đổi này không có ảnh hưởng gì đến giá trị của biến được truyền ở đầu vào vì những thay đổi này chỉ được thực hiện trên bản sao tương ứng.
Tốn 1 ít bộ nhớ và thời gian cho việc sao chép
Cho phép giá trị ở đầu vào có thể là những giá trị của hằng, biến, hàm hoặc biểu thức. Nếu đầu vào truyền hàm hoặc biểu thức thì những giá trị này được tính trước khi truyền cho tham số. Giá trị bên ngoài được chép vào 1 vùng nhớ được cấp phát tương ứng với kích thước tham số
Đặc điểm:
Truyền theo biến
Nếu trong CTC có những lệnh làm thay đổi giá trị của tham số hình thức thì những thay đổi này cũng chính là những thay đổi trên biến được truyển
Không tốn thêm bộ nhớ và thời gian do không phải sao chép
Chỉ cho phép đầu vào là giá trị của biến
Việc truyền tham số theo biến được thực hiện vào chính địa chỉ của biến được truyền
Đặc điểm:
Khai báo
* Truyền theo trị:
Tên tham số: kiểu tham số
* Truyền theo biến:
VAR Tên tham số: kiểu tham số
Việc truyền theo trị hay truyền theo biến nhiều khi dẫn đến những kết quả logic khác nhau. Sự khác nhau này được gọi là hiệu ứng lề.
Ví dụ:
Program vidu;
VAR a: integer;
Function F(var x: integer): integer;
Begin
x:= x+1;
F:= x;
End;
BEGIN
a:= 5;
writeln(F(a)+F(a));
readln;
END.
Một sự thật mà khó có thể giải thích được đối với những người mới làm quen với lập trình. Kết quả sẽ là 13 mà không phải là 12. Lí do là ở đây đã xuất hiện hiệu ứng lề. Do hàm F được tổ chức truyền theo biến đối với đối số x của nó. Lệnh x:= x+1 trong hàm F sẽ làm biến a tăng thêm 1 đơn vị mỗi khi gọi F(a). Khi thực hiện biểu thức F(a)+F(a), giá trị F(a) được gọi 2 lần. Tại lần thứ nhất a = 5, do đó F(a) = 6, tại lần thứ hai a = 6 do đó F(a)= 7 và ta nhận được kết quả là 13.
Bạn thư nhận đoán xem kết quả của chương trình trên đưa lại là bao nhiêu?
Ví dụ:
Để sửa lại chương trình cho đúng ý muốn ban đầu, ta có 2 cách sửa:
Sửa biểu thức F(a)+F(a) thành 2*F(a)
Sửa lại việc truyền cho đối số x của hàm F là theo trị
Ví dụ:
Một số chương trình lỗi hay mắc phải do cách truyền tham số không đúng:
Program Vidu;
Var x,y: integer;
Procedure Chuyen_doi(x, y: integer);
Var t: integer;
Begin
t:=x; x:=y; y:=t;
End;
BEGIN
x:=1; y:=2;
Chuyen_doi(x,y):
Writeln(`x=`,x,`y=`,y);
Readln
END.
Một số chương trình lỗi hay mắc phải do cách truyền tham số không đúng:
Lỗi ở chương trình này là thủ tục Chuyen_doi(x,y) tổ chức tuyền theo trị nên các giá trị của biến x, y không bị ảnh hưởng bởi câu lệnh đổi giá trị trong thủ tục này.
Cách sửa:
Thêm từ khóa VAR trước tên tham số x, y
Một số chương trình lỗi hay mắc phải do cách truyền tham số không đúng:
Program Vidu;
Var tu, mau, d: integer;
Function UCLN(var a,b: integer): integer;
Begin
While a <> b do
If a>b then a:=a-b else b:=b-a;
UCLN:= a;
End;
BEGIN
Writeln(`nhap tu so va mau thuc cua phan so:);
Readln(tu, mau);
d:=UCLN(tu,mau);
writeln(`Dang toi gian cua phan so da cho la: `,tu/d, `/`,mau/d);
readln;
END.
Một số chương trình lỗi hay mắc phải do cách truyền tham số không đúng:
Chương trình trên luôn cho kết quả là 1/1.
Lỗi: do hàm UCLN được truyền theo biến, nên sau lời gọi d:=UCLN(tu, mau) ta được đồng thời các giá trị tu, mau đều bằng nhau
Sửa: bỏ từ khóa VAR trước tên a,b
Truyền theo trị hay truyền theo biến?
Nếu trong thân CTC có những lệnh làm thay đổi giá trị tham số hình thức thì việc truyền theo biến hay truyền theo trị không gây ra 1 sự khác biệt nào về kết quả mà chương tình con trả lại
Trong các trường hợp việc truyền theo biến hay truyền theo trị không ảnh hưởng đến kết quả logic của chương trình thì người ta thường chọn cách truyền theo trị cho các tham số thuộc kiểu chuẩn như integer, char, boolean, real, . còn các tham số thuộc kiểu phức hợp như mảng, bảng ghi, . thì truyền theo biến. Riêng tham số kiểu File hoặc tham số không định kiểu thì luôn phải tổ chức truyền theo biến
Truyền theo trị hay truyền theo biến?
Trong các trường hợp việc truyền theo biến hay truyền theo trị không ảnh hưởng Khi CTC có những lệnh làm thay đổi giá trị tham số hình thức thì phải truyền vào nhiệm vụ của CTC đối với tham số mà quyết định cách truyền:
? Nếu CTC có nhiệm vụ phải thay đổi giá trị tham số thực thì phải tổ chức truyền theo biến cho tham số này
? Nếu tham số thực sự được dùng để gửi giá trị ở đầu vào cho CTC hoạt động mà không được làm hỏng giá trị này sau khi gọi CTC thì phải tổ chức truyền theo trị cho tham số này. Nếu kết quả logic của chương trình thì người ta thường chọn cách truyền theo trị cho các tham số thuộc kiểu chuẩn như integer, char, boolean, real, . còn các tham số thuộc kiểu phức hợp như mang, bảng ghi, . thì truyền theo biến. Riêng tham số kiểu File hoặc tham số không địh kiểu thì luôn phải tổ chức truyền theo biến
Cấp phát bộ nhớ cho ctc
Việc cấp phát bộ nhớ cho các biến trong CTC (biến địa phương) được thực hiện trong vùng stack (ngăn xếp), trong khi việc cấp phát cho các biến trong chương trình chính (biến toàn cục) được thực hiện trong vùng nhớ data (dữ liệu).
Trong quá trình chạy chương trình, mỗi khi gọi CTC, các biến của nó sẽ được cấp phát cho đến khi CTC kết thúc, các biến này lại tự động giải phóng.
Vùng cấp phát cho CTC được gọi ở mức trong cùng sẽ giải phóng đầu tiên (vào sau ra trước)
Cấp phát bộ nhớ cho ctc
Do vậy, các biến của CTC độc lập với các biến của chương trình chính, các biến của CTC này độc lập với các biến của CTC khác cho dù nó cùng tên.
Nếu khai báo quá nhiều biến địa phương trong CTC thì khi gọi CTC này có thể bị lỗi tràn stack (stack overflow)
Hiện nay, Turbo Pascal 7.0 ngầm định dành sẵn 16Kb cho vùng stack
Cách tăng gái trị StackSize:
? Dùng định hướng biên dịch
{M StackSize, HeapMin, HeapMax}
? Vào Options/MemorySize của môi trường Turbo Pascal để đặt lại giá trị cho kích thước stack
Chương trình con đệ quy
Khái niệm:
CTC đệ quy là CTC trong khi đang xây dựng lại được gọi chính nó.
Một CTC con đệ quy cũng tương tự như một bài toán được chứng minh bằng phương pháp quy nạp.
ví dụ
Bài toán:
Tính n!
Thuật toán giải:
Cách 1:
n! = 1.2.3. . .(n-1).n
Cách 2: (Tính theo phương pháp đệ quy)
1! = 1
n! = (n-1)!.n
Tính n!
Cách 1:
Function Giaithua(n: integer):LongInt;
Var i: integer;
p: LongInt;
Begin
p:=1;
for i:=1 to n do p:=p*i;
Giaithua:=p;
End;
Tính n!
Cách 2:
Function Giaithua(n: integer):LongInt;
Begin
if n < 2 then Giaithua:= 1
else Giaithua:=Giaithua(n-1) * n;
End;
Tính n!
Nhận xét:
Mặc dù về logic, 2 hàm trên cho kết quả như nhau, nhưng về mặt hệ thống, chúng hoàn toàn được thực hiện khác nhau
? Hàm thứ nhất được gọi 1 lần không phụ thuộc vào giá trị n
? Hàm thứ 2 được gọi 1 số lần tỷ lệ với n. Khi dùng hàm thứ 2 thì tiết kiệm công sức cho người lập trình song việc dùng hàm thứ 2 phải tốn bộ nhớ và số phép toán thực hiện nhiều
Một số bài toán dùng chương trình đệ quy
Xây dựng CTC đệ quy trả về số hạng thứ n của dãy Fibonaci (với n được nhập từ bàn phím trong chương trình chính)
Chương trình:
Function F(n: integer): LongInt;
Begin
if n < 3 then F:= 1
else F:=F(n-1)+F(n-2);
End;
Một số bài toán dùng chương trình đệ quy
Bài toán tháp Hà Nội:
Có một chồng gồm n cái đĩa, đĩa nhỏ được xếp trên đĩa lớn. Cần phải chuyển chồng đĩa này đến một vị trí khác theo nguyên tắc: mỗi lần chỉ chuyển 1 đĩa và chỉ được xếp đĩa nhỏ trên đĩa lớn. Trong quá trình chuyển, cho phép dùng một vị trí thứ 3 làm trung gian. Hãy xây dựng CTC thực hiện công việc này.
Một số bài toán dùng chương trình đệ quy
Procedure chuyen_dia(n, a, b, c: integer);
Begin
if n > 0 then
begin
chuyen_dia(n-1, a, c, b);
writeln(a, `-->`, b);
chuyen_dia(n-1, c, b, a);
end;
End;
Chú ý:
Khi thiết kế đệ quy, phải đảm bảo điều kiện điểm dừng. Nếu quên điều này thì lời gọi chương trình đệ quy không kết thúc và sẽ gây ra lỗi tràn stack. Để khắc phục việc tràn stack khi dùng đệ quy, bạn cần thực hiện một số kỹ thuật sau:
?Đảm bảo sự có mặt điểm dừng trong thân CTC đệ quy
?Giảm tối đa các biến riêng cũng như các tham trị của CTC đệ quy, đặc biệt đối với những biến kích thước lớn như bảng ghi, mảng
?Tăng kích thước stack mà hệ thống dành cho chương trình
Thiết kế giao diện menu
Chương trình dưới đây, tôi muốn giúp các bạn tạo một cái khung cho một chương trình có dạng Menu, song xin lưu ý đây chỉ là cái khung để các bạn dựa vào và thiết kế chứ không phải là một Menu hoàn chỉnh:
Menu gồm có:
? Menu chính
? Mục 1
? Mục 2
? Trợ giúp
? Thoát
Thiết kế giao diện menu
Program Menu;
Ues CRT;
Funtion Menu: char;
Begin
ClrScr;
writeln(`Menu chinh`);
writeln(`=========`);
writeln(`1. Muc 1`);
writlen(`2. Muc 2`);
writeln(`3. Tro giup`);
writeln(`4. Thoat`);
writeln;
writeln(`Nhap mot lua chon.`);
Repeat
menu:= readkey;
Until Menu in [`1`..`4`];
End;
Thiết kế giao diện menu
Procedure Muc1;
Begin
ClrScr;
writeln(`Day la Muc 1`);
writeln(`An ENTER de ve Menu chinh`);
readln;
End;
Procedure Muc2;
Begin
ClrScr;
writeln(`Day la Muc 2`);
writeln(`An ENTER de ve Menu chinh`);
readln;
End;
Thiết kế giao diện menu
Procedure Trogiup;
Begin
ClrScr;
writeln(`Day la Tro giup`);
writeln(`An ENTER de ve Menu chinh`);
readln;
End;
BEGIN
Repeat
case Menu of
`1`: Muc1;
`2`: Muc2;
`3`: Trogiup;
`4`: Halt;
End;
until false;
END.
Phương pháp top - down
Khái niệm:
Phương pháp lập trình Top-Down là phương pháp lập trình từ tổng thể đến chi tiết, cho phép phân rã một công việc phức tạp thành nhiều công việc đơn giản hơn.
Phương pháp Top-Down là phương pháp cơ bản hiện nay trong lập trình cấu trúc. Nhờ phương pháp này, việc lập trình mang tính công nghệ cao, cho phép xây dựng các chương trình lớn, nhiều người tham gia, thuận tiện cho việc bảo trì và mở rộng
Phương pháp top - down
Ví dụ:
Trên mặt phẳng, xét 1 số dãy các đoạn thẳng, mỗi đoạn được xác định bởi 2 điểm dầu mút cảu chúng. Mỗi điểm trên mặt phẳng được xác định các lớp đồng phương của dãy đoạn đã cho. Lập trình giải bài toán nêu trên, dữ liệu nhập từ bàn phím, trong đó lần lượt từng đoạn thẳng được nhập các tọa độ cảu các điểm đầu mút. Kết quả đưa ra màn hình số lớp đồng phương và với mỗi lớp cần chỉ ra số hiệu các đoạn thuộc lớp đó. Các đoạn thẳng được đánh số từ 1, theo thứ tự nhập
Phương pháp top - down
Program Vidu;
Type
Kieudiem = record
x, y:real;
end;
Kieudoan = record
A, B: Kieudiem;
end;
Var
n, m: integer;
Doan: array[1..50]of Kieudiem;
Sohieu:array[1..50]og integer;
Phương pháp top - down
Procedure Nhap;
Var i: integer;
Begin
writeln(`Nhap so doan thang:`);
readln(n);
for i:= 1 to n do
begin
writeln(`Vao toa do doan `, i);
with Doan[i] do
begin
writeln(`Toa do dau mut thu nhat`);
readln(A.x,A.y);
writeln(`Toa do dau mut thu nhat`);
readln(B.x,B.y);
end;
end;
End;
Phương pháp top - down
Function Dongphuong(i,j: integer):boolean;
Begin
Dongphuong:= ABS ((Doan[i].B.x-Doan[i].A.x)* (Doan[j].B.y-Doan[j].A.y)-(Doan[i].B.y-Doan[i].A.y)*(Doan[j].B.x-Doan[j].A.x)<1e-9;
End;
Phương pháp top - down
Procedure Xacdinh;
Var i, j: integer;
Begin
for i:= 1 to n do Sohieu[i]:=0;
m:= 0;
for i:= 1 to n do
if Sohieu[i]=0 then
begin
inc(m);
Sohieu[i]:=m;
for j:= i+1 to n do
if Sohieu[j] = 0 then
if Dongphuong(i,j) then Sohiue[j]:=m;
end;
end;
Phương pháp top - down
Procedure Xem(k:integer);
Var i: integer;
Begin
for i:= 1 to n do
if Sohieu[i]=k then writeln(i:5);
writeln;
end;
Phương pháp top - down
Procedure XemKQ;
Var k: integer;
Begin
writeln (`So lop: `,m);
writeln (`Cac lop:`);
for k:= 1 to m do
begin
write(`Lop `,k, `:`);
Xem(k);
end;
End;
Phương pháp top - down
BEGIN
Nhap;
Xacdinh;
XemJKQ;
readln;
END.
Viết hàm Function Root(a:real; n:integer): real;
trả về giá trị với a là số thực dương, n là số nguyên dương
Function Root(a:real; n:integer):real;
Var kq: real;
Begin
kq:= exp(1/n*ln(a));
Root:=kq;
End;
Đường thẳng ax + by + c = 0 chia mặt phẳng thành 2 nửa dương và âm. Hãy xây dựng hàm
Function Vitri(a, b, c, u, v: real): integer;
Trả về vị trí:
? -1, nếu điểm có tọa độ (u, v) nằm ở nửa mặt phẳng âm
? 1, nếu điểm có tọa độ (u, v) nằm ở nửa mặt phẳng dương
? 0, nếu điểm có tọa độ (u, v) nằm trên đường thẳng
Function vitri (a, b, c, u, v: real): integer;
var f: real;
begin
f:=a*u+b*v+c ;
if f > 0 then vitri:=1
else if f < 0 then vitri:= -1
else vitri:=0;
end;
Cho kiểu dữ liệu được khai báo như sau:
type vector = array[1..200] of real;
Các kiểu A, b thuộc kiểu Vector:
A = (a1, a2, ., an)
B = (b1, b2, ., bn)
Hãy viết hàm
Function TichVH(var a,b: vector; n:byte):real;
tính tích vô hướng 2 vectơ A và B
Type vector = array[1..200] of real;
Function TichVH(Var a,b:vector; n: byte):real;
var i: integer;
kq:real;
Begin
kp:= 0;
for i:= 1 to n do
kp:= a[i]*b[i];
TichVH:=kp;
End;
Hãy mô tả hàm sumdigit(n) trả về giá trị là tổng các chữ số của n, trong đó n là số nguyến không âm thuộc kiểu LongInt
Function sumdigit(n:LongInt):byte;
Var t,chu: byte;
Begin
t:=0;
while t <> 0 do
begin
chu:= n mod 10;
t:= t + chu;
n:= n div 10;
end;
sumdigit:=t;
End;
(CTC)
Nguyễn Minh Ngọc Lớp 11 Toán
Trường THPT Sơn Tây - Sơn Tây - Hà Nội
Khóa 48 (2007 - 2010)
Bạn đang đọc bài của Nguyễn Minh Ngọc - Lớp 11 Toán - THPT Sơn Tây về CHƯƠNG TRìNH CON. Chuyên đề này được chia làm phần:
Khái niệm và phân loại CTC, cách dùng các loại CTC, các loại biến trong CTC cũng như sự khác nhau giữa chúng
Cách dùng tham số và cấp phát bộ nhớ cho CTC
CTC đệ quy, thiết kế giao diệm Menu, Phương pháp Top-Down và một số bài tập
Mọi thắc mắc, đóng góp cin liên hệ theo địa chỉ:
[email protected]
KháI niệm:
?Chương trình là một dãy các lệnh được xây dựng cho máy tính nhằm hoàn thành một công việc nào đấy. Các chương trình như vậy được gọi là chương trình con
?Chương trình chính là chương trình ở mức ngoài cùng được gọi bởi người sử dụng
Vai trò của chương trình con
Cho phép phân rã những 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 tra toà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 việc thiết kế, che giấu nội tại. Cho phép xây dựng những chương trình lớn, có nhiều người tham gia.
Là phương tiện thực hiện 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ó cấu trúc.
Cho phép xây dựng thư việc 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 việc viết chương trình.
Khai báo chương trình con
Mỗi chương trình con đều phải đặt tên theo nguyên tắc chung của hệ thống.
Các chương trình con được gọi trong một chương trình cần được hệ thống nhận biết. Bất cứ 1 tên chương trình nào xuất hiện trong lời gọi mà hệ thống không hiểu, đều được nhận lỗi unknown identifier khi biên dịch
Những chương trình con được hệ thống nhận biết sẵn là những chương trình con của hệ thống và những chương trình con đã được biên dịch trong các thư viện đã liên kết với chương trình. Các chương trình con còn lại đều phải khai báo trước chương trình chính.
Phân loại chương trình con
Thủ tục (procedure)
Khái niệm: 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 đó.
Thành phần:
? Phần đầu (tiêu đề)
? Phần khai báo
? Phần thân (phần câu lệnh)
Thủ tục (procedure)
Phần đầu:
Procedure Tên thủ tục(dãy lệnh khai báo);
Ví dụ:
Thủ tục không có tham số:
Procedure nhap;
Thủ tục có tham số
Procedure Chuyen(x,y:integer);
Thủ tục (procedure)
Phần đầu
Procedure Tên thủ tục(dãy lệnh khai báo);
Lưu ý: Không được khai báo như sau:
Procedure nhap(var a: array[1..10] of byte);
Mà phải khai báo như sau:
Type mang = array[1..10] of byte;
Procedure nhap(var a: mang);
Phần khai báo:
Phần khai báo của thủ tục giống như phần khai báo của chương trình chính. Nó chứa các đối tượng riêng mà thủ tục đó dùng, bao gồm: Hằng, Biến, Kiểu, Các chương trình con (nếu có) của thủ tục
Thủ tục (procedure)
Phần thân
Phần thân của thủ tục cũng mô tả các công việc mà thủ tục đó thực hiện
Bắt đầu bằng từ khóa BEGIN và kết thúc bằng từ khóa END và dấu chấm phẩy `;`
Gọi thủ tục
Với thủ tục không có tham số, ta chỉ việc viết tên thủ tục trong câu lệnh
Ví dụ: Nhap;
Với thủ tục có tham số, ta phải truyền các giá trị tham số cho lời gọi thủ tục. Các giá trị này phân cách nhau bởi dấu phẩy, theo đúng thứ tự và đảm bảo tính tương thích kiểu như khai báo.
Ví dụ: Chuyen(2,1)
Nhập một xâu kí tự bất kì rồi hiện ra màn hình ở vị trí căn giữa màn hình.
Program Vidu1;
Type st=string[80];
PROCEDURE cangiua(s: st);
Begin
writeln(` `: (80-length(s)) div 2, s);
End;
BEGIN
cangiua(`XIN CHAO`);
cangiua(`NGUYEN MINH NGOC`);
cangiua(`11 TOAN - THPT SON TAY`);
readln;
END.
Hàm (function)
Khái niệm: Hàm là một chương trình con nhằm tính toán và trả lại một giá trị nào đó.
Thành phần:
? Phần đầu (tiêu đề)
? Phần khai báo
? Phần thân (phần câu lệnh)
Hàm (function)
Khai báo:
function Tên hàm(dãy lệnh khai báo):kiểu giá trị trả lại;
Lưu ý:
?Điểm khác biệt với thủ tục là phần khai báo của hàm cần khai báo thêm kiểu giá trị trả lại hàm, sau dấu hai chấm.
?Turbo Pascal chỉ cho phép kiểu giá trị của hàm là một trong những kiểu chuẩn của nó đã được định danh như byte, integer, longint, char, string, boolean, .không cho phép các kiểu phức hợp như record, array
Hàm (function)
Khai báo:
function Tên hàm(dãy lệnh khai báo):kiểu giá trị trả lại;
Lưu ý:
?Giá trị của hàm phải được xác định bằng 1 lệnh gán nào đó cho tên hàm
?Hàm có thể xuất hiện ở những chỗ thích hợp như giá trị của toán hạng trong biểu thức, giá trị ở vế phải trong 1 phép gán, giá trị truyền vào tham số của thủ tục, hàm, .
Tìm UCLN của 2 số nguyên a và b bằng thuật toán Euclide
Program vidu2;
Var a,b: integer;
FUNCTION UCLN(a,b:integer):integer;
Begin
WHILE a <> b DO
IF a > b THEN a:= a-b ELSE a:= b-a;
UCLN:= a;
End;
BEGIN
wrtieln(`Nhap cac so nguyen a,b = `);
readln(a,b);
writeln(`UCLN cua cac so da cho:`, UCLN(a,b));
readln;
END.
Khi cần thực hiện 1 công việc nào đó ta dùng thủ tục, còn khi cần tính 1 giá trị nào đó, ta dùng hàm, song điều này là không bắt buộc.
Bất cứ công việc nào được thực hiện bởi thủ tục đều thực hiện được bằng hàm và bất cứ công việc nào được thực hiện bởi thủ tục đều tính được nhờ thủ tục.
Lưu ý về thủ tục và hàm:
Thông thường, khi thực hiện hết các lệnh thì CTC tự kết thúc, song có thể thoát khỏi CTC ở bất kì chỗ nào trong phần câu lệnh bằng 1 trong các thủ tục sau:
EXIT; : Thoát khỏi chương trình con song vẫn còn nằm trong chương trình chính
HALT; : Thoát khỏi chương trình thực hiện (dừng hẳn tất cả các công việc đang thực hiện)
Thoát khỏi chương trình con
địa phương & toàn cục
Những đối tượng (hằng, biến, hàm, thủ tục) khai báo trong chương trình chính được dùng cho toàn bộ khối chương tình và các khối con khác của nó. Chúng được gọi là toàn cục (chung)
Nếu khai báo những đối tượng trên trong 1 chương trình con, thì những biến này chỉ được dùng trong CTC đó và trong các khối con của nó. Chúng được gọi là địa phương (riêng)
Khái niệm địa phương và toàn cục chỉ có tính tương đối
ví dụ về sự khác nhau giữa
địa phương và toàn cục
Program Vidu2;
Var i:integer;
PROCEDURE ktra;
Var i: integer;
Begin
i:= 5;
End;
BEGIN
i:=1;
ktra;
writeln(`i = `, i);
readln;
END.
ví dụ về sự khác nhau giữa
địa phương và toàn cục
Bạn hãy đoán xem kết quả chương trình trên biến i sẽ hiện ra màn hình là bao nhiêu ?
Chắc là nhiều bạn sẽ bất ngờ và không tin vào kết quả này. Biến i sẽ nhận giá trị là 1 mà không phải là 5. Đó chính là điểm khác biệt giữa biến toàn cục và biến địa phương. Lí do thủ tục ktra không gây ảnh hưởng gì đến giá trị i vì biến i trong ktra khác biến i của chương trình. Qua ví dụ này, ta thấy nếu biến riêng trùng tên với biến bên ngoài thì CTC luôn ưu tiên biến riêng của nó và như thế không thể truy cập biến bên ngoài được.
ví dụ về sự khác nhau giữa
địa phương và toàn cục
Program Vidu3;
Var a,b:integer;
PROCEDURE nhap;
Var a,b: integer;
Begin
writeln(`Nhap vao 2 so nguyen a,b:`);
readln(a,b);
writeln(`Cac gia tri da nhap: a=`,a,`;b=`,b);
End;
BEGIN
nhap;
writeln(`Tong cua 2 so da nhap: `, a+b);
readln;
END.
ví dụ về sự khác nhau giữa
địa phương và toàn cục
Còn giờ bạn nghĩ gì về chương trình này?
Chương trình này không đơn giản là thông báo tổng của 2 số nguyên được nhập từ bàn phím qua việc dùng thủ tục nhap, song kết quả không được như ý muốn. Lỗi ở đây là thủ tục nhpa khai báo các biến chứa các giá trị được nhập cũng như những biến riêng, trong khi chương trình chính cần dùng chúng như những biến toàn cục. Để kết quả như ý muốn thì chỉ cần bỏ dòng khai báo 2 biến a, b trong thủ tục nhap
Qua những ví dụ trên, ta thấy các ngôn ngữ lập trình có cấu trúc cao như Pascal thường đòi hỏi rất chặt chẽ về mặt khai báo. Điều này có vẻ nhiêu khê cho nhiều người, nhất là những người mới học lập trình.Việc cẩn thận trong quá trình khai báo sẽ giúp bạn dễ dàng nâng cao được chương trình, cũng như tránh được các hiểm họa của những lỗi logic rất khó phát hiện, tiết kiệm thời gian khi sửa đổi và phát triển chương trình, đặ biệt trong việc xây dựng các chương trình lớn, cần nhiều người tham gia.
Vai trò của tham số
Các tham số khai báo ở đầu CTC dùng để gửi các giá trị vào chương trình xử lý, cũng như là nơi lấy các kết quả ra mà chương trình đã xử lý xong.
Không được khai báo các biến riêng của CTC trùng với tên các tham số của nó
Tham số hình thức là các tham số chỉ được truyền giá trị từ bên ngoài vào khi xuất hiện lời gọi CTC và CTC sẽ được hoạt động với bộ giá trị đó.
Tham số thực là các tham số bên ngoài được truyền vào CTC (hay nói cách khác các tham số này tham gia chươngtirnfh con với tư các là một giá trị)
Khi truyền tham số cho CTC, cần phải đảm bảo việc truyền là tương ứng 1-1, đúng thứ tự vào tương thích kiểu
ví dụ các kiểu truyền tham số lỗi:
Thủ tục:
Procedure ve(i, j: integer; t, h: word);
Truyền tham số:
ve(5, -1, 7); {không tương ứng 1 -1}
ve(-1, 3, 4, 1.5) {không tương thích kiểu}
Phân loại các cách truyền tham số:
Truyền theo trị
Việc truyền theo trị được thực hiện qua bản sao. Giá trị bên ngoài được chép vào 1 vùng nhớ được cấp phát tương ứng với kích thước tham số.
CTC sẽ làm việc với dữ liệu chứa trong bản sao
Truyền theo trị
Việc truyền theo trị được thực hiện qua bản sao.
Nếu trong CTC có những lệnh làm thay đổi giá trị của tham số hình thức thì những thay đổi này không có ảnh hưởng gì đến giá trị của biến được truyền ở đầu vào vì những thay đổi này chỉ được thực hiện trên bản sao tương ứng.
Tốn 1 ít bộ nhớ và thời gian cho việc sao chép
Cho phép giá trị ở đầu vào có thể là những giá trị của hằng, biến, hàm hoặc biểu thức. Nếu đầu vào truyền hàm hoặc biểu thức thì những giá trị này được tính trước khi truyền cho tham số. Giá trị bên ngoài được chép vào 1 vùng nhớ được cấp phát tương ứng với kích thước tham số
Đặc điểm:
Truyền theo biến
Nếu trong CTC có những lệnh làm thay đổi giá trị của tham số hình thức thì những thay đổi này cũng chính là những thay đổi trên biến được truyển
Không tốn thêm bộ nhớ và thời gian do không phải sao chép
Chỉ cho phép đầu vào là giá trị của biến
Việc truyền tham số theo biến được thực hiện vào chính địa chỉ của biến được truyền
Đặc điểm:
Khai báo
* Truyền theo trị:
Tên tham số: kiểu tham số
* Truyền theo biến:
VAR Tên tham số: kiểu tham số
Việc truyền theo trị hay truyền theo biến nhiều khi dẫn đến những kết quả logic khác nhau. Sự khác nhau này được gọi là hiệu ứng lề.
Ví dụ:
Program vidu;
VAR a: integer;
Function F(var x: integer): integer;
Begin
x:= x+1;
F:= x;
End;
BEGIN
a:= 5;
writeln(F(a)+F(a));
readln;
END.
Một sự thật mà khó có thể giải thích được đối với những người mới làm quen với lập trình. Kết quả sẽ là 13 mà không phải là 12. Lí do là ở đây đã xuất hiện hiệu ứng lề. Do hàm F được tổ chức truyền theo biến đối với đối số x của nó. Lệnh x:= x+1 trong hàm F sẽ làm biến a tăng thêm 1 đơn vị mỗi khi gọi F(a). Khi thực hiện biểu thức F(a)+F(a), giá trị F(a) được gọi 2 lần. Tại lần thứ nhất a = 5, do đó F(a) = 6, tại lần thứ hai a = 6 do đó F(a)= 7 và ta nhận được kết quả là 13.
Bạn thư nhận đoán xem kết quả của chương trình trên đưa lại là bao nhiêu?
Ví dụ:
Để sửa lại chương trình cho đúng ý muốn ban đầu, ta có 2 cách sửa:
Sửa biểu thức F(a)+F(a) thành 2*F(a)
Sửa lại việc truyền cho đối số x của hàm F là theo trị
Ví dụ:
Một số chương trình lỗi hay mắc phải do cách truyền tham số không đúng:
Program Vidu;
Var x,y: integer;
Procedure Chuyen_doi(x, y: integer);
Var t: integer;
Begin
t:=x; x:=y; y:=t;
End;
BEGIN
x:=1; y:=2;
Chuyen_doi(x,y):
Writeln(`x=`,x,`y=`,y);
Readln
END.
Một số chương trình lỗi hay mắc phải do cách truyền tham số không đúng:
Lỗi ở chương trình này là thủ tục Chuyen_doi(x,y) tổ chức tuyền theo trị nên các giá trị của biến x, y không bị ảnh hưởng bởi câu lệnh đổi giá trị trong thủ tục này.
Cách sửa:
Thêm từ khóa VAR trước tên tham số x, y
Một số chương trình lỗi hay mắc phải do cách truyền tham số không đúng:
Program Vidu;
Var tu, mau, d: integer;
Function UCLN(var a,b: integer): integer;
Begin
While a <> b do
If a>b then a:=a-b else b:=b-a;
UCLN:= a;
End;
BEGIN
Writeln(`nhap tu so va mau thuc cua phan so:);
Readln(tu, mau);
d:=UCLN(tu,mau);
writeln(`Dang toi gian cua phan so da cho la: `,tu/d, `/`,mau/d);
readln;
END.
Một số chương trình lỗi hay mắc phải do cách truyền tham số không đúng:
Chương trình trên luôn cho kết quả là 1/1.
Lỗi: do hàm UCLN được truyền theo biến, nên sau lời gọi d:=UCLN(tu, mau) ta được đồng thời các giá trị tu, mau đều bằng nhau
Sửa: bỏ từ khóa VAR trước tên a,b
Truyền theo trị hay truyền theo biến?
Nếu trong thân CTC có những lệnh làm thay đổi giá trị tham số hình thức thì việc truyền theo biến hay truyền theo trị không gây ra 1 sự khác biệt nào về kết quả mà chương tình con trả lại
Trong các trường hợp việc truyền theo biến hay truyền theo trị không ảnh hưởng đến kết quả logic của chương trình thì người ta thường chọn cách truyền theo trị cho các tham số thuộc kiểu chuẩn như integer, char, boolean, real, . còn các tham số thuộc kiểu phức hợp như mảng, bảng ghi, . thì truyền theo biến. Riêng tham số kiểu File hoặc tham số không định kiểu thì luôn phải tổ chức truyền theo biến
Truyền theo trị hay truyền theo biến?
Trong các trường hợp việc truyền theo biến hay truyền theo trị không ảnh hưởng Khi CTC có những lệnh làm thay đổi giá trị tham số hình thức thì phải truyền vào nhiệm vụ của CTC đối với tham số mà quyết định cách truyền:
? Nếu CTC có nhiệm vụ phải thay đổi giá trị tham số thực thì phải tổ chức truyền theo biến cho tham số này
? Nếu tham số thực sự được dùng để gửi giá trị ở đầu vào cho CTC hoạt động mà không được làm hỏng giá trị này sau khi gọi CTC thì phải tổ chức truyền theo trị cho tham số này. Nếu kết quả logic của chương trình thì người ta thường chọn cách truyền theo trị cho các tham số thuộc kiểu chuẩn như integer, char, boolean, real, . còn các tham số thuộc kiểu phức hợp như mang, bảng ghi, . thì truyền theo biến. Riêng tham số kiểu File hoặc tham số không địh kiểu thì luôn phải tổ chức truyền theo biến
Cấp phát bộ nhớ cho ctc
Việc cấp phát bộ nhớ cho các biến trong CTC (biến địa phương) được thực hiện trong vùng stack (ngăn xếp), trong khi việc cấp phát cho các biến trong chương trình chính (biến toàn cục) được thực hiện trong vùng nhớ data (dữ liệu).
Trong quá trình chạy chương trình, mỗi khi gọi CTC, các biến của nó sẽ được cấp phát cho đến khi CTC kết thúc, các biến này lại tự động giải phóng.
Vùng cấp phát cho CTC được gọi ở mức trong cùng sẽ giải phóng đầu tiên (vào sau ra trước)
Cấp phát bộ nhớ cho ctc
Do vậy, các biến của CTC độc lập với các biến của chương trình chính, các biến của CTC này độc lập với các biến của CTC khác cho dù nó cùng tên.
Nếu khai báo quá nhiều biến địa phương trong CTC thì khi gọi CTC này có thể bị lỗi tràn stack (stack overflow)
Hiện nay, Turbo Pascal 7.0 ngầm định dành sẵn 16Kb cho vùng stack
Cách tăng gái trị StackSize:
? Dùng định hướng biên dịch
{M StackSize, HeapMin, HeapMax}
? Vào Options/MemorySize của môi trường Turbo Pascal để đặt lại giá trị cho kích thước stack
Chương trình con đệ quy
Khái niệm:
CTC đệ quy là CTC trong khi đang xây dựng lại được gọi chính nó.
Một CTC con đệ quy cũng tương tự như một bài toán được chứng minh bằng phương pháp quy nạp.
ví dụ
Bài toán:
Tính n!
Thuật toán giải:
Cách 1:
n! = 1.2.3. . .(n-1).n
Cách 2: (Tính theo phương pháp đệ quy)
1! = 1
n! = (n-1)!.n
Tính n!
Cách 1:
Function Giaithua(n: integer):LongInt;
Var i: integer;
p: LongInt;
Begin
p:=1;
for i:=1 to n do p:=p*i;
Giaithua:=p;
End;
Tính n!
Cách 2:
Function Giaithua(n: integer):LongInt;
Begin
if n < 2 then Giaithua:= 1
else Giaithua:=Giaithua(n-1) * n;
End;
Tính n!
Nhận xét:
Mặc dù về logic, 2 hàm trên cho kết quả như nhau, nhưng về mặt hệ thống, chúng hoàn toàn được thực hiện khác nhau
? Hàm thứ nhất được gọi 1 lần không phụ thuộc vào giá trị n
? Hàm thứ 2 được gọi 1 số lần tỷ lệ với n. Khi dùng hàm thứ 2 thì tiết kiệm công sức cho người lập trình song việc dùng hàm thứ 2 phải tốn bộ nhớ và số phép toán thực hiện nhiều
Một số bài toán dùng chương trình đệ quy
Xây dựng CTC đệ quy trả về số hạng thứ n của dãy Fibonaci (với n được nhập từ bàn phím trong chương trình chính)
Chương trình:
Function F(n: integer): LongInt;
Begin
if n < 3 then F:= 1
else F:=F(n-1)+F(n-2);
End;
Một số bài toán dùng chương trình đệ quy
Bài toán tháp Hà Nội:
Có một chồng gồm n cái đĩa, đĩa nhỏ được xếp trên đĩa lớn. Cần phải chuyển chồng đĩa này đến một vị trí khác theo nguyên tắc: mỗi lần chỉ chuyển 1 đĩa và chỉ được xếp đĩa nhỏ trên đĩa lớn. Trong quá trình chuyển, cho phép dùng một vị trí thứ 3 làm trung gian. Hãy xây dựng CTC thực hiện công việc này.
Một số bài toán dùng chương trình đệ quy
Procedure chuyen_dia(n, a, b, c: integer);
Begin
if n > 0 then
begin
chuyen_dia(n-1, a, c, b);
writeln(a, `-->`, b);
chuyen_dia(n-1, c, b, a);
end;
End;
Chú ý:
Khi thiết kế đệ quy, phải đảm bảo điều kiện điểm dừng. Nếu quên điều này thì lời gọi chương trình đệ quy không kết thúc và sẽ gây ra lỗi tràn stack. Để khắc phục việc tràn stack khi dùng đệ quy, bạn cần thực hiện một số kỹ thuật sau:
?Đảm bảo sự có mặt điểm dừng trong thân CTC đệ quy
?Giảm tối đa các biến riêng cũng như các tham trị của CTC đệ quy, đặc biệt đối với những biến kích thước lớn như bảng ghi, mảng
?Tăng kích thước stack mà hệ thống dành cho chương trình
Thiết kế giao diện menu
Chương trình dưới đây, tôi muốn giúp các bạn tạo một cái khung cho một chương trình có dạng Menu, song xin lưu ý đây chỉ là cái khung để các bạn dựa vào và thiết kế chứ không phải là một Menu hoàn chỉnh:
Menu gồm có:
? Menu chính
? Mục 1
? Mục 2
? Trợ giúp
? Thoát
Thiết kế giao diện menu
Program Menu;
Ues CRT;
Funtion Menu: char;
Begin
ClrScr;
writeln(`Menu chinh`);
writeln(`=========`);
writeln(`1. Muc 1`);
writlen(`2. Muc 2`);
writeln(`3. Tro giup`);
writeln(`4. Thoat`);
writeln;
writeln(`Nhap mot lua chon.`);
Repeat
menu:= readkey;
Until Menu in [`1`..`4`];
End;
Thiết kế giao diện menu
Procedure Muc1;
Begin
ClrScr;
writeln(`Day la Muc 1`);
writeln(`An ENTER de ve Menu chinh`);
readln;
End;
Procedure Muc2;
Begin
ClrScr;
writeln(`Day la Muc 2`);
writeln(`An ENTER de ve Menu chinh`);
readln;
End;
Thiết kế giao diện menu
Procedure Trogiup;
Begin
ClrScr;
writeln(`Day la Tro giup`);
writeln(`An ENTER de ve Menu chinh`);
readln;
End;
BEGIN
Repeat
case Menu of
`1`: Muc1;
`2`: Muc2;
`3`: Trogiup;
`4`: Halt;
End;
until false;
END.
Phương pháp top - down
Khái niệm:
Phương pháp lập trình Top-Down là phương pháp lập trình từ tổng thể đến chi tiết, cho phép phân rã một công việc phức tạp thành nhiều công việc đơn giản hơn.
Phương pháp Top-Down là phương pháp cơ bản hiện nay trong lập trình cấu trúc. Nhờ phương pháp này, việc lập trình mang tính công nghệ cao, cho phép xây dựng các chương trình lớn, nhiều người tham gia, thuận tiện cho việc bảo trì và mở rộng
Phương pháp top - down
Ví dụ:
Trên mặt phẳng, xét 1 số dãy các đoạn thẳng, mỗi đoạn được xác định bởi 2 điểm dầu mút cảu chúng. Mỗi điểm trên mặt phẳng được xác định các lớp đồng phương của dãy đoạn đã cho. Lập trình giải bài toán nêu trên, dữ liệu nhập từ bàn phím, trong đó lần lượt từng đoạn thẳng được nhập các tọa độ cảu các điểm đầu mút. Kết quả đưa ra màn hình số lớp đồng phương và với mỗi lớp cần chỉ ra số hiệu các đoạn thuộc lớp đó. Các đoạn thẳng được đánh số từ 1, theo thứ tự nhập
Phương pháp top - down
Program Vidu;
Type
Kieudiem = record
x, y:real;
end;
Kieudoan = record
A, B: Kieudiem;
end;
Var
n, m: integer;
Doan: array[1..50]of Kieudiem;
Sohieu:array[1..50]og integer;
Phương pháp top - down
Procedure Nhap;
Var i: integer;
Begin
writeln(`Nhap so doan thang:`);
readln(n);
for i:= 1 to n do
begin
writeln(`Vao toa do doan `, i);
with Doan[i] do
begin
writeln(`Toa do dau mut thu nhat`);
readln(A.x,A.y);
writeln(`Toa do dau mut thu nhat`);
readln(B.x,B.y);
end;
end;
End;
Phương pháp top - down
Function Dongphuong(i,j: integer):boolean;
Begin
Dongphuong:= ABS ((Doan[i].B.x-Doan[i].A.x)* (Doan[j].B.y-Doan[j].A.y)-(Doan[i].B.y-Doan[i].A.y)*(Doan[j].B.x-Doan[j].A.x)<1e-9;
End;
Phương pháp top - down
Procedure Xacdinh;
Var i, j: integer;
Begin
for i:= 1 to n do Sohieu[i]:=0;
m:= 0;
for i:= 1 to n do
if Sohieu[i]=0 then
begin
inc(m);
Sohieu[i]:=m;
for j:= i+1 to n do
if Sohieu[j] = 0 then
if Dongphuong(i,j) then Sohiue[j]:=m;
end;
end;
Phương pháp top - down
Procedure Xem(k:integer);
Var i: integer;
Begin
for i:= 1 to n do
if Sohieu[i]=k then writeln(i:5);
writeln;
end;
Phương pháp top - down
Procedure XemKQ;
Var k: integer;
Begin
writeln (`So lop: `,m);
writeln (`Cac lop:`);
for k:= 1 to m do
begin
write(`Lop `,k, `:`);
Xem(k);
end;
End;
Phương pháp top - down
BEGIN
Nhap;
Xacdinh;
XemJKQ;
readln;
END.
Viết hàm Function Root(a:real; n:integer): real;
trả về giá trị với a là số thực dương, n là số nguyên dương
Function Root(a:real; n:integer):real;
Var kq: real;
Begin
kq:= exp(1/n*ln(a));
Root:=kq;
End;
Đường thẳng ax + by + c = 0 chia mặt phẳng thành 2 nửa dương và âm. Hãy xây dựng hàm
Function Vitri(a, b, c, u, v: real): integer;
Trả về vị trí:
? -1, nếu điểm có tọa độ (u, v) nằm ở nửa mặt phẳng âm
? 1, nếu điểm có tọa độ (u, v) nằm ở nửa mặt phẳng dương
? 0, nếu điểm có tọa độ (u, v) nằm trên đường thẳng
Function vitri (a, b, c, u, v: real): integer;
var f: real;
begin
f:=a*u+b*v+c ;
if f > 0 then vitri:=1
else if f < 0 then vitri:= -1
else vitri:=0;
end;
Cho kiểu dữ liệu được khai báo như sau:
type vector = array[1..200] of real;
Các kiểu A, b thuộc kiểu Vector:
A = (a1, a2, ., an)
B = (b1, b2, ., bn)
Hãy viết hàm
Function TichVH(var a,b: vector; n:byte):real;
tính tích vô hướng 2 vectơ A và B
Type vector = array[1..200] of real;
Function TichVH(Var a,b:vector; n: byte):real;
var i: integer;
kq:real;
Begin
kp:= 0;
for i:= 1 to n do
kp:= a[i]*b[i];
TichVH:=kp;
End;
Hãy mô tả hàm sumdigit(n) trả về giá trị là tổng các chữ số của n, trong đó n là số nguyến không âm thuộc kiểu LongInt
Function sumdigit(n:LongInt):byte;
Var t,chu: byte;
Begin
t:=0;
while t <> 0 do
begin
chu:= n mod 10;
t:= t + chu;
n:= n div 10;
end;
sumdigit:=t;
End;
* Một số tài liệu cũ có thể bị lỗi font khi hiển thị do dùng bộ mã không phải Unikey ...
Người chia sẻ: Nguyễn Nguyễn Ngọc An
Dung lượng: |
Lượt tài: 0
Loại file:
Nguồn : Chưa rõ
(Tài liệu chưa được thẩm định)