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)
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;
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);
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;
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
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;
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:
Khai báo của danh sách (Đầu, Cuối) như sau:
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
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;
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>+ 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;
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 ở
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).
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;
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. 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);
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
TinhGiaTri:= Max(TinhGiaTri(Goc^.Trai),
TinhGiaTri(Goc^.Phai))
Else
TinhGiaTri:= Min(TinhGiaTri(Goc^.Trai),
TinhGiaTri(Goc^.Phai))
End;
Procedure TaoCayB(Goc: TroNut);
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);
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 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
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.
Begin
- Lấy một nút từ danh sách, gọi đó là 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
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:=
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ư
- 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
Trái
- 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:
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;
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
3 6 8 4 9 7 1
1 3 4 6 7 8 9
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ổ
+ Loại bỏ một nút:
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
Begin
r:= p^.Trai;
While (r^.Phai <> Nil) Do r:= r^.Phai;
r^.Phai:= Goc^.Phai;
Goc:= p^.Trai;
End;
ĐỀ 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
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);
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
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
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
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
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
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;
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ó
ĐỀ 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;
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
/* 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))
{
{
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;
} 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)
{
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;
tong_nut_la = dem_nut_la(root);
printf("\nTong so nut la = %d", tong_nut_la);
getch();
<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;
{****************************************************}
<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;
<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>
<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>end;</b>
<b>until</b> st='';