Tải bản đầy đủ (.docx) (34 trang)

de va dap an de thi cao hoc mon ct du lieu

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 (265.83 KB, 34 trang )

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

DANH SÁCH MÓC NỐI


Biến động (Nút)
Cấu trúc cây nhị phân:


Đối với cây có ba phép duyệt:
<b>-</b> Gốc – Trái – Phải


<b>-</b> Trái – Gốc – Phải
<b>-</b> Trái – Phải – Gốc
Ví dụ:


A BDE CFGH
2. Cây nhị phân tìm kiếm:


Là cây nhị phân chứa dãy khóa thỏa mãn điều kiện tại mỗi cây con thì khóa ở gốc lớn hơn khóa tại các
nút của cây con trái của nó và nhỏ hơn khóa tại các nút của cây con phải của nó.


Ví dụ:


Nhận xét:


Duyệt cây theo phương án: Trái – Gốc – Phải : 5 9 11 15 16 17 19 25 cho dãy khóa theo thứ tự tăng
dần. Như vậy việc tìm kiếm nút chứa khóa k. Nếu tìm có thì cho ra địa chỉ nút đó, nếu khơng thì cho ra
địa chỉ NULL.


Function Timnut(T: Tro; K: Integer): Tro;
Var p: Tro;


Begin



P:= T;


While (p<> Nil) and (p^.Giatri <> k) do
If (p^.Giatri < k then p:= p^.Phai
Else


P:= p^.Trai;
Timnut:= p;


End;


Tìm theo đệ quy:


Function Timnut(T: Tro; k: Integer):Tro;
Begin


If (T=NIL) or (T^.Giatri= k) Then
Timnut:= T


Else


If (T^.Giatri > k) Then


Timnut: = Timnut(T^.Phai, k)

x



A



E




C


B



F


D



G

H



Trái Phải



15



11



25


9



17


5



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

Else


Timnut:= Timnut(T^.Trai, k);
End;


2.1 Bổ sung thêm khóa K vào cây T (nếu chưa có nút nào chứa K):
Procedure Bosung(T: Tro; K: Integer);


Var p,r : Tro; OK: Boolean;
Begin



If (T=NIL) Then
Begin


New(T);


T^.Giatri: = k;
T^.Trai:= NIL;


T^.Phai:= NIL;
End
Else
Begin


P:= T; OK:= True;


While (p^.Giatri <> k) and OK do
If (p^.Giatri > k) Then


If (p^.Trai <> NIL) Then p:= p^.Trai else OK:= False
Else


If (p^.Phai <> NIL) Then p:= p^.Phai else OK:= False
If (p^.Giatri = k) Then Write(“Gia tri nay da ton tai”)


Else
Begin


New(r);
R^.Giatri:= k;



R^.Phai:= NIL;
R^.Trai:= NIL;


If (p^.Giatri > k) Then p^.Trai := r Else p^.Phai:= r;
End;


End;
End;


Đề thi năm 2003:


Câu 2: Người ta biểu diễn thông tin các câu lạc bộ bóng đá chuyên nghiệp của một quốc gia dưới dạng
một cây nhị phân tìm kiếm có khóa là TenCLB (Tên câu lạc bộ). Mỗi nút của cây là một bản ghi gồm
4 trường: <b>TenCLB</b> và 3 trường con trỏ <b>Left, Right, First</b>. Hai con trỏ <b>Left</b> và <b>Right </b>lần lượt trỏ tới 2
nút con trái và con phải của nút đó. Con trỏ First trỏ bởi phần tử đầu của một danh sách liên kết đơn
chứa thông tin các cầu thủ thuộc câu lạc bộ (danh sách này có ít nhất 11 phần tử). Mỗi phần tử con
danh sách này là một bản ghi gồm 4 trường: TenCT (Tên cầu thủ), SoAo (số áo), Tuoi (tuổi), và Next
(lưu địa chỉ của phần tử tiếp theo trong danh sách). Danh sách này được sắp theo thứ tự tăng dần của
SoAo. Người ta cho khai báo cấu trúc dữ liệu nói trên như sau:


Type st25 = string[25];
TroCT = ^Cauthu;
Cauthu = Record


TenCT: St25;
SoAo, Tuoi: Byte;
Next: TroCT;
End;



TroCLB = ^Nut;
Nut = Record


TenCLB: St25;
First: TroCT;
L,R: TroCLB;
End;


Var Top: TroCLB;


TenCLB



First

R



L



TenCLB


R



L

TenCT

L

TenCLB

R



SoAo


Tuoi


Next



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

a. Viết thủ tục in danh sách các cầu thủ trong câu lạc bộ có tên club.
Procedure List(Club: st25);


Var P: TroCLB; r: TroCT;
Begin



P:= Top;


While (p<> Nil) and (p^.TenCLB <> Club) do


If (p^.TenCLB > Club) Then p:= p^.L else p:= p^.R;
If p= Nil Then Write(“Khơng có câu lạc bộ này”)


Else
Begin


r:= p^.First;


Writeln(“Danh sách cầu thủ”);
While r<> Nil do


Begin


Writeln(p^.TenCT);
r:= r^.next;


End;
End;
End;


2. Viết thủ tục Procedure Bosung(Top: TroCLB; Name: st25; m,k: byte) bổ sung cầu thủ tên Name,
tuổi k, và số áo m vào câu lạc bộ có tên Club> Việc bổ sung này được thực hiện trong trường hợp câu
lạc bộ Club đã có trong cây và chưa có cầu thủ nào trong câu lạc bộ có số áo này.


Procedure Bosung(Top: TroCLB; Name: st25; m,k: byte);


Var p: TroCLB; q, r: TroCT;


Begin


p:= Top;


While (p<> Nil) and (p^.TenCLB <> Club) do


If (p^.TenCLB > Club) Then p:= p^.L Else p:= p^.R;
If (p = Nil) Then Write (“Khơng có Câu lạc bộ này”)


Else


Begin


R:= p^.First;


{Con trỏ r dùng để duyệt các nút và sẽ cho r dừng lại tại nút thỏa
mãn một trong các điều kiện sau:


Số áo tại đó là m


Số áo tại đó < m nhưng số áo ở nút tiếp theo > m.
Hoặc là nút cuối cùng


}


If (r^.SoAo > m) or (p^.First = Nil) then
Begin



New(q);
q^.TenCT = Name;


q^.Tuoi:= k;
q^.SoAo:= m;


q^.Next: = p^.First;
p^.First:= q;


End
Else
Begin


While (r^.Next <> Nil) and ((r^.Next)^.SoAo <= m ) do r:=
r^.Next;


If r^.SoAo = m then Write (“Đã có”)
Else


Begin


New(q);


q^.TenCT:= Name;
q^.Tuoi:= k;
q^.SoAo:= m;
q^.Next:= r^.Next;
r^.Next:= q;
End;



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

c. Xóa tên cầu thủ mang số áo m trong câu lạc bộ Club.
Procedure Xoa(Club: st25; m: byte);


Begin
p:= Top;


While (p<> Nil) and (p^.TenCLB <> Club) do


If (p^.TenCLB > Club) Then p:= p^.L Else p:= p^.R;
If (p = Nil) Then Write (“Khơng có Câu lạc bộ này”)


Else


Begin


R:= p^.First;


While (r<> Nil) and (r^.SoAo <> m) do r:= r^.Next;
If (r=Nil) Then Write(“Khơng có nút chứa số áo này!”)


Else


Begin


If (r=p^.First) Then p^.First:= r^.Next
Else


Begin


q:= p^.First;



While (q^.Next <> r) do q:= q^.Next;
q^.Next:= r^.Next;


End;
Dispose(r);
End;


End;
End;


d. Viết hàm Function TuoiMin(Club: st25): byte cho biết tuổi của cầu thủ trẻ nhất trong câu lạc bộ có
tên Club. {Tìm giá trị của nút}


Function TuoiMin(Club: st25): byte;
Var k: byte;


Begin
p:= Top;


While (p<> Nil) and (p^.TenCLB <> Club) do


If (p^.TenCLB > Club) Then p:= p^.L Else p:= p^.R;
If (p = Nil) Then Write (“Không có Câu lạc bộ này”)


Else


Begin


r:= p^.First;



If (r=Nil) Then Write (“Câu lạc bộ khơng có cầu thủ nào!”)
Else


Begin


k:= r^.Tuoi;
r:= r^.Next;


While (r<> Nil) do
Begin


If (r^.Tuoi < k) Then k:= r^.Tuoi;
R:= r^.Next;


End;
TuoiMin:= k;
End;


End;
End;


- Nếu trong tình huống tìm tên s của cầu thủ có tuổi < I { Phải tìm nút có điều kiện ..}


- Nếu Câu lạc bộ chưa có trong cây => phải bổ sung thêm câu lạc bộ và cầu thủ sẽ là nút đầu tiên của
câu lạc bộ.


Bài 1: (Đề 2003)
Type Link= ^Node;
Node = Record



Key: Integer;
Next: Link;
End;


Var i, M,N: integer; t, x: Link;
Begin


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

New(t); t^.key:= 1; x:= t;
For i:= 2 to N do


Begin
New(t^.Next);
T:= t^.Next;
T^.Key:= i;
End;
t^.Next:= x;


While (t<> t^.Next) Do
Begin


For i:= 1 to M-1 Do t:= t^.Next;
Write(t^.Next^.Key);


x:= x^.Next;


t^.Next:= t^.Next^.Next;
Dispose(x);


End;


Writeln(t^.Key);
End.


a. Cho biết kết quả với N=5; M= 3;


Kết quả: 3, 1, 5, 2, 4.


b. Chương trình trên thực hiện cơng việc gì?


 Đầu tiên tạo một danh sách nối vòng gồm n nút, lần lượt chứa dãy số 1,2,3,…,n.
 Và có nút đầu tiên trỏ bởi x, nút cuối cùng trỏ bởi t.


 Nếu như chừng nào t <> t^.next đồng nghĩa với danh sách có hơn một nút (từ 2 nút trở lên) thì


nó sẽ thực hiện:


<b>-</b> Chuyển t sang quản lí nút sau t M-1 vị trí.
<b>-</b> Sau đó viết giá trị key của nút sau t.
<b>-</b> Loại bỏ nút sau t


 Cuối cùng viết giá trị của nút trỏ bởi t ra màn hình


Bài 3: (Đề thi 1996A)


Trong một hệ soạn thảo văn bản đang soạn được lưu ở bộ nhớ trong dưới dạng một danh sách nối kép
như sau:


1

1

1

1

1



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

Khai báo của danh sách (Đầu, Cuối) như sau:


Type str80 = string[80];


Tro = ^DongVB;
DongVB = Record


Truoc: Tro;
Dong: Str80;
Sau: Tro;
End;


Var Dau, Cuoi: Tro; {Dau = Nil khi văn bản rỗng}
a. Viết một thủ tục dạng


Procedure Xemtruoc(Var d: Tro; p: Tro; S: str80);


Cho phép xen một dòng mới với nội dung cho bởi s vào trước phần được trỏ bởi p trong danh sách có
đầu d.


Giải:


// Trong thủ tục này cần thêm c là cuối danh sách để thủ tục hoàn chỉnh hơn
Procedure Xemtruoc(Var c,d: Tro; p: Tro; s: str80);
Var r: Tro;


Begin


New®; r^.dong:= s;


r^.Truoc:= Nil; r^.Sau:= Nil;
If (d= Nil) Then



Begin
d:= r;
c:= r;


End
Else


If (p = d) Then
Begin


r^.Sau:= p;
p^.Truoc:= r;
d:= r;


End
Else


Begin


r^.Truoc:= p^.Truoc;
r^.Sau:= p;


p^.Truoc^.Sau:= r;
p^.Truoc:= r;
End;


End;


c. Gọi Blốc(db,cb) là một khối liền nhau các dòng kể từ dòng trỏ bởi db đến dòng cb. Hãy viết thủ tục


chuyển dời Blốc(dc,cb) tới trước dòng trỏ bởi Noiden trong danh sách (d,c). Giả sử nơi đến không ở
trong Blốc.


Giải:


Procedure ChuyenBL(Var d,c: Tro; db, cb, Noiden: Tro);


// Nơi đến có 2 trường hợp: chỉ đến đầu văn bản hoặc giữa của văn bản.


// Khi xây dựng thủ tục cần chú ý đến các trường hợp đặc biệt sau: Trong Blốc có chứa dịng // đầu
tiên khi đó con trỏ đầu sẽ thay đổi


// Trong Blốc có chứa dịng cuối cùng => con trỏ cuối sẽ thay đổi


// Trong Blốc khơng chứa dịng đầu tiên và dòng cuối cùng . Noiden: là dòng đầu tiên thì địa //chỉ của
đầu sẽ thay đổi


// Nơi đến: khơng phải dịng đầu tiên thì địa chỉ của đầu không thay đổi
Var


Begin


If (db= d) then
Begin


dd:= d; // Con trỏ dd quản lí đầu block, block là dòng đầu văn bản
d:= cb^.Sau; //trở thành dòng đầu tiên


cb^.sau:= Nil; d^.Truoc:= Nil;



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

cb^.Sau:= Noiden;
Noiden^.Truoc:= cb;
End


Else


Begin


db^.Truoc^.Sau:= cb^.Sau;
cb^.Sau^.Truoc:= db^.Truoc;
db^.Truoc:= Nil;


cb^.Sau:= Nil;
End;


<i>/* Ba trường hợp trên nằm chung trong một nhiệm vụ là cắt Block ra khỏi danh sách chứa văn bản. </i>
<i>Nhiệm vụ tiếp theo sau là chèn Block vào trước dòng nơi đến */</i>


Noiden^.Truoc^.Sau:= db;
Db^.Truoc:= Noiden^.Truoc;
Cb^.Sau:= Noiden;


Noiden^.Truoc:= cb;


c. Viết thủ tục cho phép chép (mà không hủy) Block tới trước dòng trỏ bởi Noiden trong danh sách
đầu trỏ bởi d. Giả sử Noiden không ở trong Block.


Giải:


Procedure ChepBL(Var d: Tro; db, cb, Noiden: Tro);


/* <i>Đối với thủ tục này ta cần giải quyết các công việc sau:</i>


<i>+ Tạo một danh sách độc lập ds,cs quản lí nút đầu và cuối của danh sách để sao chép nội </i>
<i>dung của Block:</i>


<b>-</b> <i>Chèn ds, cs vào trước dòng trỏ bởi nơi đến </i> */
Var


Begin


ds:= Nil; // Danh sách rỗng
cs:= Nil;


// Trường hợp dừng sẽ là p=Nil và p^.Truoc = cb
While (p <> Nil) and (p^.Truoc <> cb) do


Begin


New(r); r^.dong:= p^.dong;
r^.Truoc:= Nil;


r^.sau:= Nil;
If (ds = Nil) Then


Begin


ds:= r; cs:= r;


End



Else begin


r^.Truoc:= cs;
cs^.Truoc:= r;
cs:= r;


End;


p:= p^.Sau;
End;


// Chèn danh sách ds, cs vào trước nơi đến
If (Noiden = d) then


Begin


cs^.Sau:= d;
d^.Truoc:= cs;
d:= ds;


End


Else
Begin


Noiden^.Truoc^.Sau:= ds; //Noiden là dịng bất kì
trong văn bản


Ds^.Truoc:= Noiden^.Truoc;
Cs^.Sau:= Noiden;



Noiden^.Truoc:= cs;

ds



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

End;
End;


Đề 1997:


Bài 3: Kết quả thi đại học của một lớp được lưu lại trong một danh sách tuyến tính móc nối các nút
được khai báo như sau:


Type Tro = ^Nut;
Nut = Record


Sohieu: integer;
Tin: Alpha;


Toan, Ly, Hoa: Real;
Tiep: Tro;


End;


Đầu của danh sách được trỏ bởi biến Dau
Var dau: Tro;


Hãy viết chương trình con


1. Procedure Nhap(Var Dau: Tro; sh: Integer; Name: Alpha; t,l, h: real) cho phép nhập số hiệu sh, tên
của học sinh là name và các điểm tốn, lý, hóa được cho bởi t, l, h tương ứng với một nút mới sẽ đặt ở


cuối danh sách của lớp được cho bởi con trỏ dau.


Giải:


Procedure Nhap(Var Dau: Tro; sh: Integer; Name: Alpha; t,l, h: real)
Var hs: Tro;


Begin


//Bổ sung một nút mới vào cuối danh sách
New(hs);


Hs^.sohieu:= sh;
Hs^.ten:= Name;
Hs^.Toan:= t;
Hs^.Ly:= l;
Hs^.Hoa:= h;
Hs^.Tiep:= Nil;


If dau = Nil then Dau:= hs
Else


Begin
P:= Dau;


While p^.Tiep <> Nil Do p:= p^.Tiep;
P^.Tiep:= Hs;


End;
End;



2. Procedure Ketqua(Dchuan: real; Dau: Tro; Var Do, Truot: Tro);


Cho phép thông báo danh sách học sinh đỗ (có trường điểm Tốn, Lý, Hóa lớn hơn hoặc bằng điểm
chuẩn Dchuan). Danh sách này được trỏ bởi con trỏ Do và danh sách các học sinh bị trượt được trỏ bởi
con trỏ Truot.


Yêu cầu: Không chép lại các phần tử của danh sách lớp học sang một vùng nhớ ngoài danh sách đã
cho.


Giải:


Ý tưởng:


+ Dùng một biến con trỏ p để duyệt danh sách trỏ bởi Dau
+ Tại mỗi vị trí của p ta làm:


<b>-</b> Cắt p khỏi danh sách Dau.


<b>-</b> Xem nút p đỗ hay trượt. Nếu đậu thì bổ sung vào sau danh sách Đỗ (trỏ bởi con trỏ Do). Nếu trượt
thì bổ sung vào danh sách trượt (trỏ bởi con trỏ Truot).


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

Procedure Ketqua(Dchuan: real; Dau: Tro; Var Do, Truot: Tro);
Var p, r1,r2: Tro;


Begin


Do:= Nil; Truot: Nil; {2 danh sách này rỗng chưa có nút nào}
While (Dau <> Nil) Do



Begin


// <i>Cắt p ra khỏi danh sách</i>


P:= Dau;


Dau:= Dau^.Tiep;
P^.Tiep:= Nil;


If (p^.Toan+ p^.Ly+p^.Hoa >= Dchuan) then //<i>Nếu thi đậu</i>


Begin


If (Do = Nil) Then Do:= p
Else


r1^.Tiep:= p;
r1:= p;


End
Else


Begin


If (Truot = Nil) Then Truot:= p
Else


r2^.Tiep:= p;
r2:= p;
End;



End;
End;


Đề 1995 – B


Bài 1: Cho khai báo kiểu của một danh sách tuyến tính móc nối.
Type Tro = ^KieuPT;


KieuPT = Record


Giatri: Integer;
Tiep: Tro;


End;


1.

Cho Var ds, q: Tro; trong đó <b>ds</b> rtỏ tới đầu của một danh sách tuyến tính. Hãy viết thư mục
Procedure LayMax(Var ds, q: Tro)


cho phép lấy phần tử lớn nhất ra khỏi danh sách ds, phần tử đó sẽ được trỏ bởi q.
Giải:


Procedure LayMax(Var ds, q: Tro)
Var r: Tro;


Begin


q:= ds; r:= q^.Tiep;
While (r <> Nil) Do



Begin


If (r^.Giatri > q^.Giatri) Then q:= r;
r:= r^.Tiep;


End;


If (q = ds) then ds:= ds^.Tiep
Else


Begin


r:= ds;


While r^.Tiep <> q do r:= r^.Tiep;
r^.Tiep:= q^.Tiep;


End;
q^.Tiep:= Nil;
End;


2

1

7

3



r = Nil


r



ds



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

2. Cho Var ds1, ds2: Tro;



Trong đó ds1, ds2 trỏ đầu của một danh sách tuyến tính chưa được sắp xếp theo trường <b>Giatri </b>cịn ds2
thì được gán bằng Nil. Viết thủ tục:


Procedure Sapchon(Var ds1, ds2: Tro);


Cho phép chọn dần các phần tử trong ds1 từ giá trị lớn đến bé, đưa vào ds2
để cuối cùng ds1 = Nil còn ds2 trỏ tới một danh sách tuyến tính gồm mọi
phần tử của ds1, nhưng đã được sắp xếp theo thứ tự tăng dần của trường
Giatri.


Giải:


Procedure Sapchon(Var ds1, ds2: Tro);
Var


Begin


While (ds1 <> Nil) Do
Begin


LayMax(ds1, q);


If ds2 = Nil Then ds2:= q


Else //Bổ sung q vào đầu danh sách d2 để theo thứ tự
tăng dần


Begin


LayMax(ds, q);


q^.Tiep:= ds2;
ds2:= q;


End;
End;


End;
Đề 1997:


Bài 3: Cây nhị phân kiểu Min – Max có tổ chức như sau:


<b>-</b> Mỗi nút chứa một trường giá trị khóa, có kiểu dữ liệu Integer;
Type Nut = Record


Giatri : Integer;
Kieu: Boolean;
Trai, Phai: ^Nut;
End;


TroNut = ^Nut;
Quy ước:


Kiểu = T nếu nút thuộc loại MAX


F nếu nút thuộc loại MIN




a. Viết thủ tục đệ quy để tính giá trị của các nút của cây nhị phân được trỏ bởi con trỏ gốc, dựa trên
khóa của nút lá.



Function TinhGiaTri (Goc: TroNut): Integer;
Function Min(a,b: Integer): Integer;


Function Max(a,b: Integer): Integer;
Begin


If (Goc^.Trai = Nil) and (Goc^.Phai = Nil) Then
TinhGiaTri:= Goc^.Giatri;


Else


If (Goc^.Kieu = T) Then //Nút có kiểu MAX

10



7

6

10

12



6

10



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

TinhGiaTri:= Max(TinhGiaTri(Goc^.Trai),
TinhGiaTri(Goc^.Phai))


Else


TinhGiaTri:= Min(TinhGiaTri(Goc^.Trai),
TinhGiaTri(Goc^.Phai))


End;


Procedure TaoCayB(Goc: TroNut);


Begin


If (Goc^.Trai = Nil) and (Goc^.Phai <> Nil) then
Begin


Goc^.Giatri:= TinhGiaTri(Goc);
TaoCayB(Goc^.Trai);


TaoCayB(Goc^.Phai);
End;


End;


b. Viết thủ tục tính giá trị trung bình của các giá trị Khóa của nút trong cây.
Procedure TimTong(Var S, SoNut: Integer; Goc: TroNut);
Begin


S:= S+ Goc^.Giatri;
SoNut:= SoNut + 1;


If (Goc^.Trai <> Nil) and (Goc^.Phai <> Nil) Then
Begin


TimTong(s, SoNut, Goc^.Trai);
TimTong(s, SoNut, Goc^.Phai);
End;


End;


Procedure TrungBinh(Goc: TroNut);


Var S, SoNut: Integer; p: TroNut;
Begin


S:= 0; SoNut:= 0; p:= Goc;
TimTong(S, SoNut, p);


Write(“Trung bình là: “, S/SoNut);
End;


Xây dựng phương án không đệ quy cho câu 1:
+ Duyệt cây theo thứ tự sau. (Trái phải gốc)


+ Mỗi lần thăm nút: Tùy theo nút đó là MIN hay MAX mà chọn giá trị cho nó, lấy cây con trái hoặc
phải(Nếu nút được thăm không phải là nút lá).


<b>Nhắc lại duyệt không đệ quy của cây nhị phân:</b>
<b>Duyệt trước: (Gốc – trái - Phải)</b>


<b>- Nộp Goc vào Stack</b>
<b>- REPEAT</b>


<b>o</b> <b>Lấy một nút p từ Stack</b>
<b>o</b> <b>Thăm p</b>


<b>o</b> <b>Nếu có con phải thì nạp vào Stack</b>
<b>o</b> <b>Nếu p có con trái thì nạp vào Stack</b>
<b>UNTIL Stack rỗng</b>


A


C



B



E



D

F

G



K

H

I



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

A B D E K C F H I G


Duyệt giữa: (Trái - Gốc - Phải)
+ p:= Goc;


+ REPEAT


- Nộp p cùng nhánh lệch trái vào Stack
- Lấy p ra từ Stack


- Thăm p


- Chuyển p sang gốc con phải của p (có thể Nil)
UNTIL (Stack rỗng) and (P = NIL)




Procedure DuyetGiua(Goc: TroNut)
Var


Begin



//Khởi tạo Stack
S = 0;


p:= Goc;
Repeat


While (p<> Nil) do
Begin


Push(S, p);
p:= p^.Trai;
End;


p:= Pop(S);


Write(p^.GiaTri,” “);
p:= p^.Phai;


Until (S =0) and (p = Nil);
Return ;


End;


Duyệt sau: (Trái - Phải - Gốc)
Procedure TaoCay(Goc: TroNut);


Type MangTro = Array[1..100] of Integer;
Var S: MangTro; R: Mang;



N, TS, TR: Integer; P: TroNut;


Procedure SPUSH(S: MangTro; Var TS: Integer; P: TroNut);
Begin


TS:= TS + 1; S[TS] := p;
End;


Function SPOP(S: MangTro; Var TS: Integer): TroNut;
Begin


TS:= TS -1 ;
SPOP:= S[TS+1];
End;


Procedure RPUSH(R: Mang; Var TR: Integer; n: Integer);
Begin


TR:= TR + 1;
R[TR]:= n;
End;


Function RPOP(S: Mang; Var TS: Integer): Integer;
Begin


TR= TR-1 ;


RPOP:= R[TR + 1];


G


I
H


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

End;
BEGIN


TS:= 0; TR:= 0; p:= Goc;
Repeat


While (p<> Nil) do
Begin


SPUSH(S, TS, p);
RPUSH(R, TR, 1);
p:= p^.Trai;
End;


p:= SPOP(S, TS);
n:= RPOP(R,TR);


If (n=1) and (p^.Phai <> Nil) then
Begin


SPUSH(S, TS, p);
RPUSH(R,TR,2);
P:= p^.Phai;
End;


Else



//Thăm nút và tính giá trị Min, Max
Begin


If (p^.Trai <> Nil) and (p^.Phai <> Nil) Then
If (p^.Kieu = T) Then


p^.GiaTri:= Max(p^.Trai^.GiaTri,
p^.Phai^.GiaTri)


Else


p^.GiaTri:= Min(p^.Trai^.GiaTri,
p^.Phai^.GiaTri);


p:= Nil;
End;


Until (TS =0) and (p = Nil);
END;


Đề 1993:


Cho cây nhị phân với khai báo như sau:
Type Tro = ^Nut;


Nut = Record


Giatri: Integer;
Trai, Phai: Tro;
End;



Var T: Tro;


Hãy lập hàm Function Copy(T: Tro): Tro; cho phép sao chép cây với gốc trỏ bởi T.
Function Copy(T: Tro): Tro;


Begin


If (T = Nil) Then
Begin


New(p);


P^.GiaTri:= T^.GiaTri;
P^.Trai:= Copy(T^.Trai);
P^.Phai:= Copy(T^.Phai);
Copy:= p;


End;
End;


Bài 4:


Với cây nhị phân được khai báo như bài 3, ta có thể tiến hành duyệt cây theo một giải thuật không đệ
quy theo sơ đồ sau, trong đó có đúng một danh sách tuyến tính để lưu (các con trỏ tới) các nút cần ghi
nhớ trong cây.


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

Begin


- Lấy một nút từ danh sách, gọi đó là N


- Thăm N (chẳng hạn in giá trị của nó


- Nạp con trỏ trái của N vào danh sách (nếu có)
- Nạp con trỏ phải của N vào danh sách (nếu có)
End;


Giải thuật S (Dùng Stack) (lấy nút mới nhất (nạp muộn nhất))
Giải thuật Q (dùng Queue) lấy nút cũ nhất (nạp sớm nhất)
a. Hãy cho biết các giải thuật S, Q duyệt cây theo thứ tự nào?
Giải:


Giải thuật S:


Stack: 1 2 3 6 4 5 8 9 7
Kết quả: 1 3 6 4 5 8 9 7
Giải thuật Queue:
Queue: 1 2 3 4 5 6 7 8 9
Kết quả: 1 2 3 4 5 6 7 8 9


Duyệt ưu tiên theo mức, cùng mức thì ưu tiên từ trái sang phải


b. Từ sự gợi ý của sơ đồ trên, hãy viết 1 thủ tục duyệt cây nhị phân theo thứ tự (gốc- trái – phải). Chú
ý không được phá hoại cây đã cho và cố gắng loại các động tác thừa . Thăm một nút được thể hiện bởi
in giá trị của nút đó ra.


Giải:


Gốc – Trái – Phải:


S: 1 3 2 5 4 7 9 8 6 -> 1 2 4 7 5 8 9 3 6



Procedure PreOrder(Goc: Tro);
Var p: Tro; TS: Integer;


Procedure PUSH(S: MangTro; Var TS: Integer; p: Tro);
Function POP(S: MangTro; Var TS: Integer): Tro;
Begin


TS:= 0; //Khởi tạo danh sách rỗng
PUSH(S, TS, Goc);


While (TS >0) do
Begin


p:= POP(S, TS);
Write(p^.Giatri);


If p^.Phai <> Nil Then PUSH(S, TS, p^.Phai);
If p^.Trai <> Nil Then PUSH(S, TS, p^.Trai);
End;


End;


ĐỀ IFI 09/96
Bài 3:


Người ta biểu diễn các thông tin của một thư viện dưới dạng một cây nhị phân tìm kiếm với khóa là
TenTG (tên tác giả). Mỗi nút của cây là một bản ghi gồm trường TenTG và 4 trường con trỏ: 2 con trỏ
Trai và Phai lần lượt trỏ tới các nút con trái và con phải. Hai con trỏ Dau va Cuoi lần lượt trỏ tới phần
tử đầu và cuối của một danh sách tuyến tính móc nối dùng để ghi nhận các sách có trong thư viện của


tác giả đó. Mỗi phần tử của danh sách này một bản ghi gồm có 2 trường: Tensach và Tieptheo. Có thể
hình dung:


1


3


2



5



4

<sub>6</sub>



7

<sub>8</sub>

<sub>9</sub>



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

Người ta khai báo:
Type Str25 = string[25];


Trosach = ^Record


Tensach: String;
Tieptheo: TroSach;
End;


TroTG = ^Tacgia;
Tacgia = Record


Trai: TroTG;
TenTG: str25;
Dau, Cuoi: TroSach;
Phai: TroTG;
End;



Var Goc: TroTG;


a. Hãy viết một hàm Function Nut(Goc: TroTG; Ten: str25): TroTG; cho kết quả là một con trỏ:
- Bằng NIL khi Goc = Nil nếu khơng thì:


- Trỏ tới nút có TenTG = Ten nếu nút đó tồn tại, nếu khơng thì:


- Trỏ tới một nút trong đó Ten < TenTG và Trai = Nil hoặc là Trỏ tới một nút trong đó
Ten > TenTG và Phai = Nil.


Cây bên trái < cây bên phải vì tên được sắp xếp theo thứ tự
Giải:


Function Nut(Goc: TroTG; Ten: str25): TroTG;
Var p: TroTG;


Begin


If (Goc = Nil) Then Nut:= Nil
Else


Begin


p:= Goc;


While ((Ten< p^.Tentg)and(p^.Trai <>
Nil))or((Ten>p^.TenTG)and(p^.Phai<> Nil))


If (Ten < p^.TenTG) Then p:= p^.Trai Else p:=


p^.Phai;


Nut:= p;
End;


End;


b. Hãy viết một hàm cho ta địa chỉ (con trỏ kiểu TroTG) của một nút mới thành lập, nhưng chưa được
gắn vào cây, trong đó TenTG = Ten và trong phần tử duy nhất của danh sách tương ứng thì TenSach =
Tuade.


Function NutMoi(Ten: str25; Tuade: string): TroTG;
Var p: TroTG; r: TroSach;


Begin


New(p);


p^.TenTG:= Ten;
p^.Trai:= Nil;
p^.Phai:= Nil;
New(r);


r^.TenSach:= Tuade;
r^.Tieptheo:= Nil;


p^.Dau:= r; p^.Cuoi:= r;
End;


c. Hãy viết một thủ tục cho phép bổ sung tên một tác giả (Ten) với một cuốn sách (Tuade) vào thư


viện trỏ bởi Goc theo cách sau:


- Nếu Ten và TuaDe đều đã có trong thư viện thì khơng phải làm gì nữa.


Đầu


Trái Cuối Phải


x x


p



Trái


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

- Nếu Ten đã có và Tuade chưa có thì bổ sung Tuade đó vào cuối danh sách tương ứng với nút có tên
TenTG = Ten.


- Nếu Ten và TuaDe đều chưa có thì bổ sung một nút mới vào thư viện, với TenTG = Ten và TenSach
= TuaDe.


Giải:


Procedure Bosung(Var Goc: TroTG; Ten: str25; TuaDe: String);
Var p: TroTG; r: TroSach;


Begin


p:= Nut(Goc, Ten);


If (p= Nil) Then Goc:= NutMoi(Ten, TuaDe)
Else



If ((Ten < p^.TenTG) Then p^.Trai:= NutMoi(Ten, TuaDe)
Else


If (Tem > p^.TenTG) Then p^.Phai:= NutMoi(Ten, TuaDe)
Else


Begin


r:= p^.Dau;


While (r<> Nil) and (r^.TenSach<> TuaDe) Do
r:= r^.TiepTheo;


If (r=Nil) Then
Begin


New(r);


r^.TenSach:= TuaDe;
r^.TiepTheo:= Nil;


If (p^.Dau = Nil) Then p^.Dau:= r
Else


p^.Cuoi^.TiepTheo:= r;
p^.Cuoi:= r;


End;
End;



End;
Đề 02/1998


Bài 2: Khai báo kiểu của một danh sách tuyến tính móc nối và một cây nhị phân như sau:
Type Tro = ^Ptu;


Ptu = Record


GiaTri: Integer;
Tiep: Tro;
End;


Pointer = ^Nut;
Nut = Record


Value: Integer;
Trai, Phai: Pointer;
End;


Var ds: Tro;


Goc: Pointer;


Viết các chương trình con thực hiện công việc sau:


1. Procedure Dungcay(ds:Tro; Var Goc: Pointer) nhằm xây dựng cây nhị phân tìm kiếm có gốc được
trỏ bởi gốc trên cơ sở các phần tử của danh sách ds đã cho. Giả thiết rằng các phần tử của danh sách có
giá trị khác nhau từng đơi một.



Ví dụ:


8 3 9 4 1 10


Ta xây dựng cây nhị phân tìm kiếm như sau:


8



3

9



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

Giải:


Procedure Dungcay(ds: Tro; Var Goc: Pointer);
Var


Procedure BosungNut(Var Goc: Pointer; n: Integer);
Var r, p: Pointer;


Begin


New(r);


r^.Value:= n;


r^.Trai:= nil; r^.Phai:= Nil;
If (Goc = nil) Then Goc:= r
Else


Begin



p:= Goc;


While ((p^.Value < n)and(p^.Phai <>Nil)) OR ((p^.Value > n) and
(p^.Trai <> Nil)) Do


If p^.Value < n Then p:= p^.Phai Else p:= p^.Trai
If (p^.Value < n) Then p^.Phai:= r Else p^.Trai:= r;
End;


End;
BEGIN


q:= ds;


While (q <> Nil) Do
Begin


BosungNut(Goc, q^.Giatri);
q:= q^.Tiep;


End;
END:


2. Nhằm xây dựng cây nhị phân tìm kiếm có gốc được trỏ bởi Goc; tương ứng với một hoán vị nào đó
của các phần tử trong danh sách sao cho độ cao của cây nhận được là nhỏ nhất.


Giải:


Procedure Cay_NP_Min(Ds: Tro; Var Goc: Pointer);
/*



+ Đầu tiên xếp dãy theo thứ tự tăng dần


+ Xóa đệ quy: Lấy giá trị ở giữa đưa vào gốc sau đó gọi đệ quy dựng cây con trái với dãy phía trước
và dựng cây con phải với dãy phía sau:


*/
Type


Mang = Array[1..1000] ị Integer;
Var A: Mang; n: Integer;


Procedure DocRaMang(Var A: Mang; Var n: Integer; Ds: Tro);
/*


Đọc dãy số từ danh sách lưu vào mảng A. Số phần tử của dãy lưu vào n. Sau đó xếp thứ tự tăng dần
trên mảng A


*/


Procedure Dung(A: Mang; Dau, Cuoi: Integer; Var Goc: Pointer);
Var Giua: Integer;


Begin


New(Goc);


Giua:= (Dau+Cuoi) Div 2;
Goc^.Giatri:= A[Giua];
Goc^.Trai:= Nil;



1 2 3 4 5 6 7 8 9 10



T1


T1



Cuối



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

Goc^.Phai:= Nil;


If (Dau< Giua) Then Dung(A, Dau, Giua-1, Goc^.Trai);
If (Giua <Cuoi) Then Dung(A, Giua + 1, Cuoi, Goc^.Phai);
End;


BEGIN


DocRaMang(A, n, DS); Dung(A, 1, n, Goc); END;
Bài 3: (Đề 1999-2000)


Cho khai báo của một cây nhị phân như sau:
Type Tro = ^Nut;


Nut = Record


GiaTri: Integer;
Trai, Phai: Tro;
End;


Var Goc: Tro;



Hãy lập các chương trình con thực hiện công việc sau:


1. Hàm cho phép Kiểm tra xem cây có gốc được trỏ bởi con trỏ gốc có phải là cây nhị phân tìm kiếm
hay khơng?


Chú ý: Cây rỗng cũng được coi là cây tìm kiếm. Viết theo 2 phương án đệ quy và không đệ quy.
Giải:


Đệ quy:


Function CayTK(Goc: Tro):Boolean;
Begin


If ((Goc = Nil) Or ((Goc^.Trai = Nil) and (Goc^.Phai = Nil))) Then
CayTK:= True


Else


Begin


If (Goc^.Trai = Nil) Then


If (Goc^.Giatri <Goc^.Phai^.Giatri) Then CayTK:=
True


Else CayTK:= False
Else


If (Goc^.Phai = Nil) Then



If (Goc^.Giatri > Goc^.Trai^.Giatri) Then
CayTK:= True


Else CayTK:= False
Else


CayTK:= CayTK(Goc^.Trai) and CayTK(Goc^.Phai) and


(Goc^.Giatri > Max(Goc^.Trai) and


(Goc^.Giatri < Min(Goc^.Phai)
End;


End;


Function Max(Goc: Tro): Integer;
Function Min(Goc: Tro): Integer;


Với giá trị trả về của hàm là nút lớn nhất hoặc nhỏ nhất của cây.


2. Trường hợp cây ban đầu khơng phải là cây tìm kiếm, hãy viết thủ tục cho phép tráo đổi nội dung
của các nút trong cây, nhưng không thay đổi cấu trúc cây, để nhận được cây nhị phân tìm kiếm.
Giải:


Đọc cây vào mảng phải đọc theo thứ tự giữa

8



7


6




4



3

<sub>1</sub>



9



4


8


3



6



1

<sub>9</sub>



7



3 6 8 4 9 7 1


1 3 4 6 7 8 9


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

Procedure SapLai(Goc: Tro);


Type Mang = Array[1..100] of Integer;
Var n: Integer;


Procedure DocVaoMang(Goc: Tro; Var A: Mang; Var n: Integer);
// n là phần tử đưa vào có số thứ tự n mang thông tin ra


Begin



If Goc <> Nil) Then
Begin


DocVaoMang(Goc^.Trai, A, n);
n:= n + 1;


A[n]:= Goc^.GiaTri;


DocVaoMang(Goc^.Phai, A, n);
End;


End;


Procedure XepThuTuTrenMang(Var A: Mang; n: Integer);
Procedure DuaVaoCay(Goc: Tro; A: Mang);


Var i: Integer;
Begin


If (Goc <> Nil) Then
Begin


DuaVaoCay(Goc^.Trai, A, i);
Goc^.GiaTri:= A[i];


i:= i + 1;


DuaVaoCay(Goc^.Phai, A, i);
End;



End;
BEGIN


N:= 0;


DocVaoMang(Goc, A, n);
XepThuTuTrenMang(A, n);
N:= 1;


DuaVaoCay(Goc, A, n);
END;


TỔNG KẾT:


* Đối với cây nhị phân nói chung có 3 phương án duyệt là đệ quy và không đệ quy.
<b>-</b> Gốc Trái Phải


<b>-</b> Trái Gốc Phải
<b>-</b> Trái Phải Gốc


Thăm gốc: Có nghĩa là ta quản lí địa chỉ của nút hay gốc đó và ta làm việc với nút đó là tùy bài tốn
cụ thể.


Cây nhị phân tìm kiếm:
<b>-</b> Có 3 giải thuật cơ bản:


+ Tìm kiếm một nút thỏa mãn điều kiện (dù nút đó là gì) và cho ra nút đó nếu có, nếu khơng
cho ra địa chỉ Nil


+ Tìm nút có giá trị Khóa cho trước, nếu có thì cho ra địa chỉ của nút đó, cịn khơng thì bổ


sung vào nút mới và cuối cùng cho ra địa chỉ nút đó.


+ Loại bỏ một nút:




10


7


15



4



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

 p khơng có con trái
 p có con trái


Procedure LoaiBo(Var Goc: Tro; p: Tro);
Begin


If (p=Goc) Then
Begin


If (p^.Trai = Nil) Then Goc:= Goc^.Phai
Else


Begin


r:= Goc^.Trai;


While r^.Phai <> Nil Do r:= r^.Phai
R^.Phai:= Goc^.Phai;



Goc:= Goc^.Trai;
End;


Dispose(p);
End


Else // Khi gốc không trùng p


If (p^.GiaTri < Goc^.GiaTri) Then LoaiBo(Goc^.Trai, p)
Else LoaiBo(Goc^.Phai, p);


End;


- Phải xác định được con trỏ quản lí p (trong cây và ở một nút nào đó) đóng vai trị quản lí gốc
- Khi Goc = p: Có cây con trái -> Loại bỏ gốc


Nếu khơng có -> Loại bỏ
Khơng đệ quy:


+ Tìm nút q mà trỏ phải hoặc trái của nó quản lí p:
Procedure LoaiBo(Var Goc: Tro; p: Tro);
Var q, r: Tro;


Begin


// Tìm nút q nhận p làm nút con
q:= Goc;


While (q^.Trai <> p) and (q^.Phai <> p) Do



If (q^.GiaTri <p^.GiaTri) Then q:= q^.Phai Else q:= q^.Trai;
//Điều chỉnh lại các con trỏ trên cây


If (p^.Trai = Nil) Then


If q^.Trai = p Then q^.Trai:= p^.Phai Else q^.Phai:= p^.Phai
Else


Begin


If (q^.Trai = p) Then q^.Trai:= p^.Trai Else q^.Phai:=
p^.Trai;


//Nếu con trỏ trái của q = p -> Con trỏ trái của q sẽ quản lí con trỏ
trái của p ngược lại con trỏ phải của q sẽ quản lí con trỏ trái của p


r:= p^.Trai;


While (r^.Phai <> Nil) Do r:= r^.Phai;
r^.Phai:= p^.Phai;


End;
Dispose(p);
End;


* Bổ sung thêm trường hợp p = Goc (p là gốc)
If (p= Goc) Then


If (p^.Trai = Nil) Then Goc:= p^.Phai


Else


Begin


r:= p^.Trai;


While (r^.Phai <> Nil) Do r:= r^.Phai;
r^.Phai:= Goc^.Phai;


Goc:= p^.Trai;
End;


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

ĐỀ IFI 1997:
Bài 4:


Người ta biểu diễn một biểu thức số học với các toán tử +, -, *, / hai ngôi và +, - một ngơi bằng một
cây. Trong đó với mọi tốn tử được chứa ở một nút trong và mỗi biến được chứa ở một lá của cây.
Chẳng hạn: (((a+b)*c)-(((-c)/d/e)) được biểu diễn bởi cây sau:


Viết khai báo của cây nhị phân nói trên. Giả sử rằng với mọi biến có một giá trị cho trước. Hãy viết
một chương trình con cho phép từ một cây đã thành lập ở bộ nhớ trong như trên, tính giá trị của biểu
thức tốn học liên quan.


Giải:
Type


Str25 = String[25];
Tro = ^Nut;
Nut = Record



Giatri: Str25;
Trai, Phai: Tro
End;


Function Value(S: Str25): Integer;
Var k, n: Integer;


Begin


Val(S, n, k); //Đổi chuỗi S thành số n, nếu thành công k =0, nếu có
lỗi k<> 0


Value:= n;
End;


Function GTBT(Goc: Tro): Real;
Begin


If (Goc^.Trai = Nil) and (Goc^.Phai =Nil) Then GTBT:=
Value(Goc^.GiaTri)


Else


Case Goc^.GiaTri Of


“*”:


GTBT:= GTBT(Goc^.Trai) *
GTBT(Goc^.Phai);



“/” :


GTBT:= GTBT(Goc^.Trai) /
GTBT(Goc^.Phai);


“+”:


If (Goc^.Trai = Nil) Then
GTBT:= GTBT(Goc^.Phai)
Else


GTBT:= GTBT(Goc^.Trai) +
GTBT(Goc^.Phai);


“-“ :


If (Goc^.Trai = Nil) Then


GTBT:= - GTBT(Goc^.Phai)
Else




-*

/



+

c

e



a

b



/




-

d



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

GTBT:= GTBT(Goc^.Trai) -
GTBT(Goc^.Phai);


End;
End;


2. Giả sử một biểu thức số học với ngoặc đơn đầy đủ đã được đọc sẵn vào một biến lưu kiểu String.
Hãy viết một chương trình con thành lập cây biểu diễn biểu thức đó. Cây này được lưu ở bộ nhớ trong
của máy tính.


Giải:
Ý tưởng:


- Xác định một toán tử cùng với các biểu thức con nằm trước và sau tốn tử đó


- Tạo cây với gốc chứa tốn tử này, sau đó gọi đệ quy để tạo cây con phải chứa biểu thức con phía sau.
Nếu có biểu thức con phía trước thì tạo cây con trái chứa biểu thức con này


- Ngược lại vì đây là một tốn tử một ngơi do đó cây con trái rỗng.


Tình huống suy biến đệ quy: Khi xâu St khơng có dấu ngoặc nào (chỉ chứa biến).
Procedure DungCay(Var Goc: Tro; St: String);


Var
Begin


If (KiemTra(St)) Then



/* KiemTra(St) = T nếu St khơng có dấu ngoặc nào


F nếu St có chứa dấu ngoặc */
Begin


New(Goc);


Goc^.GiaTri:= St;


Goc^.Trai:= Nil; Goc^.Phai:= Nil;
End


Else


Begin


If ((St[2] = “+”) or (St[2]= “-“)) Then
Begin


New(Goc);


Goc^.GiaTri:= St[2];


Goc^.Trai:= Nil; //Vì đây là biểu thức một
ngôi


Delete(St, 1, 2);


Delete(S, Length(St),1);


DungCay(Goc^.Phai, St);
End;


Else


Begin


n:= VitriToanTu(St);
S1:= XauPhiaTruoc(St, n);
S2:= XauPhiaSau(St, n);
New(Goc);


Goc^.GiaTri:= St[n];
DungCay(Goc^.Trai, S1);
DungCay(Goc^.Phai, S2);
End;


End;
End;


Function ViTriToanTu(St: String): Integer;


// Đếm vị trí của tốn tử mà tốn tử đó tách biểu thức đã cho thành 2 biểu thức con trước và //sau.
// Xác định xâu S1: For i:= 2 to n -1 do


// Xác định xâu S2: For j:= n +1 to (length(S) -1) Do
ĐỀ SỐ 2/1996


Bài 1:



Dãy Morse vô hạn được xác định như sau:


m = x0, x1, …, xn
- Ban đầu: Viết phần tử x0 = 0


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

n = n-1 , n-1 ở đây dãy con n-1 được xây dựng từ dãy con n-1 bằng cách thay 0 thành 1,
thay 1 thành 0.


0 = 0;
1 = 0 ,1
2 = 0, 1, 1, 0


1. Viết hàm đệ quy xây dựng giá trị của phần tử thứ k trong dãy Morse. Ví dụ;
k = 0: x0 = 0;


k = 7; x7 = 1;
….


Giải:


Suy biến đệ quy: k = 0;
Nếu k > 0


0 = x5 phủ định của x1 = 1;
1 = x1 phủ định của x0 = 0;


Function Phudinh(a: Integer): Integer;
Begin


If (a = 0) Then PhuDinh:= 1


Else


Begin


S:= 1;


// Số lượng phần tử k chạy từ 0. Ví dụ k =6 -> có 7 phần
tử


While S < k+1 Do
Begin


S:= S*2;
M:= S div 2;
End;


Xacdinh:= PhuDinh(Xacdinh(k-m));
End;


End;


2. Đưa ra phương án không dùng đệ quy:
Giải:


Function Xacdinh(k: Integer): Integer;
Var kk, i, Dem, a, m, S: Integer;
Begin


kk:= k; Dem:= 0;
While (kk > 0) Do



Begin


S:= 1;


While S < kk + 1 Do S:= S*2;
M:= S div 2;


Kk:= kk – m;
Dem:= Dem + 1;
End;


A:= 0;


For i:= 1 to Dem Do a:= PhuDinh(a);
Xacdinh:= a;


End;


Nếu không sử dụng (1) ta phải bỏ đi (3) và (2) sẽ được thay bằng a:= Phudinh(a), và thêm phép gán
a:= 0; ngay từ đầu.


ĐỀ NĂM 1998
Bài 2:


Khai báo kiểu của một danh sách tuyến tính móc nối như sau:
Type Tro=^Nut;


Nut = Record



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

End;
Var ds: Tro;


Viết chương trình thực hiện các cơng việc sau:


1. Function Doixung(ds: Tro): Boolean; nhằm kiểm tra xem danh sách ds có phải là đối xứng hay
khơng? Viết hai phương án lặp và đệ quy.


Đệ quy:


<b>-</b> Suy biến đệ quy: Danh sách rỗng -> Đối xứng


Danh sách có một nút -> Đối xứng
Function Doixung(ds: Tro): Boolean;


Var
Begin


//Xét khi suy biến đệ quy


If (ds = Nil) or (ds^.Tiep = Nil) Then Doixung:= True
Else


Begin


d:= ds;
r:= ds;
c:= r^.Tiep;


While c^.Tiep <> Nil Do


Begin


r:= c;


c:= c^.Tiep;
End;


If (d^.GiaTri <> c^.GiaTri) Then DoiXung:= False
Else


Begin


r^.Tiep:= Nil;


Doixung:= Doixung(ds^.Tiep);
End;


End;
End;


Phương án lặp:


Function Doixung(Ds: Tro): Boolean;
Var d, c, r: Tro; OK: Boolean;
Begin


OK:= True;
d:= Ds;


While ((d <> Nil) and (d^.Tiep <> Nil) and OK ) Do


Begin


r:= d; c:= r^.Tiep;


While (c^.Tiep <> Nil) Do
Begin


R:= c;


C:= c^.Tiep;
End;


If (d^.Giatri <> c^.GiaTri) Then OK:= False
Else


Begin


r^.Tiep:= Nil;
d:= d^.Tiep;
End;


End;


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

2. Xây dựng hàm Function KiemTra_DX(ds: Tro): Boolean; nhằm kiểm tra xem đối với danh sách ds
đã cho, có tồn tại một cách sắp xếp lại các phần tử để cuối cùng nhận được một danh sách đối xứng
hay không? Viết 2 phương án đệ quy và lặp.


Giải:


<b>-</b> Quản lí nút đầu tiên. Tìm trong danh sách có nút chứa số giống nó


<b>-</b> Nếu có: Loại cặp nút đó. Lặp lại


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

ĐỀ 2006:


Type TroNut =^Nut;


Nut = Record


GiaTri: Integer;


Left, Right: TroNut;
End;


Var T: Tro;


a.Tính chiều cao của cây


Function ChieuCao(T: TroNut): Byte;
Begin


If (T = Nil) Then ChieuCao:= 0
Else


ChieuCao:= Max(ChieuCao(T^.Left), ChieuCao(T^.Right)) + 1;
End;


b.


Type TroNutDS = ^NutDS;
NutDS = Record



GiaTri: Integer;


Muc: Byte; {lưu mức tương ứng}
Next: TroNutDS;


End;
Var F: TroNutDS;


Procedure Ghi(T: TroNut; Var F: TroNutDS; Level: Byte);
Var


Begin


If (T <> Nil) Then
Begin


New(p); p^.GiaTri:= T^.GiaTri;
P^.Muc:= level;


P^.Next: = F;
F:= p;


Ghi(T^.Left, F, Level + 1);
Ghi(T^.Right, F, Level + 1);
End;


End;


c. Viết hàm đếm số nút DemSoNut(F: TroNutDS; Level: Byte): Integer;


Function DemSoNut(F: TroNutDS; Level: Byte): Integer;
Var p: TroNutDS; Dem: Integer;


Begin


p:= F;


While (p<> Nil) do
Begin


If (p^.Muc = level) Then Dem:= Dem + 1;
P:= p^.Next;


End;
DemSoNut:= Dem;
End;


d. Kiểm tra xem cây có phải là cây nhị phân đầy đủ:
Function LaCayNPDD(T: TroNut): Boolean;


Var
Begin


H:= ChieuCao(T);
SoNut:= 1;


For i:= 1 to h – 1 do


SoNut:= SoNut*2; // Số nút tối đa ở một mức
Ghi(T, F, 1);



If (SoNut = DemSoNut(F,h) Then LaCayNPDD:= True
Else


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

/* Bai tap 3_52 - In bieu thuc dang hau to cua mot bieu thuc trung to */
#include <stdio.h>


#include <conio.h>
#define MAX 100


#define PLUS 0 /* Dau cong */
#define MINUS 1 /* Dau tru */
#define MULTIPLE 2 /* Dau nhan */
#define DIVIDE 3 /* Dau chia */


#define LPAREN 4 /* Dau mo ngoac don */
#define RPAREN 5 /* Dau dong ngoac don */
int top;


struct {
int toantu;
} stack[MAX];
void push (int tt)
{


if (top < MAX-1)


stack[++top].toantu = tt;
}



int isempty()
{


return top == -1;
}


int pop (int *tt)
{


if (!isempty())
{


*tt = stack[top--].toantu;
return 1;


}


return 0;
}


int get (int *tt)
{


if (!isempty())
{


*tt = stack[top].toantu;
return 1;


}



return 0;
}


void xet(int tt)
{


char chuoi[] = "+-*/";


int uutien[] = {0,0,1,1,-1,-1};
int toantu, done = 0, val;
if (isempty())


push(tt);
else


{
do {


if (get(&toantu))
{


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

{


pop(&toantu);


printf("%c ", chuoi[toantu]);
}


else


{


push(tt);
done = 1;
}


}
else
{


done = 1;
push(tt);
}


} while (!done);
}


}


void in_hauto(char *expr)
{


int len, i=0, ttu, done;
char c, chuoi[]="+-*/";
top = -1;


len = strlen(expr);
do {


c = expr[i++];



while (c == ' ' && i < len-1)
c = expr[i++];


switch (c)
{


case '0' :
case '1' :
case '2' :
case '3' :
case '4' :
case '5' :
case '6' :
case '7' :
case '8' :


case '9' : printf("%c ", c); break;
case '+' : xet(PLUS); break;


case '-' : xet(MINUS); break;
case '*' : xet(MULTIPLE); break;
case '/' : xet(DIVIDE); break;
case '(' : push(LPAREN); break;
case ')' : done = 0;


do {


if (isempty())
{



done = 1;


printf("\n\nError\n");
}


else
{


pop(&ttu);


if (ttu != LPAREN)


printf("%c ", chuoi[ttu]);
else


done = 1;
}


} while (!done);
break;


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

} while (i < len);
while (!isempty())
{


pop(&ttu);


printf("%c ", chuoi[ttu]);
}



}


void main()
{


char expr[50];
int done = 0;


printf("\nChuong trinh in bieu thuc hau to tuong ung voi mot bieu thuc"
"trung to hop le"


"\nChu y :"


"\nCac toan hang chi tu 0 den 9"


"\nCac toan tu chi gom + - * / ( )\n");
do {


printf("\nNhap mot bieu thuc trung to hop le (trong de thoat): ");
gets(expr);


if (strlen(expr) > 0)
in_hauto(expr);
else


done = 1;
} while (!done);
}



//Dem tong so nut la cua cay
#include <stdio.h>


#include <alloc.h>


typedef int element_type;
typedef struct node {
element_type element;
struct node *left, *right;
} NODE;


NODE *root;


void khoi_tao_cay(NODE ** root)
{


*root = NULL;
}


void insert(NODE *tmp, NODE **root)
{


if (tmp->element < (*root)->element)
if ((*root)->left)


insert(tmp, &(*root)->left);
else


(*root)->left = tmp;
else



if ((*root)->right)


insert(tmp, &(*root)->right);
else


(*root)->right = tmp;
}


void insert_node(element_type e, NODE **root)
{


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

tmp = (NODE *)malloc(sizeof(NODE));
tmp->element = e;


tmp->left = NULL;
tmp->right = NULL;
if (*root == NULL)
*root = tmp;
else


insert(tmp, root);
}


void nhap_cay(NODE **root)
{


element_type e;
do {



printf("\nNhap element (-1 de ket thuc) : ");
scanf("%d", &e);


if (e != -1)


insert_node(e, root);
} while (e != -1);


}


int dem_nut_la(NODE *root)
{


if (root == NULL)
return 0;


else


if (root->left != NULL || root->right != NULL)


return dem_nut_la(root->left) + dem_nut_la(root->right);
else


return 1;
}


void main()
{


int tong_nut_la;


khoi_tao_cay(&root);
nhap_cay(&root);


tong_nut_la = dem_nut_la(root);


printf("\nTong so nut la = %d", tong_nut_la);
getch();


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

<b>Uses crt;</b>
<b>Type</b>


DS1 =^SN;
SN = Record


info:integer;
next:DS1;
end;


DS2 =^TEN;
TEN = Record


ten:string;
dau:DS1;
down:DS2;
end;


<b>Var</b>


index:DS2;
st,ten1:string;


so:integer;


{****************************************************}
<b>Procedure</b> Bosung(<b>var</b> index:ds2;so:integer;ten:string);
<b>Var</b> p,q,tempo:DS2;


tam,tmp:DS1;
<b>Begin</b>


new(tam);
tam^.info:=so;
tam^.next:=nil;
p:=index;


<b>while</b> (p<>nil) <b>and</b> (p^.ten<ten) <b>do</b>
<b>begin</b>


q:=p;


p:=p^.down;
<b>end;</b>


<b>if</b> (p<>nil) <b>and</b> (p^.ten=ten) <b>then</b>
<b>begin</b>


tmp:=p^.dau;


<b>while</b> tmp^.next<>nil <b>do</b> tmp:=tmp^.next;
tmp^.next:=tam;



<b>end</b>
<b>else</b>
<b>begin</b>


new(tempo);
tempộten:=ten;
tempộdau:=tam;
<b> if</b> p=index <b>then</b>
<b> begin</b>


tempộdown:=index;
index:=tempo;


<b>end</b>
<b> else</b>
<b> begin</b>


tempộdown:=p;
q^.down:=tempo;
<b>end;</b>


<b> end;</b>
<b>end;</b>


{***********************************************}
<b>Procedure</b> Inbang(index:ds2);


<b>var</b> p:ds2;tam:ds1;
aa: string[10];
<b>begin</b>



writeln;


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

<b>while</b> p<>nil <b>do</b>
<b>begin</b>


write(' ',p^.ten,' ':35-length(p^.ten));
tam:=p^.dau;


<b>while</b> tam<>nil <b>do</b>
<b>begin</b>


str(tam^.info,aa);


write(tam^.info,' ': 5- length(aa));
tam:=tam^.next;


<b>end;</b>


p:=p^.down;
writeln;
<b>end;</b>


<b>end;</b>


(* --- *)
//Xoá tên của học viên trong danh sách


<b>Procedure</b> Xoaten(<b>var</b> index: ds2;st: string);
<b>Var</b> p,q: ds2;



<b>Begin</b>


p:= index;


<b>While</b> (p<> nil)and(p^.ten< st)<b> do</b>
<b>Begin</b>


q:= p;


p:= p^.down;
<b>end;</b>


<b>If</b> p = nil <b>then</b> Writeln('Khong co ten nay trong danh sach')
<b>else</b>


<b>if</b> p= index then index:= index^.down
<b>else</b>


q^.down:= p^.down;
<b>end;</b>


(* --- *)
<b>Procedure </b>Xoa(var index: ds2; st: string;so: integer);


<b>Var</b> tam,p1: ds1;
p,q: ds2;
<b>Begin</b>


p:= index;



<b>While </b>(p <> nil) and (p^.ten < st ) <b>do</b>
<b>Begin</b>


q:= p;


p:= p^.down;
<b>end;</b>


<b>If</b> p = nil <b>then</b> Writeln('Khong co ten nay trong danh sach')
<b>else</b>


<b>begin</b>


tam:= p^.dau;


<b>While</b> (tam <> nil)and( tam^.info <> so) <b>do</b>
<b>Begin</b>


p1:= tam;


tam:= tam^.next;
<b>end;</b>


<b>If</b> tam = nil <b>then</b> writeln('Khong co so trang trong ten nay')
<b>else</b>


<b>if</b> tam= p^.dau <b>then</b> p^.dau:= p^.dau^.next
<b>else</b>



p1^.next:= tam^.next;
<b>end;</b>


<b>end;</b>


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

<b>Procedure</b> Sapxep(var index: ds2);
<b>Var</b> p1,q1: ds1;


tam: integer;
p: ds2;


<b>Begin</b>


p:= index;


<b>While</b> p<> nil <b>do</b>
<b>Begin</b>


p1:= p^.dau;


<b>While</b> p1^.next <> nil <b>do</b>
<b>Begin</b>


q1:= p1^.next;
<b>While</b> q1 <> nil <b>do</b>


<b>Begin</b>


<b>If</b> p1^.info > q1^.info <b>then</b>
<b>Begin</b>



tam:= p1^.info;
p1^.info:= q1^.info;
q1^.info:= tam;
<b>end;</b>


q1:= q1^.next;
<b>end;</b>


p1:= p1^.next;
<b>end;</b>


p:= p^.down;
<b>end;</b>


<b>end;</b>


(*---*)
{ Thu tuc dem xem co bao nhieu trang xuat hien cua ten: '}


<b>Procedure</b> Demst(var index: ds2);
<b>Var</b> dem: byte;


p,q: ds2;
p1: ds1;
<b>Begin</b>


Writeln(' TEN SO LAN XUAT HIEN ');
p:= index;



<b>While</b> p<> nil<b> do</b>
<b>Begin</b>


p1:= p^.dau;
Dem:= 1;


<b>While</b> p1^.next <> nil <b>do</b>
<b>Begin</b>


dem:= dem+ 1;
p1:= p1^.next;
<b>end;</b>


Writeln(' ', p^.ten,' ':35-length(p^.ten),dem);
p:= p^.down;


<b>end;</b>
<b>end;</b>


<b>BEGIN</b> {CHUONG TRINH CHINH}
<b>Repeat</b>


write('Nhap ten :');readln(st);
<b>if</b> st<>'' <b>then</b>


<b>begin</b>
<b>repeat</b>


write('Nhap so trang :');readln(so);
if so>0 then bosung(index,so,st);


<b>until</b> so<=0;


<b>end;</b>
<b>until</b> st='';


</div>

<!--links-->

×