96
TRƯỜNG ĐẠI HỌC SƯ PHẠM KỸ THUẬT HƯNG YÊN KHOA CÔNG NGHỆ THÔNG TIN BÀI TẬP THỰC HÀNH HỌC PHẦN: CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT Trình độ đào tạo Hệ đào tạo : : Đại học Chính quy Hưng Yên năm 2012

Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Embed Size (px)

Citation preview

Page 1: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

TRƯỜNG ĐẠI HỌC SƯ PHẠM KỸ THUẬT HƯNG YÊN

KHOA CÔNG NGHỆ THÔNG TIN

BÀI TẬP THỰC HÀNH

HỌC PHẦN: CẤU TRÚC DỮ LIỆU

VÀ GIẢI THUẬT

Trình độ đào tạo

Hệ đào tạo

:

:

Đại học

Chính quy

Hưng Yên năm 2012

Page 2: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 2

MỤC LỤC

BÀI THỰC HÀNH 1. KIỂU DỮ LIỆU CÓ CẤU TRÚC ................................................................................ 3

BÀI THỰC HÀNH 2. ĐỘ PHỨC TẠP TÍNH TOÁN .................................................................................. 16

BÀI THỰC HÀNH 3+4. DANH SÁCH NỐI ĐƠN ......................................................................................... 22

BÀI THỰC HÀNH 5. NGĂN XẾP - STACK ............................................................................................. 42

BÀI THỰC HÀNH 6. HÀNG ĐỢI - QUEUE ........................................................................................... 53

BÀI THỰC HÀNH 7. DANH SÁCH LIÊN KẾT KÉP ................................................................................. 59

BÀI THỰC HÀNH 8. DANH SÁCH LIÊN KẾT VÒNG ............................................................................. 70

BÀI THỰC HÀNH 9. CÂY NHỊ PHÂN .................................................................................................. 81

BÀI THỰC HÀNH 10. Kiểm tra thực hành .......................................................................................... 96

Page 3: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 3

BÀI THỰC HÀNH 1. KIỂU DỮ LIỆU CÓ CẤU TRÚC

* Mục tiêu

Hệ thống lại kiến thức về kiểu dữ liệu mảng, xâu, tệp, cấu trúc: Cách khai báo, các

thao tác trên, cách thức tổ chức bộ nhớ của mảng, xâu, tệp, cấu trúc

* Yêu cầu:

A. Bài tập mẫu

Bài 1: Cho n số nguyên dương a0,a1,a2,...,an-1.

a.Chèn phần tử x vào vị trí k của dãy.

b.Xóa tất cả các số nguyên tố trong dãy.

Gợi ý:

a.Khởi tạo một mảng trung gian tmp có độ dài là (a.Length+1) sau đó gán các giá

trị : tmp[i]=a[i] với i từ 0 ->k-1 (k-1 là vị trí trước vị trí cần chèn)

tmp[k]=giá trị cần chèn

tmp[i+1]=a[i] với i từ k->a.Length-1

Cuối cùng gán mảng a=tmp.

b.Thực hiện duyệt các phần tử trong mảng kiểm tra xem phần tử đó có phải là số

nguyên tố hay không (số nguyến tố là số chỉ chia hết cho 1 và chính nó) :

+ Nếu là số nguyên tố: Duyệt mảng từ trái sang phải.Từ vị trí số nguyên tố đó tiến

hành dời các phần tử về phía trước cho đến khi kết thúc mảng, sau đó giảm kích

thước mảng

+Ngược lại, chuyển sang kiểm tra phần tử kế tiếp

Lời giản mẫu

using System;

class VD

{ static int[] a;

static void Nhap()

{ int n;

Console.Write("Nhap n=");

n = int.Parse(Console.ReadLine());

a = new int[n];

Page 4: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 4

for (int i = 0; i < a.Length; ++i)

{

Console.Write("a[" + i + "]=");

a[i] = int.Parse(Console.ReadLine());

}

}

static void Chen(int x, int k)

{

if (k >= 0 && k <= a.Length - 1)

{

int[] tmp = new int[a.Length + 1];

for (int i = 0; i < k; ++i)

tmp[i] = a[i];

tmp[k] = x;

for (int i = k; i < a.Length; ++i)

tmp[i + 1] = a[i];

a = tmp;

}

else Console.WriteLine("Du lieu khong hop le");

}

static bool ngto(int x)

{

bool ok = true;

for (int i = 2; i < x - 1; ++i)

if (x % i == 0) { ok = false; break; }

return ok;

}

static void Xoa()

{

int n = a.Length;

for (int i = 0; i < n; )

if (ngto(a[i]))

Page 5: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 5

{

for (int j = i; j < a.Length - 1; ++j)

a[j] = a[j + 1];

n = n - 1;

}

else ++i;

int[] tmp = new int[n];

for (int i = 0; i < n; ++i)

tmp[i] = a[i];

a = tmp;

}

static void Hien()

{

for (int i = 0; i < a.Length; ++i)

Console.Write(a[i] + "\t");

Console.WriteLine();

}

static void Main()

{

Nhap();

Chen(333, 1);

Hien();

Xoa();

Hien();

Console.ReadKey();

}

}

Bài 2: Cho một danh sách lưu trữ thông tin về các nhân viên trong một công ty, thông tin

gồm :

- Mã nhân viên

- Họ và tên

- Năm sinh (số nguyên)

Page 6: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 6

- Phòng ban

- Lương cơ bản (số nguyên)

- Thưởng (số nguyên)

- Thực lĩnh (số nguyên, trong đó thực lĩnh = lương cơ bản + thưởng )

Hãy thực hiện các yêu cầu sau:

a.Tính tổng thực lĩnh tháng của tất cả nhân viên trong công ty.

b.In danh sách những nhân viên có mức lương cơ bản thấp nhất.

Gợi ý:

Để lưu trữ thông tin của từng nhân viên ta khai báo một cấu trúc lưu trữ các thông tin

struct NhanVien

{

public string MaNV;

public string Hoten;

public int Namsinh;

public string Phongban;

public int LuongCB;

public int Thuong;

}

class VD

{

static NhanVien[] DS;

a.Thực hiện duyệt từng nhân viên : tính thực lĩnh của từng người sau đó cộng các

thực lĩnh lại với nhau

b.Trước tiên ta tìm mức lương cơ bản thấp nhất bằng cách :

+ Gán một giá trị min bằng lớn vô cùng : int min = int.MaxValue;

+Duyệt qua từng nhân viên nếu nhân viên nào có mức lương nhỏ hơn min thì

gán min bằng mức lương đó

Cuối cùng in ra thông tin của các nhân viên có mức lương bằng min

Lời giản mẫu

using System;

struct NhanVien

{

Page 7: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 7

public string MaNV;

public string Hoten;

public int Namsinh;

public string Phongban;

public int LuongCB;

public int Thuong;

}

class VD

{

static NhanVien[] DS;

static void Nhap()

{

int n;

Console.Write("Nhap n="); n = int.Parse(Console.ReadLine());

DS = new NhanVien[n];

for (int i = 0; i < DS.Length; ++i)

{

Console.WriteLine("Nhap thong tin NV thu:" + i);

Console.Write("Ma nhan vien:"); DS[i].MaNV = Console.ReadLine();

Console.Write("Ho ten:"); DS[i].Hoten = Console.ReadLine();

Console.Write("Nam sinh:"); DS[i].Namsinh = int.Parse(Console.ReadLine());

Console.Write("Phong ban:"); DS[i].Phongban = Console.ReadLine();

Console.Write("Luong co ban:"); DS[i].LuongCB =

int.Parse(Console.ReadLine());

Console.Write("Thuong:"); DS[i].Thuong = int.Parse(Console.ReadLine());

}

}

static int ThucLinh(int i)

{

return DS[i].Thuong + DS[i].LuongCB;

}

static void HienMin()

Page 8: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 8

{

int min = int.MaxValue;

for (int i = 0; i < DS.Length; ++i)

if (min > DS[i].LuongCB) min = DS[i].LuongCB;

Console.WriteLine("Danh sach luong cb min");

for (int i = 0; i < DS.Length; ++i)

if (DS[i].LuongCB == min)

Console.WriteLine(DS[i].MaNV + "\t" + DS[i].Hoten + "\t" + DS[i].Namsinh

+ "\t" + DS[i].Phongban + "\t" + DS[i].LuongCB + "\t" + DS[i].Thuong + "\t" +

ThucLinh(i));

}

static void TongLuongCTy()

{

int t = 0;

for (int i = 0; i < DS.Length; ++i)

t += ThucLinh(i);

Console.WriteLine("Tong luong cty:" + t);

}

static void Main()

{

Nhap();

TongLuongCTy();

HienMin();

Console.ReadKey();

}

}

B. Bài tập tự giải

Bài 1: Cho n số nguyên dương a0,a1,a2,...,an-1.

a.Chèn phần tử x vào vị trí k của dãy.

b.Xóa tất cả các số nguyên tố trong dãy.

c.Kiểm tra dãy có tăng dần hay không ?

d.Tìm số nhỏ nhất chia hết cho tất cả các số của dãy.

Page 9: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 9

e.Tìm các cặp số nguyên tố cùng nhau (hai số nguyên dương được gọi là nguyên

tố cùng nhau nếu ước số chung lớn nhất của chúng bằng 1).

f.Tìm tần số xuất hiện của các số trong dãy.

Gợi ý:

a. Khởi tạo một mảng trung gian tmp có độ dài là (a.Length+1) sau đó gán các

giá trị : tmp[i]=a[i] với i từ 0 ->k-1 (k-1 la vị trí trước vị trí cần chèn)

tmp[k]=giá trị cần chèn

tmp[i+1]=a[i] với i từ k->a.Length-1

Cuối cùng gán mảng a=tmp.

b. Thực hiện duyệt các phần tử trong mảng kiểm tra xem phần tử đó có phải la số

nguyên tố hay không (số nguyến tố là số chỉ chia hết cho 1 và chính nó) :

+ Nếu là số nguyên tố: Duyệt mảng từ trái sang phải. Từ vị trí số nguyên tố đó tiến

hành dời các phần tử về phía trước cho đến khi kết thúc mảng,sau đó giảm kích

thước mảng

+ Ngược lại,chuyển sang kiểm tra phần tử kế tiếp

c. Duyệt qua các phần tử a[i] của mảng với i từ 0->n-2, tại mỗi phần tử kiểm tra

xem nó có nhỏ hơn các phần tử a[j] kế tiếp không với j=i+1->n-1

+ Nếu không, thoát khỏi vòng lặp trả ra giá trị False (không tăng dần)

+ Ngược lại, kiểm tra phần tử a[i] kế tiếp

d. Đầu tiên ta xây dựng một hàm BCNN(int x,int y) tính BCNN của 2 số. Sau đó

ta khởi tạo giá trị int bc = 1 rồi thực hiện tính BCNN của bc với từng phần tử của

mảng, kết quả thu được đưa vào bc

e. Xây dựng một hàm tìm UCLN của 2 số

Thực hiện duyệt qua từng phần tử a[i] của mảng với i từ 0->n-2, với mỗi phần tử

ta tìm UCLN của phần tử đó với từng phần tử a[j] kế tiếp nó với j từ i+1 -> n-1 .

nếu UCLN =1 ta in ra cặp a[i],a[j] đó.

f. Ta tạo 2 mảng mới: mảng b chứa các phần tử không trùng nhau của mảng a,

mảng c chứa tần số xuất hiện của các số tương ứng ở mảng b ( khởi tạo các phần

tử của c =0)

Khởi tạo b[0]=a[0]. Duyệt qua các phần tử của mảng a:

+Nếu a[i] = b[i] thì c[i] =c[i]+1

+Nếu a[i] !=b[i] thì b[i+1]=a[i]

Page 10: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 10

Bài 2: Cho ma trận vuông n dòng và n cột; các phần tử là các số nguyên (0≤ n < 100).

Viết các hàm thực hiện các yêu cầu sau:

a.Tính tổng tất cả các phần tử của ma trận.

b.Tìm giá trị dương nhỏ nhất của ma trận.

c.Tính tổng các phần tử nằm trên đường chéo phụ.

d.Kiểm tra xem các phần tử nằm trên đuờng chéo chính có tăng dần hay không ?

(theo chiều từ góc trên bên trái xuống góc dưới bên phải).

Gợi ý:

a. Khởi tạo 1 giá trị t=0.Sau đó duyệt qua từng phần tử của ma trận , thực hiện

cộng t với từng phần tử trong ma trận:

b. Khởi tạo giá trị min bằng dương vô cùng int min = int.MaxValue;

Thực hiện duyệt qua các phần tử của ma trận,nếu thấy phần tử đó nhỏ hơn

min và lớn hơn 0 thì gán vào min

c.Ta nhận thấy rằng các phần tử a[i,j] thuộc đường chéo chính của ma trận cấp n

thì có j=(n-1)-i với i ,j chạy từ 0 ->n-1

Để tính tổng các phần tử đường chéo phụ ta duyệt qua các phần tử a[i,j] của

ma trận nếu phần tử nào thỏa mãn j=(n-1)-i thì ta thực hiện cộng các phần tử đó lại

d.Ta thấy trong ma trận cấp n thì số phần tử trên đường chéo chính la n.

+ Đầu tiên , ta thực hiện việc khai báo một mảng một chiều []tg có n phần tử chứa

các phần tử a[i,j] trên đường chéo chính của ma trận(với i=j) theo chiều từ góc bên

trái phía trên đến bên phải phía dưới

+ Duyệt qua các phần tử tg[i] của mảng tg với i từ 0->n-2, tại mỗi phần tử kiểm tra

xem nó có nhỏ hơn các phần tử tg[j] kế tiếp không với j=i+1 ->n-1

*Nếu không ,thoát khỏi vòng lặp trả ra giá trị False (không tăng dần)

*Ngược lại,kiểm tra phần tử tg[i] kế tiếp

Bài 3: Cho ma trận vuông n dòng n cột; mỗi phần tử của ma trận là một phân số (giả thiết

rằng tử số và mẫu số của các phân số này là các số nguyên). Hãy thực hiện các yêu cầu

sau:

a.Tìm phân số có giá trị nhỏ nhất nằm trong khoảng.(0;1).

b.Đếm số lượng phân số nằm trong ma trận tam giác trên có giá trị nằm trong

khoảng (0,1)

Page 11: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 11

c.Sắp xếp các phân số trong ma trận tăng dần từ trái qua phải và từ trên xuống

dưới.

Gợi ý:

Để lưu trữ thông tin của từng phần tử phân số ma trận ta khai báo một trường lưu

trữ các thông tin của một phân số(tử số và mẫu số)

struct Phanso

{

public int Tu;

public int Mau;

}

class VD

{

static Phanso[] DS;

a.Khởi tạo giá trị nhỏ nhất double min = 1 .

+Thực hiện duyệt qua các phần tử của ma trận.Tại mỗi phần tử thực hiện so sánh

giá trị của tử số chia cho mẫu số với min ,nếu nhỏ hơn min va lớn hơn 0 thì gán

min bằng giá trị đó:

+Hiện ra phần tử có giá trị tử số chia mẫu số bằng min .Dùng một biến đếm int

d=0 đếm các giá trị bằng min,nếu ra khỏi vòng lặp mà d=0 ta kết luận không có

phân số cần tìm

b.Ta thấy các phần tử nằm trong ma trận tam giác trên thì luôn có vị trí hàng nhỏ

hơn vị trí cột (i<j) .Từ đó ta thực hiện việc đếm các phần tử của mảng o vi trí

DS[i,j] thỏa mãn i<j và có giá trị Tử chia cho mẫu trong khoảng (0,1):

c.Thực hiện duyệt các phần tử DS[i,j] của mảng với i từ 0->n-1 và j từ 0->n-2,

Với mỗi phần tử ta so sánh với từng phần tử kế tiếp nó nếu phần tử kế tiếp có giá

trị nhỏ hơn thì thực hiện đổi chỗ 2 phần tử đó với nhau:

Bài 4: Cho một danh sách lưu trữ thông tin về các nhân viên trong một công ty, thông tin

gồm :

- Mã nhân viên

- Họ và tên

- Năm sinh (số nguyên)

- Phòng ban

Page 12: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 12

- Lương cơ bản (số nguyên)

- Thưởng (số nguyên)

- Thực lĩnh (số nguyên, trong đó thực lĩnh = lương cơ bản + thưởng )

Hãy thực hiện các yêu cầu sau:

a.Tính tổng thực lĩnh tháng của tất cả nhân viên trong công ty.

b. In danh sách những nhân viên có mức lương cơ bản thấp nhất.

c. Đếm số lượng nhân viên có mức thưởng >= 1200000.

d. In danh sách các nhân viên tăng dần theo phòng ban, nếu phòng ban trùng nhau

thì giảm dần theo mã nhân viên.

e. Cập nhật tăng lương của tất cả các nhân viên lên 5%

Gợi ý: Để lưu trữ thông tin của từng nhân viên ta khai báo một trường lưu trữ các thông

tin

struct NhanVien

{

public string MaNV;

public string Hoten;

public int Namsinh;

public string Phongban;

public int LuongCB;

public int Thuong;

}

class VD

{

static NhanVien[] DS;

a.Trước hết ta xây dựng một hàm thuclinh(int x) để tính thực lĩnh của một nhân

viên bất kỳ. Sau đó ta duyệt từ đầu đến cuối danh sách nhân viên rồi gọi hàm

thuclinh(i) ra. Khi đó ta sẽ được tổng số thực lĩnh tháng của tất cả các nhân viên

trong công ty.

b.Đầu tiên ta gán một biến min=int.MaxValue(giá trị dương vô cùng).

Page 13: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 13

+Tiếp theo duyệt qua tất cả các nhân viên kiểm tra xem min>DS[i].LuongCB hay

không?

-Nếu thoả mãn min = DS[i].LuongCB

-Ngược lại,tiếp tục duyệt các nhân viên tiếp theo.

+Khi kết thúc vòng lặp kiểm tra đó ta sẽ tìm được danh sách những người có mức

lương cơ bản thấp nhất.

+Tiếp tục

c. +Khởi tạo biến dem=0,duyệt qua các phần tử của danh sách. Tại mỗi phần tử

kiểm tra xem DS[i].Thuong >= 1200000 nếu thoả mãn thì dem++.

d. Duyệt qua tất cả các phần tử trong mảng. Tại mỗi phần tử ta thực hiện in ra các

thông tin của nhân viên đó. Riêng ở phần thông tin về lương thì ta tăng thêm

5%nữa

Bài 5:Viết chương trình tạo tập tin văn bản có tên là “BANGSO.INP” có cấu trúc như

sau:

-Dòng đầu tiên ghi hai số m và n (m, n là các số nguyên dương nhập từ bàn phím)

-Trong m dòng tiếp theo mỗi dòng ghi n số nguyên ngẫu nhiên trong phạm vi từ 0

đến 1000 (các số cách nhau ít nhất một dấu cách)

Hãy thực hiện các công việc sau:

a.Hãy cho biết chỉ số các dòng có chứa số nguyên tố (giả thiết các dòng trong tập

tin văn bản được đánh số từ 0 đến m-1).

b.Xoay vòng các cột qua phải một vị trí (cột 0 sẽ qua cột 1, cột 1 qua cột 2,... cột

n-1 về cột 0).

c.Sắp xếp các phần tử tăng dần trên từng cột.

Hãy ghi các kết quả trên vào file văn bản có tên là “BANGSO.OUT”.

Bài 6: Cho mảng vuông n. Hãy tìm phần tử lớn nhất trên mỗi đường chéo song song với

đường chéo chính.

Gợi ý: Xây dựng 2 hàm tính max của đường chéo thuộc ma trận đường chéo trên có phần

tử đầu tiên thuộc cột jvà max của đường chéo thuộc ma trận đường chéo dưới có phần tử

đầu tiên thuộc hàng i:

Page 14: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 14

*Với đường chéo thuộc ma trận đường chéo trên.Khởi tạo giá trị

max=int.MinValue.Duyệt qua các phần tử của mảng tại mỗi phần tử a[i ,j] có j-i =địa chỉ

cột nếu a[i ,j]>max gán max =a[i,j].

* Với đường chéo thuộc ma trận đường chéo dưới.Khởi tạo giá trị

max=int.MinValue.Duyệt qua các phần tử của mảng tại mỗi phần tử a[i ,j] có i-j =địa chỉ

hàng nếu a[i ,j]>max gán max =a[i,j].

Tại hàm Main() thực hiện:

+Duyệt qua số cột của ma trận ,tại mỗi cột gọi hàm tính max chéo trên của cột đó va in ra

+Duyệt qua số hang của ma trận ,tại mỗi hang gọi hàm tính max chéo dưới của hàng đó

và in ra

C. Bài tập làm thêm

Bài 1: Cho mảng một chiều gồm n tọa độ điểm (giả sử hoành độ và tung độ của các

điểm là các số nguyên).

a.Hãy tìm một điểm trong mảng xa gốc tọa độ nhất.

b.Hãy tìm tọa độ hai điểm gần nhau nhất.

c.Hãy xác định tọa độ của hình chữ nhật nhỏ nhất bao hết cả n điểm trên (tọa độ

góc trên bên trái và tọa độ góc dưới bên phải của hình chữ nhật).

Ví dụ n = 5 và tọa độ 5 điểm là: (0,0); (0,3); (3,3); (4,1); (4,4).

Thì kết quả câu a là điểm (4,4), kết quả câu b là (3,3) và (4,4), kết quả câu c là

(0,4); 4(,0).

Bài 2: Viết chương trình tạo một tập tin văn bản có tên là “DAYSO.INP” có cấu trúc như

sau: -Dòng đầu tiên ghi n (n là số nguyên dương nhập từ bàn phím).

-Trong các dòng tiếp theo ghi n số nguyên ngẫu nhiên trong phạm vi từ 1 đến

10000, mỗi dòng 10 số (các số cách nhau ít nhất một dấu cách).

Hãy thực hiện các công việc sau đây:

a.Tìm giá trị lớn nhất của các số trong tập tin DAYSO.INP.

b.Đếm số lượng số chẵn, số lượng số lẻ trong tập tin DAYSO.INP.

c.Hãy đếm số lượng số nguyên tố, số chính phương, số hoàn hảo, số Amstrong

trong tập tin DAYSO.INP.

Hãy ghi kết quả của các câu a,b,c trên vào tập tin văn bản có tên là “DAYSO.OUT”.

Page 15: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 15

Bài 3: Một đơn vị quan tâm về dân số lặp một bản thống kê số lượng người sinh trong

từng năm, kể từ năm 1920 đến 1970 và lưu trữ bảng đó trong máy tính tính bằng một

mảng một chiều N[1920..1970] với N[k] có giá trị bằng số người sinh trong năm k.

Hãy viết giải thuật thực hiện:

a. In ra những năm mà không có người nào được sinh ra

b. Tính số lượng những năm mà số người sinh ra không quá 10

c. Tính số người trên 50 tuổi tính đến năm 1985.

Page 16: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 16

BÀI THỰC HÀNH 2. ĐỘ PHỨC TẠP TÍNH TOÁN * Mục tiêu

Lựa chọn thuật toán tốt để tiết kiện được thời gian, không gian nhớ tốt nhất cho

mỗi bài toán

* Yêu cầu:

A. Bài tập mẫu

Bài 1: Giả sử n ≥ 0 và x là số thực.Hãy tính giá trị của biểu thức sau đây.

Gợi ý:

Algorithms1: O(N2)

double s=1;

for (int i=1;i<=n;i++)

s=s+pow(x,i)/giaithua(i);// giaithua(i) = i!=1.2.3….i

Độ phức tạp theo cách này là O(N2), tuy nhiên chương trình không thể thực hiện

được khi n lớn; chẳng hạn n =100 - do phép tính giai thừa của n không thể thực

hiện..

Algorithms2: O(N2)

double s=1,p;

for (int i=1; i<=n;i++)

{

p=1;

for (int j=1; j<=i;j++)

p=p*x/j;

s=s+p;

}

Độ phức tạp theo cách này vẫn là là O(N2), tuy nhiên chương trình đã không

cần tính giai thừa của n.

Algorithms3: O(N) – độ phức tạp tuyến tính

double s=1,p=1;

for (int i=1;i<=n;i++)

{

Page 17: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 17

p=p*x/i;

s=s+p;

}

Lời giản mẫu

using System;

class VD

{

static void Main()

{

double s = 1, p = 1, x;

int n;

Console.Write("Nhap n="); n = int.Parse(Console.ReadLine());

Console.Write("Nhap x="); x = double.Parse(Console.ReadLine());

for (int i = 1; i <= n; i++)

{

p = p * x / i;

s = s + p;

}

Console.WriteLine("Ket qua:" + s);

Console.ReadKey();

}

}

Bài 2: Cộng hai số nguyên lớn a và b, trong đó số a có m chữ số và số b có n chữ số.

Số nguyên lớn ở đây là số có thể có đến vài trăm chữ số. Để lưu trữ các số nguyên

lớn này ta có thể dùng chuỗi (mỗi ký tự của chuỗi là một chữ số) hoặc dùng mảng một

chiều (mỗi phần tử của mảng một chiều là một chữ số).

Gợi ý :Giả sử có 2 số a,b nhập vào ở dạng xâu so1 và so2

Đầu tiên ta thực hiện chuẩn hóa 2 số như sau : kiểm tra xem xâu nào có độ dài nhỏ

hơn thì thêm 0 vào đầu xâu cho đến khi thu được 2 xâu so1 và so2 có độ dài như nhau

Thực hiện tính tổng :Khai báo một biến nhớ =0; Thực hiện duyệt qua các phần tử

của 2 xâu từ phần tử cuối đến phần tử đầu, tại mỗi phần

Page 18: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 18

Lời giản mẫu

using System;

using System.Text;

class BaiXau

{

static void chuanHoaSo(ref string so1, ref string so2)

{

StringBuilder s1 = new StringBuilder(so1);

StringBuilder s2 = new StringBuilder(so2);

if (s1.Length > s2.Length)

while (s2.Length < s1.Length)

s2.Insert(0, "0");

else

if (s2.Length > s1.Length)

while (s1.Length < s2.Length)

s1.Insert(0, "0");

so1 = s1.ToString();

so2 = s2.ToString();

}

static string tinhTong(string so1, string so2)

{

string s;

int t, a, b, nho = 0;

int n;

chuanHoaSo(ref so1, ref so2);

StringBuilder kq = new StringBuilder("");

n = so1.Length - 1;

while (n >= 0)

{

a = so1[n] - 48;

b = so2[n] - 48;

Page 19: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 19

t = a + b + nho;

s = t.ToString();

if (s.Length == 1) s = "0" + s;

nho = s[0] - 48;

kq.Insert(0, s[1]);

n = n - 1;

}

if (nho == 1) kq.Insert(0, "1");

return kq.ToString();

}

static void Main()

{

string so1, so2;

StringBuilder x = new StringBuilder("");

StringBuilder y = new StringBuilder("");

StringBuilder s = new StringBuilder("");

Console.WriteLine("\t\t BAN HAY NHAP VAO HAI SO NGUYEN");

Console.Write(" "); so1 = Console.ReadLine();

Console.WriteLine("+");

Console.Write(" "); so2 = Console.ReadLine();

x.Append('-', so1.Length > so2.Length ? so1.Length : so2.Length);

y.Append(' ', Math.Abs(so1.Length - so2.Length));

s.AppendFormat("\t\t{0}\n\n", "BAN HAY NHAP VAO HAI SO NGUYEN");

if (so1.Length < so2.Length)

s.AppendFormat(" {0}{1}\n", y.ToString(), so1);

else

s.AppendFormat(" {0}\n", so1);

s.AppendFormat("{0}\n", "+");

if (so2.Length < so1.Length)

s.AppendFormat(" {0}{1}\n", y.ToString(), so2);

Page 20: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 20

else

s.AppendFormat(" {0}\n", so2);

s.AppendFormat(" {0}\n", x.ToString());

s.AppendFormat(" {0}", tinhTong(so1, so2));

Console.Clear();

Console.WriteLine(s);

Console.ReadKey();

}

}

B. Bài tập tự giải

Bài 1: Giả sử n ≥ 0 và x là số thực.Hãy tính giá trị của biểu thức sau đây.

Gợi ý:

Ta nhận thấy (x ^ n)/n!=(x.x.x…x)/(n(n-1)(n-2)…2.1) .Để tính S, khai báo 2 biến

p và s

Duyệt qua các số tự nhiên từ 1->n ,tại mỗi số ta thực hiện tính tích của thương x

và số đó với thương x và các số trước nó (p=p*x/i) sau đó thực hiện cộng dồn các kết

quả đó lại ta được tổng S

Bài 2: Cho dãy n số nguyên a0,a1,...,an-1. Hãy chuyển k phần tử đầu tiên của dãy về cuối

dãy.

Gợi ý: Sử dụng một mảng tg chứa k phần tử và mảng tmp chứa n-k phần tử. Duyệt qua

các phần tử a[i] của mảng (i: 0->n):

+Nếu i < k tg[i]=a[i] (chuyển k phần tử đầu sang tg

+Ngược lai, tmp[j++] =a[i] ( khởi tạo j=0) chuyển các phần tử còn lại sang tmp

Sau đó thực hiện ghép 2 mảng tmp và tg với nhau

Bài 3: Cho dãy n số nguyên {ai, ở đây giả sử i=1..n} Dãy con liên tiếp là dãy mà thành

phần của nó là các thành phần liên tiếp nhau trong {a}, ta gọi tổng của dãy con là tổng tất

cả các thành phần của nó. Tìm tổng lớn nhất trong tất cả các tổng của các dãy con của

{a}. Ví dụ nếu n = 7;

4 –5 6 –4 2 3 -7

Page 21: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 21

Thì kết quả tổng là 7.

Bài 4. Giả sử n ≥1 và x là số thực. Hãy viết hàm tính giá trị của biểu thức sau đây

(với độ phức tạp tuyến tính):

Gợi ý: Xây dựng một hàm tính biểu thức mẫu với đối số là một số tự nhiên bất kỳ, giả sử

ta có hàm Mau(int n) trả giá trị 1+1/2+…+1/n

Tại hàm Main ta duyệt qua các số tự nhiên i từ 1->n.Tại mỗi số i ta tính tích của (-

1)mũ i với x mũ i và chia cho hàm Mau (với đối số là số i đó), đồng thời tiến hành cộng

dồn các kết quả đó lại được S

C. Bài tập làm them

Bài 1: Cộng hai số nguyên lớn a và b, trong đó số a có m chữ số và số b có n chữ số. Số

nguyên lớn ở đây là số có thể có đến vài trăm chữ số. Để lưu trữ các số nguyên lớn này ta

có thể dùng chuỗi (mỗi ký tự của chuỗi là một chữ số) hoặc dùng mảng một chiều (mỗi

phần tử của mảng một chiều là một chữ số). Tuy nhiên trong hai phương án này thì

phương án dùng mảng một chiều để lưu trữ sẽ có thuật toán tốt hơn.

Bài 2: Tìm số hạng thứ n của dãy Fibonasci (giải quyết khi n là một số lớn – khi đó ta

không thể sử dụng đệ quy và cũng không thể sử dụng mảng để lưu trữ).

Bài 3: Cho dãy n số nguyên a0,a1,...,an-1.Hãy tìm dãy con liên tiếp tăng dài nhất.

Bài 4: Cho dãy n số nguyên a0,a1,...,an-1.Hãy tìm đoạn con dài nhất chứa toàn số 0.

Bài 5: Cho dãy n số nguyên a0,a1,...,an-1.Hãy tìm dãy con tăng chứa nhiều số

Page 22: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 22

BÀI THỰC HÀNH 3+4. DANH SÁCH NỐI ĐƠN

* Mục tiêu

Hệ thống lại những kiến thức liên quan đến danh sách liên kết và các phép toán

trên nó

* Yêu cầu:

A. Bài tập mẫu

Bài 1: Cho một danh sách liên kết đơn l (l chứa địa chỉ nút đầu tiên của danh sách), mỗi

nút là một số nguyên dương.

a.Đếm xem trong danh sách có bao nhiêu số bằng x ?

b.Tìm phần tử dương nhỏ nhất trong danh sách.

c. Xóa phần tử x xuất hiện đầu tiên trong danh sách.

Gợi ý: Khởi tạo một danh sách toàn cục l

a.Khởi tạo một biến đếm d=0.Duyệt qua từng phần tử của danh sách, nếu phần tử

nào có giá trị là x thì tăng d=d+1;

b.Khởi tạo biến minduong=int.MaxValue .Duyệt qua từng phần tử của danh sách

nếu phần tử nào nhỏ hơn min thì gán bằng min

c.Sử dụng 2 nút p và t ,với p=l ,t trỏ vào nút phía trước nút p.Duyệt qua các phần

tử của danh sách đến khi gặp phần tử có giá trị x .Lúc này p trỏ vào phần tử cần

xóa ,ta xóa nút p bằng cách cho nút t nắm thông tin của nút sau nút p

*Chú ý:

+ Có 3 trường hợp p trỏ vào l (phần tử đầu), p trỏ vào cuối (p=null), p trỏ vào

giữa

+ Để quan sát kết quả ta nhập dữ liệu cho danh sách liên kết l

Lời giản mẫu

using System;

class Node

{

public int info;

public Node link;

}

class DSLKD

Page 23: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 23

{

static Node l = new Node(); // l dùng để chứa địa chỉ của nút đầu tiên trong danh sách

static void Nhap()

{

Console.WriteLine("Nhap vao day so nguyen");

int i = 0; l = null; Node tg; char kt;

do

{

Console.WriteLine("Nhap so nguyen thu:" + ++i);

tg = new Node();

Console.Write("Info="); tg.info = int.Parse(Console.ReadLine());

tg.link = null;

// bổ sung nút tg vào đầu danh sách l

if (l == null) l = tg;

else { tg.link = l; l = tg; }

Console.WriteLine("Ban nhap tiep C/K"); kt = char.Parse(Console.ReadLine());

} while (char.ToUpper(kt) == 'C');

}

static void Hien()

{

Console.WriteLine("Cac phan tu co trong danh sach");

Node tg = l;

while (tg != null)

{

Console.Write(tg.info + "\t");

tg = tg.link;

}

Console.WriteLine();

}

static int Dem(int x)

{

int d = 0;

Page 24: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 24

Node tg = l;

while (tg != null)

{

if (x == tg.info) d++;

tg = tg.link;

}

return d;

}

static int MinDuong()

{

if (l == null) throw new Exception("Danh sach rong");

else

{

int m = int.MaxValue;

Node tg = l;

while (tg != null)

{

if (m > tg.info && tg.info >= 0) m = tg.info;

tg = tg.link;

}

return m;

}

}

static void Xoa(int x)

{

Node p = l;

Node t = p;

while (p != null && p.info != x)

{

t = p;

p = p.link;

}

Page 25: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 25

if (p == null) Console.WriteLine("x khong ton tai trong danh sach");

else

{

if (p == l) l = l.link;

else if (p.link == null) t.link = null;

else t.link = p.link;

}

}

//Ham thuc hien cac chuc nang cua chuong trinh

static void Main()

{

Nhap();

Xoa(3);

Hien();

Console.WriteLine("Min duong nho nhat:" + MinDuong());

Console.ReadKey();

}

}

Bài 2: Hãy viết phần khai báo cấu trúc dữ liệu để mô tả một danh sách liên kết đơn l mà

mỗi phần tử chứa một số nguyên. Viết các hàm thực hiện các yêu cầu sau:

a.Tạo một danh sách l1 chỉ chứa các số chẵn và chia hết cho 3 từ danh sách l.

b.Sắp xếp các phần tử của danh sách theo chiều giảm dần.

Gợi ý: Khởi tạo 1 danh sách toàn cục l

a.Tạo một danh sách l1. Sử dụng một nút tg duyệt qua từng phần tử của danh sách

l nếu có phần tử thỏa mãn là số chẵn và chia hết cho 3 thì ta gán 1 nút tmp =tg và

tmp.link=null và đưa tmp vào danh sách l1 :

+Nếu l1 =null thì l=tmp

+Ngược lại them tmp vào danh sách l1 ( tmp.link=l1;l1=tmp)

b.Thực hiện so sánh từng nút i của danh sách với các nút j ở phía sau nó nếu giá trị

của nút i > nút j ta đổi giá trị của 2 nút cho nhau

Lời giải mẫu

using System;

Page 26: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 26

class Node

{

public int info;

public Node link;

}

class DSLKD

{

static Node l;

static void Nhap()

{

Console.WriteLine("Nhap vao day so nguyen");

int i = 1; l = null; Node tg; char kt;

do

{

Console.WriteLine("Nhap so nguyen thu:" + i);

tg = new Node();

Console.Write("Info="); tg.info = int.Parse(Console.ReadLine());

tg.link = null;

if (l == null) l = tg;

else { tg.link = l; l = tg; }

Console.WriteLine("Ban nhap tiep C/K"); kt = char.Parse(Console.ReadLine());

} while (char.ToUpper(kt) == 'C');

}

static void Hien(Node l)

{

Console.WriteLine("Cac phan tu co trong danh sach");

Node tg = l;

while (tg != null)

{

Console.Write(tg.info + "\t");

tg = tg.link;

}

Page 27: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 27

Console.WriteLine();

}

static Node Tach()

{

Node tg = l, tmp, l1 = null;

while (tg != null)

{

if (tg.info % 3 == 0 && tg.info % 2 == 0)

{

tmp = new Node();

tmp.info = tg.info;

tmp.link = null;

//bổ sung nút tmp vào đầu danh sách l1

if (l1 == null) l1 = tmp;

else tmp.link = l1;

l1= tmp;

}

tg = tg.link;

}

return l1;

}

static void SapXep()

{

Node i, j;

i = l;

while (i.link != null)

{

j = i.link;

while (j != null)

{

if (i.info > j.info)

{ int tg = i.info; i.info = j.info; j.info = tg; }

Page 28: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 28

j = j.link;

}

i = i.link;

}

}

//Ham thuc hien cac chuc nang cua chuong trinh

static void Main()

{

Nhap();

SapXep();

Hien(l);

Node l1 = Tach();

Hien(l1);

Console.ReadKey();

}

}

Bài 2: Dùng danh sách liên kết đơn cộng hai đa thức bất kỳ

R(x) =P(x)+Q(x)

Với

P(x)=a0xn+a1x

n-1+…+an

Q(x)=b0xm+b1x

m-1+…+bm

Gợi ý: Khai báo danh sách gồm 2 trường số mũ và hệ số để lưu trữ từng phần tử của đa

thức

Khai báo các danh sách toàn cục P,Q, R

Nhập vào danh sách P va Q

Xây dựng một hàm thêm 1 nút tg vào danh sách l:

+Nếu l=null thì l=tg;

+Ngược lại l!=null : Duyệt qua các phần tử của danh sách l bằng một nút p

*Nếu p.số mũ =tg.số mũ thì cộng hệ số của p với hệ số của tg đưa kết quả vào p.hệ số

*Nếu trong ds l không có số mũ = số mũ của tg ta thực hiện chèn tg vào sau nút cuối

cùng có số mũ nhỏ hơn tg ( có 3 th :chèn đầu –chèn cuối –chèn giữa)

Xây dựng hàm tính tổng như sau: khai báo R=null

Page 29: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 29

Duyệt qua các nút của danh sách chứa đa thức P và Q tại mỗi phần tử ta gọi hàm thêm

nút với tham số truyền vào là ds R và nút đang duyệt

Lời giải mẫu

using System;

class Node

{

public int hs;

public int mu;

public Node next;

}

class DaThuc

{

static Node P, Q, R; // nút P, Q, R lần lượt chứa địa chỉ nút đầu tiên của các danh sách

tương ứng

static void Nhap(out Node l)

{

Console.WriteLine("Nhap thong tin cho da thuc");

int i = 1; l = null; Node tg; char kt;

do

{

Console.WriteLine("Nhapa thong tin cho phan tu thu:" + i);

tg = new Node();

Console.Write("He so:"); tg.hs = int.Parse(Console.ReadLine());

Console.Write("Mu:"); tg.mu = int.Parse(Console.ReadLine());

tg.next = null;

Add(ref l, tg); // bổ sung nút tg vào vị trí thích hợp theo số mũ

Console.WriteLine("Ban nhap tiep C/K"); kt = char.Parse(Console.ReadLine());

} while (char.ToUpper(kt) == 'C');

}

static void Add(ref Node l, Node tg)

{

if (l == null) l = tg;

Page 30: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 30

else

{

Node p = l, t = l;

while (p != null && p.mu < tg.mu)

{

t = p;

p = p.next;

}

//Neu mu da co

if (p != null && tg.mu == p.mu)

p.hs = p.hs + tg.hs;

else

//Them vao dau

if (p == l)

{

tg.next = l;

l = tg;

}

//Them vao sau

else if (p == null && t.next == null) t.next = tg;

//Them vao giua

else

{

tg.next = p;

t.next = tg;

}

}

}

static void Hien(Node l)

{

Node tg = l;

string kq = "";

Page 31: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 31

while (tg != null)

{

if (tg.mu == 0) kq = kq + tg.hs;

else if (tg.mu == 1) kq = kq + (tg.hs > 0 ? "+" : "-") + tg.hs + "X";

else kq = kq + (tg.hs > 0 ? "+" : "-") + tg.hs + "X^" + tg.mu;

tg = tg.next;

}

Console.WriteLine(kq);

}

static void Tong()

{

R = null;

Node tmp = P, tg;

while (tmp != null)

{

tg = new Node();

tg.hs = tmp.hs;

tg.mu = tmp.mu;

tg.next = null;

Add(ref R, tg);

tmp = tmp.next;

}

tmp = Q;

while (tmp != null)

{

tg = new Node();

tg.hs = tmp.hs;

tg.mu = tmp.mu;

tg.next = null;

Add(ref R, tg);

tmp = tmp.next;

}

Page 32: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 32

}

//Ham thuc hien cac chuc nang cua chuong trinh

static void Main()

{

Console.WriteLine("Nhap thong tin da thuc P");

Nhap(out P);

Hien(P);

Console.WriteLine("Nhap thong tin da thuc Q");

Nhap(out Q);

Hien(Q);

Console.WriteLine("Tong hai da thuc");

Tong();

Hien(R);

Console.ReadKey();

}

}

B.Bài tập tự giải

Buổi 1

Bài 1: Cho một danh sách liên kết đơn l, mỗi nút là một số nguyên dương.

a.Tìm phần tử lớn nhất danh sách l.

b.Tính tổng các phần tử của danh sách l.

c.Đếm xem trong danh sách l có bao nhiêu số nguyên tố ?

d.Đếm xem trong danh sách có bao nhiêu số âm ? bao nhiêu số bằng 0 ? bao nhiêu

số dương ?

e.Đếm xem trong danh sách có bao nhiêu số bằng x ?

f.Tìm phần tử dương nhỏ nhất trong danh sách.

Gợi ý: Khai báo danh sách toàn cục l

a.Khởi tạo giá trị max=int.MinValue.Duyệt qua các phần tử của danh sách tại mỗi

phần tử so sánh với max, nếu lớn hơn max gán max bằng phần tử đó

b.Khởi tạo t=0.Duyệt qua các phần tử của danh sách và thực hiện cộng dồn các giá

trị của nó vào t

Page 33: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 33

c.Xây dựng một hàm kiểm tra một số bất kì có phải là số nguyên tố không ( giả sử

hàm KTNT(int x) .Sau đó duyệt qua các phần tử của danh sách với mỗi phần tử ta

gọi hàm KTNT( giá trị phần tử) nếu trả giá trị True ta tăng biến đếm lên 1 ( với

khởi tạo biến đếm =0)

d.Khởi 3 biến đếm âm ,dương và 0 bằng 0.Duyệt qua các phần tử của danh sách

tại mỗi phần tử tiến hành kiểm tra:

+Nếu có giá trị <0 tăng biến đếm âm lên 1

+Nếu có giá trị >0 tăng biến đếm dương lên 1

+Nếu có giá trị =0 tăng biến đếm 0 lên 1

e.Duyệt qua các phần tử của danh sách ,tại mỗi phần tử nếu có giá trị = x ta thực

hiện tăng giá trị biến đếm lên 1 (với khởi tạo biến đếm =0)

f.Khởi tạo giá trị minduong=int.MaxValue .Thực hiện duyệt qua các phần tử của

danh sách ,nếu có giá trị nhỏ hơn minduong và lớn hơn 0 thì gán min= giá trị đó

Bài 2: Cho một danh sách liên kết đơn l, mỗi nút là một số nguyên dương.

a.Xóa phần tử đầu tiên trong danh sách.

b.Xóa phần tử cuối cùng trong danh sách.

c.Xóa một phần tử được trỏ bởi con trỏ q.

d.Xóa một phần tử ngay trước phần tử được trỏ bởi con trỏ q.

e.Xóa một nút có giá trị k.

Gợi ý: Khai báo danh sách toàn cục l

a.Muốn xóa phần tử đầu ta cho phần tử đầu nắm thông tin của phần tử kế tiếp

nó(l=l.next)

b.Để xóa phần tử cuối ta cho phần tử đó trỏ vào null

c.Xóa con trỏ q:

+Nếu q trỏ vào đầu danh sách ta thực hiện xóa đầu ( l=l.next –câu a)

+Nếu q trỏ vào cuối danh sách ta thực hiện xóa cuối ( cho phần tử cuối trỏ vào

null –câu b)

+Còn lai, ta cho con trỏ t ( với t trỏ vào phần tử phía trước q) nắm bắt thong tin

của phần tử mà q nắm bắt (t.next =q.next)

d.Sử dụng 2 con trỏ t và p ( t trỏ vào phần tử trước p,p=l) duyệt qua các phần tử

của danh sách đến khi p.next =q.Sau khi thoát khỏi vòng lặp p là nút cần xóa:

+Nếu p=l thực hiện xóa đầu

Page 34: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 34

+Nếu q=null thực hiện xóa cuối

+Ngược lại,cho t nắm bắt thông tin của q

e.Sử dụng 2 con trỏ t và p( t trỏ vào phần tử trước p,p=l) duyệt qua các phần tử của

danh sách đến khi p=null hoặc giá trị của p =k.Thoát khỏi vòng lặp p trỏ vào nút

có giá trị k và t trỏ vào nút trước p

+Nếu p=l thực hiện xóa đầu

+Nếu p.next=null thực hiện xóa cuối

+Ngược lại,cho t nắm bắt thông tin của nút sau p (t.next =p.next)

Bài 3: Cho một danh sách liên kết đơn l, mỗi nút là một số nguyên dương.

a.Hãy tạo danh sách l1 chỉ chứa các số nguyên tố từ danh sách l.

b.Tách danh sách l thành 2 danh sách: một danh sách chứa toàn số chẵn, một

danh sách chứa toàn số lẻ.

Gợi ý: Khởi tạo danh sách toàn cục l

a.Xây dựng hàm kiểm tra 1 số bất kỳ có là số nguyên tố không giả sử là hàm

KTNT(int x).Khai báo danh sách l1=null và con trỏ p=l1.Duyệt qua các phần tử

của danh sách ,tại mỗi phần tử gọi hàm KTNT(phần tử đó) nếu giá trị trả về True

ta đưa nó vào danh sách l1 ( p.info=giá trị phần tử đó và p..next=null)

b.Khởi tạo 2 danh sách l1=null , l2=null và 2 con trỏ p=l1 ,q=l2 .Duyệt qua các

phần tử của danh sách l:

Nếu phần tử đó là chẵn đưa vào l1: p.info=giá trị phần tử đó và p.next=null

Nếu phần tử đó là lẻ đưa vào l2: q.info=giá trị phần tử đó và q.next=null

Bài 4: Cho một danh sách liên kết đơn l, mỗi nút là một số nguyên dương.

a.Trộn hai danh sách tăng dần thành một danh sách tăng dần.

b.Sắp xếp các phần tử của L giảm dần theo phương pháp chọn trực tiếp

Gợi ý: Khai báo danh sách toàn cục l

a.Trước tiên ta xây dựng hàm thêm 1 nút tg vào danh sách l sao cho danh sách

tăng dần:

+Nếu l=null thì l=tg ,l.next=null

+Ngược lại .Sử dụng 1 con trỏ p duyệt qua các phần tử của l cho đến khi danh

sách rỗng hoặc gặp giá trị lớn hơn giá trị nút tg .Sau vòng lặp:

*Nếu p=null

Bài 5: Viết chương trình thực hiện các yêu cầu sau:

Page 35: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 35

a.Khai báo cấu trúc dữ liệu của một danh sách liên kết đơn các tỉnh. Biết rằng

thông tin của mỗi tỉnh bao gồm: tên tỉnh, diện tích, dân số

b.Cài đặt các thao tác cơ bản cho danh sách liên kết đơn các tỉnh (thêm, sửa , xóa,

duyệt).

c.Tính tổng diện tích của tất cả các tỉnh trong danh sách liên kết

d.Tìm địa chỉ của node chứa tính có diện tích lớn nhất trong danh sách liên kết.

e.Tìm một tỉnh có dân số lớn nhất

f.Sắp xếp danh sách tăng dần theo diện tích.

Gợi ý : Khai báo danh sách toàn cục l

a.Khai báo lớp Node bao gồm 3 trường thông tin giá trị tên tỉnh (string) ,diện tích

và dan số (int) và địa chỉ nút kế tiếp

b.Các thao tác :

*Thêm :Khai báo nút tg chứa thông tin tỉnh cần thêm và tg.next=null. Sử dụng con

trỏ t và p=l ( t trỏ vào nút phía trước p) duyệt qua các phần tử của danh sách cho

đến vị trí cần thêm :

+Nếu p=null báo lỗi vị trí

+Ngược lại ,cho t nắm thông tin của tg và tg nắm thông tin của p

*Sửa: Sử dụng một nút tg =l duyệt qua các phần tử của danh sách đến khi gặp vị

trí cần sửa

+Nếu tg=null báo lỗi

+Ngược lại,gán các trường thông tin giá trị của nút tg trỏ vào bằng các giá trị mới

*Xóa: Khai báo nút tg chứa thông tin tỉnh cần thêm và tg.next=null. Sử dụng con

trỏ t và p=l ( t trỏ vào nút phía trước p) duyệt qua các phần tử của danh sách cho

đến vị trí cần xóa :

+Nếu p=null báo lỗi

+Ngược lại, xóa nút p :

Nếu p=l, thực hiện xóa nút đầu

Ngược lại, cho t nắm thông tin của nút sau p (xóa giữa và cuối)

c. Sử dụng con trỏ tg =l duyệt qua các phần tử trong danh sách và thực hiện cộng

dồn giá trị thông tin Diện tích của từng phần tử vào một biến tổng

d. Khai báo một biến max có giá trị là giá trị Diện tích của phần tử đầu tiên trong

danh sách và một biến vị trí =0. Thực hiện duyệt qua các phần tử trong danh sách

Page 36: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 36

nếu phần tử nào có giá trị diện tích lớn hơn max thì gán bằng max và tăng biến vị

trí lên 1

e. Khai báo một biến max có giá trị là giá trị Dân số của phần tử đầu tiên trong

danh sách. Thực hiện duyệt qua các phần tử trong danh sách nếu phần tử nào có

giá trị dân số lớn hơn max thì gán bằng max. Để hiện ra tỉnh có dân số max ta

duyệt qua các phần tử của danh sách nếu phần tử nào có giá trị dân số = max thì

hiện các thông tin của phần tử đó ra màn hình

f. Thực hiện duyệt qua các phần tử của danh sách tại mỗi phần tử so sánh giá trị

diện tích của phần tử đó với từng phâng tử kế tiếp nó nếu lớn hơn thực hiện đổi

chỗ toàn bộ các giá trị (tên tỉnh –dân số - diện tích)của 2 nút đó với nhau

Buổi 2

Bài 6: Cho danh sách nối đơn, có con trỏ LIST trỏ tới nút đầu tiên của danh sách này.

Hãy viết giải thuật thực hiện:

a. Cộng thêm một số A vào số đang chứa tại trường INFO của mỗi nút.

b. Đếm số lượng các nút có trong danh sách đó.

c. Đếm số lượng các nút đang chứa số dương thuộc danh sách đó (giả sử các số chứa

trong mỗi nút là số đại số khác không).

Bài 7: Hãy viết phần khai báo cấu trúc dữ liệu để mô tả một danh sách liên kết đơn mà

mỗi phần tử chứa một số nguyên. Viết các hàm thực hiện các yêu cầu sau:

a.Đếm các số nguyên tố của danh sách

b.Tạo một danh sách l1 chỉ chứa các số chẵn và chia hết cho 3 từ danh sách l.

c.Sắp xếp các phần tử của danh sách theo chiều giảm dần.

Gợi ý:

Trước tiên ta khai báo 1 lớp node gồm trường lưu trữ thông tin ,trường chứa địa

chỉ và nhập một danh sách mới:

class node

{

public int x;

public node link;

}

Page 37: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 37

Sau đó với mỗi yêu cầu ta thực hiện như sau:

a. Ta phải xây dựng một hàm kiểm tra xem một số bất kỳ nào đó có phải là số

nguyên tố không giả sử hàm đó là bool kiemtraNT(int n). Sau đó chúng ta duyệt

qua tất cả các phần tử của danh sách, với mỗi phần tử tg.info chúng ta gọi hàm

kiemtraNT ra thực hiện nếu kiemtraNT (tg.info) trả về giá trị là True nghĩa là

phần tử tg.info chúng ta đang kiểm tra là số nguyên tố ta tăng biến đếm khởi tạo

bằng 0 lên 1. Số nguyên tố bằng giá trị của biến đếm đó.

b. Ta khai báo mới danh sách mới l1=null,một node c=null và node tg=l Duyệt các

phần tử trong danh sách tg cho đến khi tg=null,kiểm tra nếu phần tử đó chia hết

cho 3 và chia hết cho 2(số chia hết cho 2 là số chẵn) thì ta thêm phần tử đó vào

l1 bằng cách:khai báo 1 node tmp mới để chứa phần tử đang xét,rồi kiểm tra,nếu

l1=null thì ta gán l1=tmp,ngược lại c.link = tg;c = tmp;

c. Khai báo node i,j,gán i=l,ta sử dụng 2 vòng lặp while. Trong khi i.link!=null ta

gán j=i.link,rồi duyệt j cho đến khi j=null. Kiểm tra giá trị của phần tử i.info nếu

lớn hơn j.info thì ta hoán đổi giá trị của hai phần tử này qua một biến trung gian

nào đó. Kết thúc công việc đó ta được 1 danh sách giảm dần.

Bài 8: Hãy khai báo kiểu danh sách liên kết đơn có tên LIST mà mỗi phần tử chứa các

thông tin về một sinh viên bao gồm một số nguyên dương chỉ mã số sinh viên và một

chuỗi ký tự cho biết họ và tên của sinh viên.

Thực hiện các công việc sau:

a.Xây dựng hàm sắp xếp danh sách sinh viên theo thứ tự tăng dần của mã số sinh

viên.

b.Xây dựng hàm thêm một sinh viên mới vào danh sách(đã có thứ tự) sao cho vẫn

bảo đảm thứ tự tăng dần của mã số.

Gợi ý: Đầu tiên ta khai báo cấu trúc sinhvien gồm họ tên và mã sinh viên,sau đó khai 1

lớp node gồm thành phần dữ liệu info kiểu sinhvien,thành phần lưu trữ địa chỉ phần tử kế

tiếp trong danh sách.

a.Khai báo 2 node mới i=l(l là danh sách toàn cục)và j Trong khi phần tử tiếp theo

của i chưa bằng null thì ta sẽ gán j=i.next(nghĩa là j sẽ chạy trước i,j bằng phần tử kế

tiếp của i),trong khi j khác null thì kiểm tra nếu giá trị của i.masv.info<j.masv.info

thì đổi chỗ i.masv.info và j.masv.info với nhau qua 1 biến trung gian nào đó.

Page 38: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 38

b. Khai báo 2 node mới p=l,t=l. Trong khi p.masv.info<mã sinh viên mới nhập vào

và p chưa rỗng thì gán t=p. Khởi tạo 1 node tg mới gán tg.masv.info=mã sinh viên

mới nhập vào. Kiểm tra nếu l rỗng gán l=tg luôn,nếu p=l thì thêm vào đầu gán phần

tử tiếp theo của tg:tg.next=l;l=tg.,nếu p rỗng thì them vào sau gán t.next=tg,ngược

lại tất cả điều trên ta thêm vào giữa.

Bài 9: Cho một danh sách liên kết, mỗi nút chứa một số nguyên.

a.Thêm một phần tử có giá trị x vào đầu danh sách

b.Chỉ giữ lại một giá trị trong số các giá trị giống nhau.

c.Kiểm tra xem danh sách có được sắp xếp tăng dần hay không?

d.Đảo ngược danh sách.

e.Sắp xếp các số chẵn trong danh sách theo thứ tự tăng, sắp xếp các số lẻ

theo thứ tự giảm dần, các số 0 giữ nguyên vị trí.

Gợi ý: Trước tiên ta khai báo 1 lớp node gồm trường lưu trữ thông tin ,trường chứa địa

chỉ và nhập một danh sách mới, sau đó với mỗi yêu cầu ta thực hiện như sau:

a.Kiểm tra danh sách nếu rỗng thì ta gán l=tg nghĩa là đó là phần tử đầu tiên của

danh sách,ngược lại ta cho địa chỉ tiếp theo của tg nắm bắt lấy l(tg.next=l)và gán

l=tg.

b.Đầu tiên kiểm tra xem danh sách nếu rỗng(l=null) thì in ra thông báo danh sách

rỗng. Ngược lại khởi tạo node i=l,j,ta sử dụng 2 vòng lặp. Thực hiện các công việc

sau cho đến khi j=l:gán j=i.next,trong khi j!=l thì kiểm tra nếu i.info=j.info thì xóa

j đi.

c. Kiểm tra xem danh sách nếu rỗng(l=null) thì in ra thông báo danh sách rỗng.

Ngược lại khai báo node tg=l,kiểm tra xem phần tử bên phải của tg không bằng

l(tg.next!=l) và giá trị của tg lớn hơn giá trị của phần tử tiếp theo(tg.next.info) thì

gán ok=false(ok là biến theo dõi tính đúng hay sai) rồi thoát khỏi vòng lặp. Nếu

ok=true thì dãy tăng dần ngược lại là dãy k tăng dần.

d. Đầu tiên ta đếm xem danh sách đó có bao nhiêu phần tử. Sau đó ta duyệt ngược

danh sách đó cho 1 vòng lặp lồng trong 1 vòng lặp khác. Vòng lặp bên trong chạy

sau vòng lặp ngoài 1 phần tử ta hoán vị 2 phần tử kế nhau cho đến khi nào hết

danh sách thì thôi.

e.Khởi tạo thêm 2 node l1,l2 rỗng. duyệt hết danh sách nếu phần tử chia hết cho 2

thì them vào danh sách l1,không chia hết them vào danh sách l2,bằng 0 thì giữ

Page 39: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 39

nguyên. Sau đó sắp xếp tăng dần cho l1,giảm dần cho l2. Cuối cùng ta chèn l1,l2

vào l.

C. Bài tập làm thêm

Bài 1:.Viết chương trình thực hiện các yêu cầu sau:

a.Khai báo cấu trúc dữ liệu của một danh sách liên kết đơn để lưu tọa độ các đỉnh

của một đa giác lồi trong mặt phẳng OXY.

b.Tính chu vi của đa giác.

c.Tính diện tích của đa giác.

Gợi ý: Tạo một lớp node gồm 2 trường info lưu trữ thông tin tung độ, hoành độ và 1 con

trỏ chỉ đến cấu trúc node để lưu tọa độ các đỉnh của một đa giác lồi. Sau đó thực hiện

việc nhập danh sách với các tọa độ của các đỉnh đa giác đó.

a. Tính độ dài vectơ các cạnh của đa giác. Sau đó áp dụng công thức tính chu vi

đa giác bằng tổng các cạnh của đa giác đó.

b. Diện tích của 1 đa giác lồi áp dụng công thức s=1/2(x1.y2-x2.y1+x2y3-

x3y2+….+(xn-1)yn-xn(yn-1)+xny1-x1yn).

Ghi chú: Đa giác lồi (Convex polygon): toàn bộ đa giác nằm về một phía của đường

thẳng chứa cạnh bất kỳ nào của đa giác.

Bài 2: Cho một danh sách nối đơn có con trỏ P trỏ tới nút đầu tiên của nó. Biết rằng danh

sách này không rỗng. Hãy viết giải thuật:

a. Bổ sung một nút mới vào sau nút có địa chỉ T (hay : con trỏ T trỏ tới nó) đang có

trong danh dách đó.

b. Bổ sung một nút mới vào trước nút trỏ bởi T đang có trong danh sách đó.

Biết rằng phần thông tin dành cho nút mới đang chứa trong ô có địa chỉ là X.

c. Bổ sung một nút vào vị trí thứ k của danh sách.

d. Tìm xem trong danh sách có nút mang giá trị là Y hay không? Nếu thấy thì trả ra

địa chỉ của nút đó, ngược lại trả ra giá trị null.

Bài 3: Cho một danh sách nối đơn có con trỏ Q trỏ tới nút đầu tiên của danh sách. Biết

rằng danh sáhc này không rỗng. Hãy viết giải thuật:

a. Loại bỏ nút đầu tiên của danh sách.

b. loại bỏ nút trỏ bởi T đang có trong danh sách. Biết rằng T không phải là đại chỉ nút

đầu tiên và cũng không phải là đại chỉ nút cuối cùng.

c. Loại bỏ nút thứ k của danh sách.

Page 40: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 40

Bài 4: Cho ba danh sách nối đơn, lần lượt có nút đầu tiên được trỏ bởi L1, L2, L3. Hãy

viết giải thuật:

a. Ghép danh sách L2 vào sau danh sách L1 và cho L trỏ tới danh sách tổng hợp.

b. Ghép danh sách L3 vào trước L2 và L1 vào sau L2 và cho L trỏ tới danh sách tổng

hợp.

Giả sử rằng cả ba danh sách này đều không rỗng.

Bài 5: Cho một danh sách nối đơn có con trỏ P trỏ tới nút đầu tiên của nó, danh sách này

không rỗng. Cho con tỏ Q trỏ tới một nút đang có trong danh sách. Hãy viết giải thuật

tách danh sách này thành hai danh sách con. Danh sách thứ nhất sẽ được trỏ bởi P.

Danh sách thứ hai sẽ trỏ bởi Q (nút trỏ bởi Q sẽ là nút đầu tiên của danh sách thứ hai).

Bài 6: Cho danh sách nối đơn, không rỗng, có con trỏ LIST trỏ tới nút đầu tiên. Biết rằng

trường INFO của mỗi nút đều chứa một số dương. Hãy viết giải thuật:

Tính giá trị trung bình của các số chứa trong danh sách.

Bài 7: Viết khai báo và các thủ tục cài đặt danh sách bằng mảng. Dùng các thủ tục này để

viết:

a. Thủ tục nhận một dãy các số nguyên nhập từ bàn phớm, lưu trữ nó trong danh

sách theo thứ tự nhập vào.

b. Thủ tục nhận một dãy các số nguyên nhập từ bàn phím, lưu trữ nó trong danh sách

theo thứ tự ngược với thứ tự nhập vào.

c. Viết thủ tục in ra màn hình các phần tử trong danh sách theo thứ tự của nó trong

danh sách.

Bài 8: Viết thủ tục thêm một phần tử trong danh sách liên kết đã có thứ tự sao cho ta vẫn

có một danh sách có thứ tự.

Bài 9: Viết thủ tục nhận vào từ bàn phím một dãy số nguyên, lưu trữ nó trong một danh

sách có thứ tự không giảm, theo cách sau: với mỗi phần tử được nhập vào thủ tục phải

tìm vị trí thích hợp để xen nó vào danh sách cho đúng thứ tự. Viết thủ tục trên cho trường

hợp danh sách được cài đặt bằng mảng và cài đặt bằng con trỏ.

Bài 10: Viết thủ tục loại bỏ các phần tử trùng nhau (giữ lại duy nhất 1 phần tử) trong một

danh sách có thứ tự không giảm, trong hai trường hợp: cài đặt bằng mảng và cài đặt bằng

con trỏ.

Page 41: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 41

Bài 11: Viết thủ tục nhận vào từ bàn phím một dãy số nguyên, lưu trữ nó trong một danh

sách có thứ tự tăng không có hai phần tử trùng nhau, theo cách sau: với mỗi phần tử được

nhập vào thủ tục phải tìm kiếm xem nó có trong danh sách chưa, nếu chưa có thì xen nó

vào danh sách cho đúng thứ tự. Viết thủ tục trên cho trường hợp danh sách được cài đặt

bằng mảng và cài đặt bằng con trỏ.

Bài 12: Viết thủ tục trộn hai danh sách liên kết chứa các số nguyên theo thứ tự tăng để

được một danh sách cũng có thứ tự tăng.

Bài 13: Viết thủ tục xóa khỏi danh sách lưu trữ các số nguyên các phần tử là số nguyên

lẻ, cũng trong hai trường hợp: cài đặt bằng mảng và bằng con trỏ.

Bài 14: Viết thủ tục tách một danh sách chứa các số nguyên thành hai danh sách: một

danh sách gồm các số chẳn còn cái kia chứa các số lẻ.

Bài 15: Cho đa thức P(x)= anxn+ an-1xn-1+... + a1x + a0 được lưu trữ trong máy tính

dưới dạng một danh sách liên kết mà mỗi phần tử của danh sách là một record có ba

trường lưu giữ hệ số, số mũ, và trưòng NEXT trỏ đến phần tử kế tiếp. Chú ý cách lưu trữ

đảm bảo thứ tự giảm dần theo số mũ của từng hạng tử của đa thức.

Ví dụ: đa thức 5x4 - x + 3 được lưu trữ trong danh sách có 3 phần tử như sau:

a. Hãy viết chương trình thực hiện được sự lưu trữ này.

b. Dựa vào sự cài đặt ở trên, viết thủ tục thưc hiện việc cộng hai đa thức.

c. Viết thủ tục lấy đạo hàm của đa thức.

Page 42: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 42

BÀI THỰC HÀNH 5. NGĂN XẾP - STACK

* Mục tiêu

- Hệ thống lại những kiến thức liên quan đế Stack và các phép toán trên nó

- Cài đặt được các phép toán trên Stack sử dụng mảng và danh sách liên kết

* Yêu cầu:

A. Bài tập mẫu

Bài 1: Cài đặt các phép toán trên Stack bằng mảng gồm các phép toán:

- Kiểm tra Stack rỗng không IsEmpty()

- Kiểm tra Stack có đầy không IsFull()

- Thêm một phần tử vào Stack Push(x)

- Loại một phần tử khỏi Stack Pop()

- Khởi tạo Stack Init()

Gợi ý: Trước tiên khai báo mảng s và biến top toàn cục.

-Stack rỗng khi top=-1(top là biến theo dõi đỉnh của stack), vậy ta chỉ cần trả về giá trị

của top=-1.

-Stack đầy khi top bằng hoặc lớn hơn độ dài của stack, ta trả về giá trị của

top>=s.length.

-Đầu tiên ta kiểm tra xem stack đã đầy chưa, nếu đầy rồi ta in ra 1 thông báo không

thể thêm phần tử vào stack nữa,ngược lại gán s[++top]=x.

-Kiểm tra xem stack có rỗng không? Nếu rỗng không có gì lấy cả thì in ra 1 thông báo

ngoại lệ, ngược lại ta trả về giá tri s[top--].

-Khởi tạo stack bằng cách tạo 1 mảng mới với độ dài tùy ý và gán top=-1;

Lời giải mẫu

using System;

class Stack

{

public int top;

public int[] s;

public bool isEmpty()

{

return top == -1;

Page 43: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 43

}

public bool isFull()

{

return top >= s.Length;

}

public void Init()

{

s = new int[20];

top = -1;

}

public void Push(int x)

{

if (!isFull()) s[++top] = x;

else Console.Write("Stack tran");

}

public int Pop()

{

if (isEmpty()) throw new Exception("Tack Empty");

else return s[top--];

}

}

Bài 2: Chuyển một số từ hệ đếm thập phân sang hệ đếm thập lục phân

Gợi ý: Đầu tiên ta phải xây dựng 1 lớp stack gồm các hàm kiểm tra rỗng, kiểm tra đầy,

thêm 1 phần tử, lấy ra 1 phần tử, khởi tạo stack.

-Tại hàm Main ta thực hiện các công việc sau:

1. Khởi tao 1 stack t mới.

2. Nhập số cần chuyển đổi n.

3. Khai báo string st = "0123456789ABCDEF";

4. Trong khi n!=0 ta dùng hàm push(hàm thêm 1 phần tử vào stack) để thêm giá trị

của phép tính n%16 vào stack ,sau đó gán n=n/16;

5. In ra kết quả bằng cách thực hiện:trong khi stack chưa rỗng thì dùng hàm pop(hàm

lấy 1 phần tử trong stack) để lấy các giá trị có trong stack ra.

Page 44: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 44

Lời giải mẫu

using System;

class Stack

{

public int top;

public int[] s;

public bool isEmpty()

{

return top == -1;

}

public bool isFull()

{

return top >= s.Length;

}

public void Init()

{

s = new int[20];

top = -1;

}

public void Push(int x)

{

if (!isFull()) s[++top] = x;

else Console.Write("Stack tran");

}

public int Pop()

{

if (isEmpty()) throw new Exception("Tack Empty");

else return s[top--];

}

}

class App

{

Page 45: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 45

static void Main()

{

Stack t = new Stack();

int n;

Console.Write("Nhap vao so can doi:");

n = int.Parse(Console.ReadLine());

t.Init();

string st = "0123456789ABCDEF";

while (n != 0)

{

t.Push((int)st[n % 16]);

n = n / 16;

}

Console.Write("Ket qua chuyen sang he thap luc phan:");

while (!t.isEmpty())

{

Console.Write("{0}", (char)t.Pop());

}

Console.ReadKey();

}

}

Bài 3: Xây dựng chương trình nhập vào một biểu thức bất kỳ sau đó tính giá trị của

chúng

Gợi ý: Đầu tiên ta phải xây dựng 1 lớp stack gồm các hàm kiểm tra rỗng. Kiểm tra đầy,

thêm 1 phần tử, lấy ra 1 phần tử, khởi tạo stack, khai báo mảng s và biến top toàn cục.

-Sau đó là lớp chương trình, ta tạo 1 hàm kiểm tra độ ưu tiên của toán tử với phép cộng

và trừ là 1, phép nhân và chia là 2.

-Xây dựng 1 hàm postfix để thêm hoặc lấy ra 1 phần tử trong stack.

+Trước hết, ta tạo 1 stack t mới, khởi tạo 1 xâu E1 rỗng, duyệt từ đầu cho đến hết xâu E

(xâu được nhập vào từ bàn phím) kiểm tra E[i] nếu là số thì thêm vào bên phải xâu E1,

nếu là “(“ thì đẩy vào stack,nếu “)” thì sẽ lấy các phần tử trong stack thêm vào bên phải

E1 cho đến khi gặp “(“ thì mới thôi lấy ra, nếu gặp toán tử thì gọi hàm kiểm tra độ ưu tiên

Page 46: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 46

để so sánh độ ưu tiên giữa toán tử đang xét với toán tử trong stack, nếu độ ưu tiên của

toán tử đang xét nhỏ hơn toán tử ở đỉnh stack thì lấy toán tử đầu stack thêm vào E1 đồng

thời đẩy toán tử đang xét vào stack.

+ Sau đó trong khi stack chưa rỗng thì lấy hết các phần tử trong đó ra và thêm vào E1.

+ Tiếp đến là công viêc tính toán:đầu tiên tạo 1 satck mới, khai báo 2 biến lưu trư 2 toán

hạng lấy ra, 1 biến lưu trữ kết quả kiểu số thực. Duyệt từ đầu cho hết E1 nếu là số thì đẩy

vào satck,ngược lại thì lấy hai toán hạng đầu satck ra rồi thực hiện phép toán tương ứng,

được kết quả ta lại đẩy vào stack. Cuối cùng ta trả giá giá trị kết quả là phần tử lấy ra cuối

cùng của stack.

Lời giải mẫu:

using System;

using System.Collections.Generic;

using System.Text;

public class Stack

{

public int top;

public object[] s;

public bool isEmpty()

{

return top == -1;

}

public bool isFull()

{

return top >= s.Length;

}

public void Init()

{

s = new object[20];

top = -1;

}

public object Top()

{

Page 47: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 47

if (isEmpty()) throw new Exception("Tack Empty");

else return s[top];

}

public void Push(object x)

{

if (!isFull()) s[++top] = x;

else Console.Write("Stack tran");

}

public object Pop()

{

if (isEmpty()) throw new Exception("Tack Empty");

else return s[top--];

}

}

public class TBT

{

static int Pri(char k)

{

int kq = 0;

switch (k)

{

case '+': kq = 1; break;

case '-': kq = 1; break;

case '*': kq = 2; break;

case '/': kq = 2; break;

}

return kq;

}

static string PostFix(string E)

{

Stack t = new Stack(); t.Init();

Page 48: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 48

string E1 = "";

for (int i = 0; i < E.Length; ++i)

if (E[i] >= '0' && E[i] <= '9')

E1 = E1 + E[i].ToString();

else if (E[i] == '(') t.Push('(');

else if (E[i] == ')')

{

while ((char)t.Top() != '(')

{

E1 = E1 + t.Pop();

}

t.Pop();

}

else

{ while (!t.isEmpty() && Pri((char)t.Top()) > Pri(E[i]))

{

E1 = E1 + t.Pop();

}

t.Push(E[i]);

}

while (!t.isEmpty()) E1 = E1 + t.Pop();

return E1;

}

static double Calculator(string E)

{

double y, x, z;

Stack t = new Stack(); t.Init();

for (int i = 0; i < E.Length; ++i)

if (E[i] >= '0' && E[i] <= '9') t.Push((double)E[i] - 48);

else switch (E[i])

{

Page 49: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 49

case '+':

y = (double)t.Pop();

x = (double)t.Pop();

z = x + y;

t.Push((double)z);

break;

case '-':

y = (double)t.Pop();

x = (double)t.Pop();

z = x + y;

t.Push((double)z);

break;

case '*':

y = (double)t.Pop();

x = (double)t.Pop();

z = x + y;

t.Push((double)z);

break;

case '/':

y = (double)t.Pop();

x = (double)t.Pop();

z = x + y;

t.Push((double)z);

break;

}

return (double)t.Pop();

}

//Ham thuc hien cac chuc nang cua chuong trinh

static void Main()

{

string E = "5+(5+3*2)+3+6/2";

string E1 = PostFix(E);

Page 50: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 50

Console.WriteLine(Calculator(E1));

Console.ReadKey();

}

}

A. Bài tự làm

Bài 1: Cài đặt các phép toán trên Stack bằng danh sách liên kết gồm các phép toán:

- Kiểm tra Stack rỗng không IsEmpty()

- Thêm một phần tử vào Stack Push(x)

- Loại một phần tử khỏi Stack Pop()

- Khởi tạo Stack Init()

Gợi ý: Trước tiên khai báo 1 lớp node gồm 1 trường info lưu trữ thông tin của phần tử,1

node link lưu trữ địa chỉ kế tiếp trong danh sách. Sau đó trong lớp satck khai báo 1 node s

toàn cục.

-Stack rỗng khi s==null(s là theo dõi phần tử đầu tiên của danh sách),vậy ta chỉ cần

trả về giá trị của s==null.

-Khởi tạo 1 node tg mới chứa phần tử cần thêm vào stack,gán giá trị

tg.info=x;tg.link=null(địa chỉ kế tiếp trong danh sách tg là null),kiểm tra xem danh

sách có rỗng không? Nếu rỗng thì gán s=tg;ngược lại tg.link=s;s=tg.

-Kiểm tra xem stack có rỗng không? Nếu rỗng không có gì lấy cả thì in ra 1 thông báo

stack rỗng,ngược lại ta gán int kq=s.x;s=s.link sau đó trả ra giá trị kết quả.

-Khởi tạo stack bằng cách tạo 1 danh sách rỗng s=null.

Bài 2: Dùng Stack để chuyển một số nguyên bất kỳ sang hệ đếm thập lục phân, nhị phân

Gợi ý: Đầu tiên ta phải xây dựng 1 lớp stack gồm các hàm kiểm tra rỗng.kiểm tra

đầy,thêm 1 phần tử,lấy ra 1 phần tử.

-Tại hàm Main ta thực hiện các công việc sau:

1. 1.Khởi tao 1 stack t mới.

2. Nhập số cần chuyển đổi n,nhập hệ cần đổi k.

3. Khai báo string st = "0123456789ABCDEF";

4. Trong khi n!=0 ta dùng hàm push(hàm thêm 1 phần tử vào stack) để thêm giá trị

của phép tính n% k vào stack ,sau đó gán n=n/k;

5. In ra kết quả bằng cách thực hiện:trong khi stack chưa rỗng thì dùng hàm pop(hàm

lấy 1 phần tử trong stack) để lấy các giá trị có trong stack ra.

Page 51: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 51

Bài 3: Dùng Stack kiểm tra tính hợp lệ của một dãy các dấu ( và ) trong một biểu thức

Ví dụ 1: (()()()()) là hợp lệ

Ví dụ 1: (())()()) là không hợp lệ

Gợi ý: Đầu tiên ta phải xây dựng 1 lớp stack gồm các hàm kiểm tra rỗng.kiểm tra

đầy,thêm 1 phần tử,lấy ra 1 phần tử,khởi tạo stack. Khai báo mảng s và biến top toàn cục.

-Gọi hàm khởi tạo 1 stack t mới init(),duyệt từ 0 đến s.length

+kiểm tra nếu s[i]=’(‘ thì gọi hàm push(s[i])(ham thêm 1 phần tử vào stack),ngược

lại kiểm tra nếu stack rỗng thì gán false (kt 1 biến kiểm tra nào đó và được khởi

tạo là true )và thoát khỏi vòng lặp,ngược lại gọi hàm thêm 1 phần tử vào pop().

+Kiểm tra,nếu kt=false in ra không hợp lệ,ngược lại kiểm tra nếu stack rỗng thì in

ra man hình hợp lệ,ngược lại là không hợp lệ.

Bài 4: Tính giá trị của một biểu thức dạng chuỗi ký tự bao gồm các chữ số và các phép

toán +,-,*,/ , % và dấu đóng mở ngoặc đơn.

Ví dụ: (( 2 + 3 )*2) – 4/2 = 12

Gợi ý: Đầu tiên ta phải xây dựng 1 lớp stack gồm các hàm kiểm tra rỗng.kiểm tra

đầy,thêm 1 phần tử,lấy ra 1 phần tử,khởi tạo stack,khai báo mảng s và biến top toàn cục.

-Sau đó là lớp chương trình,ta tạo 1 hàm kiểm tra độ ưu tiên của toán tử với phép cộng và

trừ là 1,phép nhân và chia là 2.

-Xây dựng 1 hàm postfix để thêm hoặc lấy ra 1 phần tử trong stack.

+Trước hết,ta tạo 1 stack t mới,khởi tạo 1 xâu E1 rỗng,duyệt từ đầu cho đến hết xâu

E(xâu được nhập vào từ bàn phím) kiểm tra E[i] nếu là số thì thêm vào bên phải xâu

E1,nếu là “(“ thì đẩy vào stack,nếu “)” thì sẽ lấy các phần tử trong stack thêm vào bên

phải E1 cho đến khi gặp “(“ thì mới thôi lấy ra,nếu gặp toán tử thì gọi hàm kiểm tra độ ưu

tiên để so sánh độ ưu tiên giữa toán tử đang xét với toán tử trong stack,nếu độ ưu tiên của

toán tử đang xét nhỏ hơn toán tử ở đỉnh stack thì lấy toán tử đầu stack thêm vào E1 đồng

thời đẩy toán tử đang xét vào stack.

+Sau đó trong khi stack chưa rỗng thì lấy hết các phần tử trong đó ra và thêm vào E1.

+Tiếp đến là công viêc tính toán:đầu tiên tạo 1 satck mới,khai báo 2 biến,2 biến lưu trư 2

toán hạng lấy ra,1 biến lưu trữ kết quả kiểu số thực.Duyệt từ đầu cho hết E1 nếu là số thì

đẩy vào satck,ngược lại thì lấy hai toán hạng đầu satck ra rồi thực hiện phép toán tương

ứng,được kết quả ta lại đẩy vào stack. Cuối cùng ta trả giá giá trị kết quả là phần tử lấy ra

cuối cùng của stack.

Page 52: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 52

Bài 5: Hãy cho biết nội dung của Stack sau mỗi thao tác trong dãy :

Ví dụ cho dãy: EAS*Y**QUE***ST***I*ON

Với một chữ cái tượng trưng cho thao tác thêm chữ cái tương ứng vào stack, dấu * tượng

trưng cho thao tác lấy nội dung một phần tử trong stack in lên màn hình.

Hãy cho biết sau khi hoàn tất chuỗi thao tác, những gì xuất hiện trên màn hình ?

Gợi ý: Đầu tiên ta phải xây dựng 1 lớp stack gồm các hàm kiểm tra rỗng.kiểm tra

đầy,thêm 1 phần tử,lấy ra 1 phần tử,khởi tạo stack,khai báo mảng s và biến top toàn cục.

-Duyệt hết dãy được nhập vào, kiểm tra nếu là chữ cái thì đẩy vào stack, còn là dấu “*”

thì lấy 1 chữ cái đầu stack ra rồi thêm vào bên phải 1 xâu mới. Kết quả là 1 dãy chữ

cái(xâu mới).

Page 53: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 53

BÀI THỰC HÀNH 6. HÀNG ĐỢI - QUEUE

* Mục tiêu

Hệ thống lại những kiến thức liên quan đến hàng đợi Queue và các phép toán trên

* Yêu cầu:

A. Bài tập mẫu

Cài đặt các phép toán trên Queue bằng danh sách gồm các phép toán:

- EnQueue(O): thêm một đối tượng O - Object vào đuôi hàng đợi;

- DeQueue(): lấy ra một đối tượng ở đầu hàng đợi và trả về trị của nó, nếu hàng đợi

rỗng sẽ gặp lỗi;

- EmptyQueue(): kiểm tra xem hàng đợi có rỗng hay không;

- Front(): Trả về trị của phần tử ở đầu hàng đợi mà không loại nó khỏi hàng đợi, nếu

hàng đợi rỗng sẽ gặp lỗi.

Gợi ý: Khai báo con trỏ first trỏ vào phần tử đầu tiên của Queue

- EmptyQueue(): Hàng đợi rỗng khi con trỏ first bằng null

- EnQueue(O): Thêm một đối tượng O vào đuôi hàng đợi, ta khởi tạo một nút tg có chứa

giá của đối tượng O, cho tg chứa thông tin của con trỏ first và gán first bằng tg

- DeQueue():Thực hiện kiểm tra hàng đợi :

+Nếu hàng đợi rỗng báo lỗi

+Ngược lại,kiểm tra :

*Nếu hàng đợi có 1 phần tử (first.next =null) đối tượng lấy ra có giá trị bằng first và first

bằng null

*Ngược lại, dùng một con trỏ c duyệt qua các phần tử của Queue ( khởi tạo c=first duyệt

đến c.next.next=null) ,đối tượng lấy ra có giá trị bằng phần tử duyệt đến sau cùng của

Queue (c.next) và xóa phần tử đó ra khỏi Queue (c.next=null)

-Front():Kiểm tra hàng đợi

+Nếu hàng đợi rỗng báo lỗi

+Ngược lại , kiểm tra :

*Nếu hàng đợi có 1 phần tử (first.next =null) phần tử đầu hàng đợi có giá trị bằng first

Page 54: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 54

* Ngược lại, dùng một con trỏ c duyệt qua các phần tử của Queue ( khởi tạo c=first duyệt

đến c.next.next=null) ,phần tử đầu hàn đợi có giá trị bằng phần tử duyệt đến sau cùng của

Queue (c.next)

Lời giải mẫu

using System;

class Node

{

public int value;

public Node next;

}

class Queue

{

public Node first;

public bool EmptyQueue()

{

return first == null;

}

public void EnQueue(int x)

{

Node tg = new Node();

tg.value = x;

tg.next = first;

first = tg;

}

public int DeQueue()

{

int value;

if (first == null) throw new Exception("Queue empty");

else

{

if (first.next == null)

{

Page 55: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 55

value = first.value;

first = null;

}

else

{

Node c = first;

while (c.next.next != null) c = c.next;

value = c.next.value;

c.next = null;

}

return value;

}

}

public void Cleanup()

{

first = null;

}

public int Front()

{

int value;

if (first == null) throw new Exception("Queue empty");

{

if (first.next == null)

{

value = first.value;

}

else

{

Node c = first;

while (c.next.next != null) c = c.next;

value = c.next.value;

}

Page 56: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 56

return value;

}

}

}

class App

{

static void Main()

{

Queue t = new Queue();

int x; char kt;

do

{

Console.Write("Nhap mot so nguyen:");

x = int.Parse(Console.ReadLine());

t.EnQueue(x);

Console.Write("Ban co nhap tiep C/K"); kt = char.Parse(Console.ReadLine());

} while (char.ToUpper(kt) == 'C');

Console.WriteLine("Cac so nguyen da nhap");

while (!t.EmptyQueue())

Console.Write(t.DeQueue() + "\t");

Console.WriteLine();

Console.ReadKey();

}

}

B. Bài tự làm

Bài 1: Cài đặt các phép toán trên Queue bằng mảng gồm các phép toán:

- EnQueue(O): thêm một đối tượng O vào đuôi hàng đợi;

- DeQueue(): lấy ra một đối tượng ở đầu hàng đợi và trả về trị của nó, nếu hàng đợi

rỗng sẽ gặp lỗi;

- EmptyQueue(): kiểm tra xem hàng đợi có rỗng hay không;

- Front(): Trả về trị của phần tử ở đầu hàng đợi mà không loại nó khỏi hàng đợi, nếu

hàng đợi rỗng sẽ gặp lỗi.

Page 57: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 57

Bài 2: Cài đặt các phép toán trên Queue bằng danh sách liên kết gồm các phép toán:

- EnQueue(O): thêm một đối tượng O vào đuôi hàng đợi;

- DeQueue(): lấy ra một đối tượng ở đầu hàng đợi và trả về trị của nó, nếu hàng đợi

rỗng sẽ gặp lỗi;

- EmptyQueue(): kiểm tra xem hàng đợi có rỗng hay không;

- Front(): Trả về trị của phần tử ở đầu hàng đợi mà không loại nó khỏi hàng đợi, nếu

hàng đợi rỗng sẽ gặp lỗi.

Gợi ý: Khai báo con trỏ first trỏ vào phần tử đầu tiên của Queue

-EmptyQueue():Hàng đợi rỗng khi con trỏ first bằng null

-EnQueue(O):Thêm một đối tượng O vào đuôi hàng đợi, ta khởi tạo một nút tg có chứa

giá của đối tượng O, cho tg nắm thông tin của con trỏ first và gán first bằng tg

-DeQueue():Thực hiện kiểm tra hàng đợi :

+Nếu hàng đợi rỗng báo lỗi

+Ngược lại,kiểm tra :

*Nếu hàng đợi có 1 phần tử (first.next =null) đối tượng lấy ra có giá trị bằng first và first

bằng null

*Ngược lại, dùng một con trỏ c duyệt qua các phần tử của Queue ( khởi tạo c=first duyệt

đến c.next.next=null) ,đối tượng lấy ra có giá trị bằng phần tử duyệt đến sau cùng của

Queue (c.next) và xóa phần tử đó ra khỏi Queue (c.next=null)

-Front():Kiểm tra hàng đợi

+Nếu hàng đợi rỗng báo lỗi

+Ngược lại , kiểm tra :

*Nếu hàng đợi có 1 phần tử (first.next =null) phần tử đầu hàng đợi có giá trị bằng first

* Ngược lại, dùng một con trỏ c duyệt qua các phần tử của Queue ( khởi tạo c=first duyệt

đến c.next.next=null) ,phần tử đầu hàn đợi có giá trị bằng phần tử duyệt đến sau cùng của

Queue (c.next)

Bài 3: Sắp xếp danh sách số nguyên dùng Queue

Gợi ý: Khai báo một Queue toàn cục Q

Trước tiên xây dựng một hàm thêm một số bất kỳ vào một Queue sao cho thứ tự

sắp xếp trong Queue không đổi ví dụ là hàm Them(int a,Queue P), Thực hiện kiểm tra:

+Nếu P rỗng thêm a vào P

+Ngược lại,kiểm tra phần tử ở đầu Queue P

Page 58: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 58

*Nếu P.Front()>a thêm a vào P

*Ngược lai,sử dụng một Queue TG ,chuyển hết các phần tử trong P sang TG đến khi gặp

số lớn hơn a, rồi đưa a vào P.Sau đó đưa toàn bộ các phần tử ở TG sang P

Tại hàm Main() thực hiện duyệt qua danh sách các số đã nhập, tại mỗi số ta gọi hàm

Them ( số đó ,Q) .Kết thúc hiện ra Q ta được dãy số giảm dần

Bài 4: Dùng Queue mô phỏng dòng chữ chạy trên màn hình

Bài 5: Hãy cho biết nội dung của hàng đợi sau mỗi thao tác trong dãy :

Ví dụ cho dãy: EAS*Y**QUE***ST***I*ON

Với một chữ cái tượng trưng cho thao tác thêm chữ cái tương ứng vào hàng đợi,

dấu * tượng trưng cho thao tác lấy nội dung một phần tử trong hàng đợi in lên màn hình.

Hãy cho biết sau khi hoàn tất chuỗi thao tác, những gì xuất hiện trên màn hình ?

Gợi ý: Khởi tạo một Queue lưu trữ các kí tự

Nhập vào xâu s dãy ký tự. Sau đó thực hiện thêm từng ký tự trong xâu s vào

Queue

Thực hiện duyệt qua các phần tử của Queue đến khi Queue rỗng .Tại mỗi phần tử

của Queue nếu kí tự trả ra có mã ASCII thuộc vào khoảng mã ASCII tương ứng của các

chữ cái A->Z và a->z thì hiện kí tự đó ra màn hình.

Page 59: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 59

BÀI THỰC HÀNH 7. DANH SÁCH LIÊN KẾT KÉP

* Mục tiêu

Hệ thống lại những kiến thức liên quan đế danh sách liên kết kép và các phép toán

trên nó

* Yêu cầu:

A. Bài tập mẫu

Bài 1: Cho một danh sách liên kết đôi, mỗi nút là một số nguyên dương.

a.Đếm xem trong danh sách có bao nhiêu số bằng x ?

b.Tìm phần tử dương nhỏ nhất trong danh sách.

c. Xóa phần tử x xuất hiện đầu tiên trong danh sách.

Gợi ý: Khai báo 2 nút toàn cục pHead, pTail lần lượt chứa địa chỉ nút đầu và nút cuối

danh sách

a.Khởi tạo biến d=0 đếm các số =x. Duyệt qua các phần tử trong danh sách bằng

một nút tg (khởi tạo tg=pHead), tại mỗi phần tử so sánh giá trị của nó với x nếu

bằng ta tăng giá trị biến d=d+1.

b. Khởi tạo giá trị min bằng lớn vô cùng (MaxValue). Duyệt qua các phần tử trong

danh sách bằng một nút tg (khởi tạo tg=pHead), tại mỗi phần tử nếu có giá trị nhỏ

hơn min va lớn hơn 0 thì gán min bằng phần tử đó.

c. Sử dụng một nút p (Khởi tạo p=pHead), duyệt qua các phần tử của danh sách

đến khi gặp phần tử có giá trị x

+Nếu p=null báo lỗi không có x trong danh sách

+Ngược lại, p sẽ trỏ vào nút cần xóa:

*Nếu p=pHead, gán pHead bằng phần tử đứng sau pHead (pHead=pHead.next)

*Nếu p=pTail (hay p.next=null tức p trỏ vào phần tử cuối), ta cho p trỏ vào null

*Ngược lại, ta cho nút đứng trước p chứa địa chỉ nút đứng sau p và nút đứng sau p

chứa địa chỉ nút đứng trước p. Khi đó, p không còn liên kết trong danh sách.

Lời giải mẫu

using System;

class Node

{

Page 60: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 60

public int info;

public Node pre, next;//chứa địa chỉ nút đứng trước, đứng sau

}

class DSLKK

{

static Node L, R;// chứa địa chỉ nút đầu tiên, cuối cùng của danh sách

static void Nhap()

{

Console.WriteLine("Nhap vao day so nguyen");

int i = 1; Node tg; char kt;

L =R = null;

do

{

Console.WriteLine("Nhap so nguyen thu:" + i);

tg = new Node();

Console.Write("Info="); tg.info = int.Parse(Console.ReadLine());

tg.pre = null;

tg.next = null;

if (L == null && R == null) L = R = tg;

else

{

tg.pre = R;

R.next = tg;

R = tg;

}

Console.WriteLine("Ban nhap tiep C/K"); kt = char.Parse(Console.ReadLine());

} while (char.ToUpper(kt) == 'C');

}

static void Hien()

{

Console.WriteLine("Cac phan tu co trong danh sach");

Node tg = L;

Page 61: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 61

while (tg != null)

{

Console.Write(tg.info + "\t");

tg = tg.next;

}

Console.WriteLine();

}

public static int Dem(int x)

{

int d = 0;

Node tg = L;

while (tg != null)

{

if (x == tg.info) d++;

tg = tg.next;

}

return d;

}

static int MinDuong()

{

if (L == null && R == null) throw new Exception("Danh sach rong");

else

{

int m = int.MaxValue;

Node tg = L;

while (tg != null)

{

if (m > tg.info && tg.info >= 0) m = tg.info;

tg = tg.next;

}

return m;

}

Page 62: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 62

}

static void Xoa(int x)

{

Node p = L;

while (p != null && p.info != x) p = p.next;

if (p == null) Console.WriteLine("x khong ton tai trong danh sach");

else

{

if (p == L) L = L.next;

else if (p.next == null) p.pre.next = null;

else

{

p.pre.next = p.next;

p.next.pre = p.pre;

}

}

}

//Ham thuc hien cac chuc nang cua chuong trinh

static void Main()

{

Nhap();

Xoa(3);

Hien();

Console.WriteLine("Min duong trong danh sach:" + MinDuong());

Console.ReadKey();

}

}

Bài 2: Hãy viết phần khai báo cấu trúc dữ liệu để mô tả một danh sách liên kết đôi mà

mỗi phần tử chứa một số nguyên. Viết các hàm thực hiện các yêu cầu sau:

a. Đưa ra màn hình các phần tử là số nguyên tố có trong danh sách

b. Sắp xếp các phần tử của danh sách theo chiều giảm dần.

Page 63: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 63

c. Giả sử danh sách đã được sắp xếp giảm dần, hãy thêm một phần tử vào danh

sách sao cho thứ tự trong danh sách không thay đổi

Gợi ý: Khai báo 2 nút toàn cục pHead, pTail chứa địa chỉ nút đầu và nút cuối danh sách

a. Xây dựng hàm kiểm tra một số bất kỳ có phải số nguyên tố hay không, giả sử là hàm

KTNT(int x). Thực hiện duyệt qua các phần tử cả danh sách tại mỗi phần tử gọi hàm

KTNT nếu trả giá trị True ta hiện giá trị của phần tử đó ra màn hình

b. Duyệt qua từng phần tử của danh sách, tại mỗi phần tử thực hiện so sánh với từng phần

tử phía sau nó nếu lớn hơn thực hiên hoán đổi vị trí của 2 phần tử cho nhau,

c. Khởi tạo một nút tg chứa giá trị cần thêm vào có địa chỉ nút đứng trước và đứng sau là

null,

+Nếu danh sách rỗng gán pHead=pTail=tg

+Ngược lại,sử dụng nút p =pHead duyệt qua các phần tử của danh sách đến khi gặp phần

tử nhỏ hơn giá trị thêm

*Nếu p=null tức giá trị thêm vào là nhỏ nhất ta thực hiện thêm vào bên phải danh sách

*Nếu p=pHead giá trị thêm vào là nhỏ nhất ta thêm vào đầu danh sách

*Ngược lại, ta thực hiện thêm tg vào vị trí nút p đang trỏ đến

Lời giải mẫu:

using System;

class Node

{

public int info;

public Node pre, next;//chứa địa chỉ nút đứng trước, đứng sau

}

class DSLKK

{

static Node pHead, pTail;

static void Nhap()

{

Console.WriteLine("Nhap vao day so nguyen");

int i = 1; Node tg; char kt;

pHead = pTail = null;

Page 64: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 64

do

{

Console.WriteLine("Nhap so nguyen thu:" + i);

tg = new Node();

Console.Write("Info="); tg.info = int.Parse(Console.ReadLine());

tg.pre = null;

tg.next = null;

if (pHead == null && pTail == null) pHead = pTail = tg;

else

{

tg.pre = pTail;

pTail.next = tg;

pTail = tg;

}

Console.WriteLine("Ban nhap tiep C/K"); kt = char.Parse(Console.ReadLine());

} while (char.ToUpper(kt) == 'C');

}

static void Hien()

{

Node tg = pHead;

while (tg != null)

{

Console.Write(tg.info + "\t");

tg = tg.next;

}

Console.WriteLine();

}

//Hàm kiểm tra n có phải là số nguyên tố không?

static bool NguyenTo(int n)

{

bool ok = true;

for (int i = 2; i <= n - 1; ++i)

Page 65: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 65

if (n % i == 0) { ok = false; break; }

return ok;

}

static void HienNT()

{

Console.WriteLine("Cac phan tu la so nguyen to co trong danh sach");

Node tg = pHead;

while (tg != null)

{

if (NguyenTo(tg.info))

Console.Write(tg.info + "\t");

tg = tg.next;

}

Console.WriteLine();

}

static void SapXep()

{

Node i = pHead;

while (i.next != null)

{

Node j = i.next;

while (j != null)

{

if (i.info < j.info)

{

int tg = i.info;

i.info = j.info;

j.info = tg;

}

j = j.next;

}

i = i.next;

Page 66: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 66

}

}

static void Them(int x)

{

Node tg = new Node();

tg.info = x;

tg.pre = tg.next = null;

if (pHead == null && pTail == null) pHead = pTail = tg;

else

{

Node p = pHead;

while (p != null && p.info > tg.info) p = p.next;

if (p == pHead)//Them đầu danh sách

{

tg.next = pHead;

pHead.pre = tg;

pHead = tg;

}

else if (p == null)//Them cuối danh sách

{

tg.pre = pTail;

pTail.next = tg;

pTail = tg;

}

else//Them o giua

{

tg.next = p;

tg.pre = p.pre;

p.pre.next = tg;

p.pre = tg;

}

}

Page 67: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 67

}

//Ham thuc hien cac chuc nang cua chuong trinh

static void Main()

{

Nhap();

Console.WriteLine("Danh sach luc dau");

Hien();

Console.WriteLine("Danh sach sau khi sap xep");

SapXep();

Hien();

Console.WriteLine("Danh sach sau khi chen");

Them(5);

Hien();

Console.WriteLine("Danh sach cac so nguyen to");

HienNT();

Console.ReadKey();

}

}

B. Bài tập tự giải

Bài 1: Dùng danh sách liên kết kép viết chương trình lưu trữ một danh sách các số

nguyên, sắp xếp danh sách theo thứ tự (tăng hoặc giảm), trộn 2 danh sách có thứ tự để

được một danh sách mới có thứ tự.

Yêu cầu chi tiết:

1. Viết các khai báo cần thiết để cài đặt một danh sách các số nguyên.

Gợi ý: Khai báo nút mang thông tin là số nguyên và địa chỉ nút trước, sau của nút

Khai báo nút đầu và cuối của danh sách

2. Viết thủ tục khởi tạo một danh sách rỗng.

Gợi ý: Danh sách rỗng khi nút đầu và cuối của danh sách là rỗng (null)

3. Viết hàm kiểm tra danh sách rỗng.

Gợi ý: Hàm kiểm tra trả giá trị True khi nút đầu và cuối cùng rỗng (null)

4. Viết thủ tục nhập một danh sách.

Page 68: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 68

Gợi ý: Khai báo 2 nút đầu, cuối của danh sách pHead, pTail

Khởi tạo danh sách rỗng và một nút tg chứa giá trị cần nhập với địa chỉ nút đứng

trước và sau của tg là null. Thực hiện thêm tg vào danh sách

+Nếu danh sách rỗng gán pHead = pTail =tg

+Ngược lại, thêm tg vào trước nút cuối của danh sách

5. Viết thủ tục hiển thị danh sách ra màn hình.

Gợi ý: Khởi tạo nút tg=pHead duyệt qua các phần tử bên phải tg của danh sách ,tại mỗi

phần tử hiện ra giá trị của nó

6. Viết thủ tục sắp xếp danh sách theo thứ tự (tăng hoặc giảm).

Gợi ý: Khởi tạo nút tg=pHead duyệt qua các phần tử bên phải tg của danh sách,tại mỗi

phần tử thực hiện so sánh với từng phần tử bên phải nó nếu lớn hơn thực hiên hoán đổi

giá trị của 2 phần tử cho nhau,

7. Xen một phần tử mới x vào danh sách sau cho danh sách mới vẫn bảo đảm thứ tự.

Gợi ý: (Giả sử cho danh sách tăng dần)

Khởi tạo một nút tg chứa giá trị x với địa chỉ trước và sau của tg là null

+Nếu danh sách là rỗng ta gán nút đầu và cuối danh sách bằng tg

+ Ngược lại dùng nút p=pHead duyệt qua các phần tử đứng sau tg của danh sách đến khi

gặp nút có giá trị lớn hơn x. Sau khi duyệt p trỏ vào vị trí cần thêm

*Nếu p=pHead thực hiện thêm vào đầu danh sách (x là nhỏ nhất so với danh sách)

*Nếu p=null thêm vào phải danh sách (x là lớn nhất)

*Ngược lại, thêm vào vị trí nút p dang trỏ đến

8. Xóa một phần tử x ra khỏi danh sách sao cho danh sách mới vẫn bảo đảm thứ tự.

Gợi ý : Khi xóa một phần tử không làm thay đổi thứ tự danh sách.

Xóa một phần tử như sau:

+ Nếu danh sách rỗng hoặc không có x trong danh sách: báo lỗi

+ Ngược lại :

*Nếu x=pHead, pHead=pHead.next

*Nếu x=pTail, pTail=pTail.pre

*Ngược lại, cho nút đứng trước x nắm thông tin nút đứng sau x và nút đứng sau x nắm

thông tin nút đứng trước x. Khi đó, x không còn liên kết trong danh sách.

9. Viết thủ tục trộn 2 danh sách đã có thứ tự thành một danh sách mới sao cho danh sách

mới vẫn bảo đảm thứ tự.

Page 69: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 69

Gợi ý: Xây dựng một hàm thêm một số bất kỳ vào một danh sách sao cho thứ tự không

đổi ( cách làm như câu 7)

Sau đó khai báo một danh sách kq, rồi duyệt qua các phần tử của 2 danh sách, tại

mỗi phần tử ta gọi hàm thêm vào ở trên với đối số là phần tử đang xét và danh sách kq

Bài 2: Dùng danh sách liên kết kép cộng hai đa thức bất kỳ

R(x) =P(x)+Q(x)

Với

P(x)=a0xn+a1x

n-1+…+an

Q(x)=b0xm+b1x

m-1+…+bm

Sau đó tính giá trị của một đa thức R tại điểm x0

Gợi ý: Khai báo danh sách gồm 2 trường số mũ và hệ số để lưu trữ từng phần tử của đa

thức

Khai báo 2 nút toàn cục pHead, pTail chứa địa chỉ đầu và cuối danh sách

Khai báo các danh sách toàn cục P,Q,KQ

Nhập vào danh sách P và Q

Xây dựng một hàm thêm 1 nút tg vào danh sách P:

+Nếu P rỗng thì pHead = pTail =tg;

+Ngược lại P!=null : Duyệt qua các phần tử của danh sách P bằng một nút p

*Nếu p.số mũ =tg.số mũ thì cộng hệ số của p với hệ số của tg đưa kết quả vào p.hệ số

*Nếu trong ds P không có số mũ = số mũ của tg ta thực hiện chèn tg vào sau nút cuối

cùng có số mũ nhỏ hơn tg ( có 3 th :chèn trái–chèn phải –chèn giữa danh sách)

Xây dựng hàm tính tổng như sau: khai báo danh sách KQ rỗng

Duyệt qua các nút của danh sách chứa đa thức P và Q tại mỗi phần tử ta gọi hàm thêm

nút với tham số truyền vào là nút đang duyệt và danh sách KQ

Page 70: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 70

BÀI THỰC HÀNH 8. DANH SÁCH LIÊN KẾT VÒNG

* Mục tiêu

Hệ thống lại những kiến thức liên quan đế danh sách liên kết vòng và các phép

toán trên nó

* Yêu cầu:

A. Bài tập mẫu

Bài 1: Hãy viết phần khai báo cấu trúc dữ liệu để mô tả một danh sách liên kết đơn vòng

mà mỗi phần tử chứa một số nguyên. Viết các hàm thực hiện các yêu cầu sau:

a.Tách danh sách ban đầu thành hai danh sách: l1 chứa các số chẵn, l2 chứa các số lẻ

b.Tính tổng các phân tử là số dương và chia hết cho 3 có ở trong danh sách

Gợi ý: Trước tiên ta phải khởi tạo và nhập giá trị cho danh sách l.

a. Khởi tạo 2 danh sách l1, l2 mới rỗng. Sau đó kiểm tra danh sách l nếu rỗng thì in

ra 1 dòng thông báo danh sách rỗng. Ngược lại, khởi tạo 1 node p=l, trong khi chưa

hết phần tử trong p, kiểm tra nếu p.info chia hết cho 2 (số chia hết cho 2 là số chẵn)

thì thêm p.info vào l1, ngược lại thêm p.info vào l2.

b. Khởi tạo t=0(1 biến để lưu trữ phần tử là số dương và chia hết cho 3). Khai báo 1

node tg=l, trong khi chưa duyệt hết các phần tử trong tg ta kiểm tra nếu phần tử nào

là số dương (tg.info>0) và chia hết cho 3 (tg.info%3==0) thì ta cộng giá trị phần tử

đó vào biến t (t=t+tg.info).

Lời giải mẫu:

using System;

class Node

{

public int info;

public Node link;

}

class DSLKDV

{

static Node l, l1, l2;

static void Nhap()

{

Page 71: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 71

Console.WriteLine("Nhap vao day so nguyen");

int i = 1; l = null; Node tg; char kt;

do

{

Console.WriteLine("Nhap so nguyen thu:" + i);

tg = new Node();

Console.Write("Info="); tg.info = int.Parse(Console.ReadLine());

tg.link = null;

ThemDau(ref l, tg);//Hoac ThemCuoi(ref l,tg);

Console.WriteLine("Ban nhap tiep C/K"); kt = char.Parse(Console.ReadLine());

} while (char.ToUpper(kt) == 'C');

}

static void ThemDau(ref Node l, Node tg)

{

Node c;

if (l == null) { l = tg; c = tg; }

else

{

c = l;

//Tim dia chi phan tu cuoi

while (l != null && c.link != l) c = c.link;

tg.link = l;

l = tg;

}

c.link = l;

}

static void ThemCuoi(ref Node l, Node tg)

{

if (l == null) l = tg;

else

{

Node c = l;

Page 72: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 72

//Tim dia chi phan tu cuoi

while (l != null && c.link != l) c = c.link;

c.link = tg;

}

tg.link = l;

}

static void Hien(Node l)

{

if (l == null)

Console.WriteLine("Danh sach rong");

else

{

Node tg = l;

do

{

Console.Write(tg.info + "\t");

tg = tg.link;

} while (tg != l);

Console.WriteLine();

}

}

static void Tong()

{

int t = 0;

if (l == null)

Console.WriteLine("Danh sach rong");

else

{

Node tg = l;

do

{

if (tg.info > 0 && tg.info % 3 == 0)

Page 73: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 73

t = t + tg.info;

tg = tg.link;

} while (tg != l);

Console.WriteLine("Ket qua la:" + t);

}

}

static void Tach()

{

l1 = l2 = null;

//l1 chua cac so chan, l2 chua cac so le

if (l == null)

Console.WriteLine("Danh sach rong");

else

{

Node p = l, tg;

do

{

tg = new Node();

tg.info = p.info;

tg.link = null;

if (p.info % 2 == 0) ThemDau(ref l1, tg);

else ThemDau(ref l2, tg);

p = p.link;

} while (p != l);

Console.WriteLine();

}

}

//Ham thuc hien cac chuc nang cua chuong trinh

static void Main()

{

Nhap();

Page 74: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 74

Console.WriteLine("Danh sach luc dau");

Hien(l);

Tach();

Console.WriteLine("Danh sach so chan");

Hien(l1);

Console.WriteLine("Danh sach so e");

Hien(l2);

Tong();

Console.ReadKey();

}

}

Bài 2: Cho một danh sách liên kết đôi, mỗi nút chứa một số nguyên.

a.Rut gọn danh sách và chỉ giữ lại một giá trị trong số các giá trị giống nhau.

b.Kiểm tra xem danh sách có được sắp xếp tăng dần hay không?

Gợi ý: Trước tiên ta phải khởi tạo và nhập giá trị cho danh sách PHead, pTail. Tạo 1 lớp

node gồm 1 trường lưu trữ thông tin info kiểu int, và 2 trường lưu trữ địa chỉ pre,next

(pHead.pre lưu trữ thông tin nút đứng trước của pHead còn next lưu trữ thông tin nút

đứng sau của pTail). Khai báo danh sách pHead, pTail toàn cục.

a. Đầu tiên kiểm tra xem danh sách nếu rỗng (pHead=null và pTail=null) thì in ra

thông báo danh sách rỗng. Ngược lại khởi tạo node i=pHead,j, ta sử dụng 2 vòng

lặp. Thực hiện các công việc sau cho đến khi j=pHead:gán j=i.right,trong khi

j!=pHeadthì kiểm tra nếu i.info=j.info thì xóa j đi.

b. Kiểm tra xem danh sách nếu rỗng (pHead=null và pTail=null) thì in ra thông

báo danh sách rỗng. Ngược lại khai báo node tg=pHead, kiểm tra xem phần tử

đứng trước của tg không bằng pHead (tg.next!=pHead nghĩa là chưa duyệt hết

vòng) và giá trị của tg lớn hơn giá trị của phần tử tiếp theo(tg.next.info) thì gán

ok=false(ok là biến theo dõi tính đúng hay sai) rồi thoát khỏi vòng lặp. Nếu

ok=true thì dãy tăng dần ngược lại là dãy k tăng dần.

Lời giải mẫu:

using System;

class Node

{

Page 75: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 75

public int info;

public Node pre, next;

}

class DSLKKV

{

static Node pHead, pTail;

static void Nhap()

{

Console.WriteLine("Nhap vao day so nguyen");

int i = 1; Node tg; char kt;

pHead = pTail = null;

do

{

Console.WriteLine("Nhap so nguyen thu:" + (i++));

tg = new Node();

Console.Write("Info="); tg.info = int.Parse(Console.ReadLine());

tg.pre = null;

tg.next = null;

ThemDauTrai(tg);

Console.WriteLine("Ban nhap tiep C/K"); kt = char.Parse(Console.ReadLine());

} while (char.ToUpper(kt) == 'C');

}

static void ThemDauTrai(Node tg)

{

if (pHead == null && pTail == null)

{

pHead = pTail = tg;

tg.next = pHead;

tg.pre = pTail;

}

else

{

Page 76: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 76

tg.next = pHead;

tg.pre = pTail;

pHead.pre = tg;

pTail.next = tg;

pHead = tg;

}

}

static void Rutgon()

{

if (pHead == null && pTail == null)

Console.WriteLine("Danh sach rong");

else

{

Node i = pHead, j;

do

{

j = i.next;

do

{

if (i.info == j.info) Xoa(j);

j = j.next;

} while (j != pHead);

i = i.next;

} while (i != pHead);

Console.WriteLine();

}

}

static void Xoa(Node p)

{

if (pHead == null && pTail == null) return;

else

{

Page 77: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 77

if (p == pHead && p == pTail) pHead = pTail = null;

else if (p == pHead)

{

pTail.next = pHead.next;

pHead.next.pre = pTail;

pHead = pHead.next;

}

else if (p == pTail)

{

pHead.pre = pTail.pre;

pTail.pre.next = pHead;

pTail = pTail.pre;

}

else

{

p.pre.next = p.next;

p.next.pre = p.pre;

}

}

}

static void KiemTra()

{

bool ok = true;

if (pHead == null && pTail == null)

Console.WriteLine("Danh sach rong");

else

{

Node tg = pHead;

do

{

if (tg.next != pHead && tg.info > tg.next.info) { ok = false; break; }

tg = tg.next;

Page 78: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 78

} while (tg != pHead);

Console.WriteLine();

}

if (ok) Console.WriteLine("Day da cho la day tang dan");

else Console.WriteLine("Day da cho khong la day tang dan");

}

static void Hien()

{

if (pHead == null && pTail == null)

Console.WriteLine("Danh sach rong");

else

{

Node tg = pHead;

do

{

Console.Write(tg.info + "\t");

tg = tg.next;

} while (tg != pHead);

Console.WriteLine();

}

}

//Ham thuc hien cac chuc nang cua chuong trinh

static void Main()

{

Nhap();

Console.WriteLine("Day ban dau");

Hien();

Rutgon();

Console.WriteLine("Day sau khi rut gon");

Hien();

KiemTra();

Console.ReadKey();

Page 79: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 79

}

}

B.Bài tập tự giải

Dùng danh sách liên kết vòng viết chương trình lưu trữ một danh sách các số

nguyên, sắp xếp danh sách theo thứ tự (tăng hoặc giảm), trộn 2 danh sách có thứ tự để

được một danh sách mới có thứ tự.

Yêu cầu chi tiết:

1. Viết các khai báo cần thiết để cài đặt một danh sách các số nguyên.

2. Viết thủ tục khởi tạo một danh sách rỗng.

3. Viết hàm kiểm tra danh sách rỗng.

4. Viết thủ tục nhập một danh sách.

5. Viết thủ tục hiển thị danh sách ra màn hình.

6. Viết thủ tục sắp xếp danh sách theo thứ tự (tăng hoặc giảm).

7. Xen một phần tử mới x vào danh sách sau cho danh sách mới vẫn bảo đảm thứ tự.

8. Xóa một phần tử x ra khỏi danh sách sao cho danh sách mới vẫn bảo đảm thứ tự.

9. Viết thủ tục trộn 2 danh sách đã có thứ tự thành một danh sách mới sao cho danh sách

mới vẫn bảo đảm thứ tự.

Gợi ý:

1. Khai báo lớp node gồm thành phần lưu trữ thông tin info kiểu dữ liệu int,thành phần

lưu trữ địa chỉ phần tử kế tiếp next.

2. Danh sách rỗng phần tử đầu bằng phần tử cuối và bằng null.

3. Trả về giá trị phần tử đầu bằng phần tử cuối và bằng null.

4. Nối đơn (thêm vào đầu): nếu danh sách rỗng pHead=null thì gán pHead=tg; c=tg,

ngược lại tg.next=pHead, pHead=tg.(c.next=pHead). Nối kép (thêm vào đầu):danh

sach rỗng pHead=null và pTail=null thì gán pHead = pTail=tg, ngược lại

tg.next=pHead;pHead.pre=tg; pHead=tg. Sau đó gán pTail.next=pHead;

pTail.pre=pTail.

5. Duyệt các phần tử trong danh sách trong khi chưa đi giáp vòng ta in ra giá trị phần tử

tương ứng.

6. Khai báo node i, j, gán i=pHead, ta sử dụng 2 vòng lặp while. Trong khi

i.next!=null ta gán j=i.next, rồi duyệt j cho đến khi j=null. Kiểm tra giá trị của

Page 80: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 80

phần tử i.info nếu lớn hơn(nhỏ hơn) j.info thì ta hoán đổi giá trị của hai phần tử

này qua một biến trung gian nào đó. Kết thúc công việc đó ta được 1 danh sách

giảm dần(tăng dần) đối với danh sách nối đơn, danh sách nối kép tương tự.

7. Khai báo 2 node mới p=l, t=l. Trong khi p.info<phần tử mới nhập vào và p chưa

rỗng thì gán t=p. Khởi tạo 1 node tg mới gán tg.info=phần tử mới nhập vào. Kiểm

tra nếu l rỗng gán l=tg luôn, nếu p=l thì thêm vào đầu gán phần tử tiếp theo của

tg:tg.next=l;l=tg., nếu p rỗng thì thêm vào sau gán t.next=tg, ngược lại tất cả điều

trên ta thêm vào giữa. (Đây là cách đảm bảo thứ tự theo chiều tăng dần của danh

sách nối đơn, đối với danh sách nối kép hoăc theo chiều giảm dần tương tự).

8. Xóa một phần tử x ra khỏi danh sách sao cho danh sách mới vẫn bảo đảm thứ tự.

Khi xóa một phần tử không làm thay đổi thứ tự danh sách.

Xóa một phần tử như sau:

+ Nếu danh sách rỗng hoặc không có x trong danh sách: báo lỗi

+ Ngược lại, cho nút bên trái x nắm thông tin nút bên phải x và nút bên phải x nắm

thông tin nút bên trái x

9. Xây dựng một hàm thêm một số bất kỳ vào một danh sách sao cho thứ tự không

đổi (cách làm như câu 7)

Sau đó khai báo một danh sách kq, rồi duyệt qua các phần tử của 2 danh

sách, tại mỗi phần tử ta gọi hàm thêm vào ở trên với đối số là phần tử đang xét và

danh sách kq

Page 81: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 81

BÀI THỰC HÀNH 9. CÂY NHỊ PHÂN * Mục tiêu

- Hệ thống lại kiến thức về kiểu dữ liệu cây nhị phân như: Cách khai báo, các phép

duyệt trên cây nhị phân

- Cài đặt được các phép duyệt và một số thao tác trên cây nhị phân.

* Yêu cầu:

A. Bài tập mẫu

Bài 1: Tạo cây nhị phân, sau đó hiển thị các nút trên cây theo phép duyệt thứ tự giữa

Lời giải mẫu

using System;

class Node

{

public int Data;

public Node Left, Right;

}

class Trees

{

static void InSert(ref Node root, int newdata)

{

if (root == null)

{

root = new Node();

root.Data = newdata;

root.Left = null;

root.Next = null;

}

else if (newdata < root.Data) InSert(ref root.Left, newdata);

else if (newdata > root.Data) InSert(ref root.Right, newdata);

else Console.WriteLine("Error: Trung lap du lieu");

}

static void Duyet(Node nut)

{

Page 82: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 82

Console.Write(nut.Data + "->");

}

static void Pinorder(Node nut)

{

if (nut != null)

{

Pinorder(nut.Left);

Duyet(nut);

Pinorder(nut.Right);

}

}

//Ham thuc hien cac chuc nang cua chuong trinh

static void Main()

{

Node root = null; int newdata;

do

{

Console.Write("Ket thuc nhap nhan Enter");

newdata = int.Parse("0" + Console.ReadLine());

if (newdata != 0) InSert(ref root, newdata);

} while (newdata != 0);

Console.WriteLine("Duyet thu tu giua_LNR su dung de quy:");

Pinorder(root);

Console.ReadKey();

}

}

Câu 2: Thực hiện những thao tác sau với cây nhị phân tìm kiếm

a) Tạo cây nhị phân tìm kiếm với các khóa cho trước

b) Khiểm tra xem một khóa bất kỳ có trong cây không?

c) Hiện thị kết quả khi duyệt cây theo thứ tự giữa

d) Đếm số node trong cây

e) Đếm số nút có một con

Page 83: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 83

f) Đếm số nút có hai con

g) Đếm số lá của cây

h) Chiều cao của cây

Lời giải mẫu

using System; class Node { public int value; public Node left, right; } class Tree { static Node Root = null;//Goc cua cay nhi phan //Phuong thuc them mot nut co khoa la X vao cay nhi phan p static void Insert(ref Node Root, int X) { if (Root == null) { Root = new Node(); Root.value = X; Root.left = null; Root.right = null; } else { if (Root.value < X) Insert(ref Root.right, X); else if (Root.value > X) Insert(ref Root.left, X); } } static void Search(Node Root, int x, ref Node p) { //Nếu tìm thấy thì p chỉ tới nút có trường khoá bằng x, ngược lại p = null} p = Root; if (p != null) if (x < p.value) Search(Root.left, x, ref p); else if (x > p.value) Search(Root.right, x, ref p); else Console.WriteLine("Da tim thay nut co gia tri"+x); else Console.WriteLine("Khong tim thay nut co gia tri" + x); } //Phuong thuc duyet cay nhi phan tho thu tu giua static void LNR(Node Root) { if (Root != null)

Page 84: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 84

{ LNR(Root.left); Console.Write("{0} -> ", Root.value); LNR(Root.right); } } //Dem so nut cua cay nhi phan, luu trong bien dem static void CountNode(Node Root,ref int dem) { if (Root != null) { dem++; CountNode(Root.left, ref dem); CountNode(Root.right, ref dem); } } static int Count1Node(Node Root) { if (Root == null) return 0; else if ((Root.left == null) && (Root.right == null)) return 0; else if (Root.left == null) return 1 + Count1Node(Root.right); else if (Root.right == null) return 1 + Count1Node(Root.left); else return Count1Node(Root.left) + Count1Node(Root.right); } static int Count2Node(Node Root) { if (Root == null) return 0; else if ((Root.left == null) && (Root.right == null)) return 0; else if (Root.left == null) return Count2Node(Root.right); else if (Root.right == null) return Count2Node(Root.left); else return 1 + Count2Node(Root.left) + Count2Node(Root.right); } static int CountLeaf(Node Root) { if (Root == null) return 0; else if ((Root.left == null) && (Root.right == null)) return 1;

Page 85: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 85

else return CountLeaf(Root.left) + CountLeaf(Root.right); } static int max(int a, int b) { int max; if (a > b) max = a; else max = b; return max; } static int high_tree(Node Root) { if (Root == null) return 0; else return 1 + max(high_tree(Root.left), high_tree(Root.right)); } static void Main() { int[] A = new int[] { 6, 13, 25, 14, 51, 42, 12, 31, 56, 67, 34 }; //Lan luot them cac phan tu cua mang A vao cay nhi phan thoa man dieu kien la cay nhi phan tim kiem for (int i = 0; i < A.Length; i++) Insert(ref Root, A[i]); //In ra cay nhi phan bang cach duyet theo thu tu giua LNR(Root); Console.WriteLine(); Node p = null; Search(Root, 56, ref p); //Dem so luong nut tren cay nhi phan int dem = 0; CountNode(Root, ref dem); Console.Write("\nSo nut tren cay nhi phan {0}", dem); Console.Write("\nSo node co mot con: {0}", Count1Node(Root)); Console.Write("\nSo node co hai con: {0}", Count2Node(Root)); Console.Write("\nSo la: {0}", CountLeaf(Root)); Console.Write("\nChieu cao: {0}", high_tree(Root)); Console.ReadKey(); } }

Câu 3: Viết chương trình cài đặt cây biểu thức với các yêu cầu sau: a) Tạo cây biểu thức b) Tính giá trị của cây biểu thức c) Hiển thị giá trị các node theo thứ tự sau

Gợi ý

Page 86: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 86

Thuật toán này yêu cầu sử dụng 2 stack: - OperatorStack: Chứa các toán tử - NodeStack: Chứa các node tạo nên cấu trúc cây (node gốc của các cây con được xây dựng từ dưới lên) Các bước tiến hành thuật toán

Tạo một phương thức phụ CreateSubTree() có nhiệm vụ tạo một cây biểu thức gồm 3 node. Node gốc là toán tử Pop ra từ OperatorStack, hai node lá là toán hạng Pop từ NodeStack. Cuối cùng đưa node gốc vào lại NodeStack. Lặp qua từng token trong biểu thức infix - Nếu là toán hạng: Push vào NodeStack - Nếu là dấu mở ngoặc “(“: Push vào OperatorStack - Nếu là dấu đóng ngoặc “)”:

+ Lặp cho đến khi lấy được dấu mở ngoặc “(“ trong OperatorStack, mỗi lần lặp gọi phương thức CreateSubTree(). + Pop dấu mở ngoặc ra khỏi OperatorStack.

- Nếu là toán tử: + Lặp cho đến khi OperatorStack rỗng hoặc độ ưu tiên của toán tử ở đỉnh OperatorStack nhỏ hơn độ ưu tiên của toán tử hiện tại. Mỗi lần lặp gọi phương thức CreateSubTree() + Push toán tử vào OperatorStack.

Khi hết vòng lặp, nếu OperatorStack còn phần tử, gọi phương thức CreateSubTree() cho đến khi OperatorStack rỗng. Node cuối cùng nằm trong NodeStack là node gốc của cây. Ví dụ chuyển biểu thức infix sau thành cây biểu thức: (a+b)*c-d/e

Token OperatorStack NodeStack Description

( ( {Empty} Push “(“ vào OperatorStack

a ( a Push “a” vào NodeStack

+ (+ a Push “+” vào OperatorStack

b (+ a b Push “b” vào NodeStack

) {Empty} + Cho “a”, “b” ra thành node con của “+” Push “+” vào NodeStack

* * + Push “*” vào OperatorStack

c * + c Push “c” vào NodeStack

- - * Cho “+”, “c” thành node con của “*” Push “*” vào node Stack Push “-“ vào OperatorStack

d - * d Push “d” vào NodeStack

Page 87: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 87

/ - / * d Push “/” vào OperatorStack

e - / * d e Push “e” vào NodeStack

- / * d e Kết thúc vòng lặp

- * / Cho “d” và “e” thành node con của “/” Push “/” vào NodeStack

{Empty} - Cho “*” và “/” thành node con của “-“ Push “-“ vào NodeStack

Lời giải mẫu using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; class BinaryTreeNode { public BinaryTreeNode LeftChild; public BinaryTreeNode RightChild; public string Value; public bool IsLeaf { get { return this.LeftChild == null && this.RightChild == null; } } public BinaryTreeNode(string value) { Value = value; } } class Expression { static string Infix2Prefix(string infix) { List<string> prefix = new List<string>(); Stack<string> stack = new Stack<string>(); for(int i=0;i<infix.Length;++i) { if (IsOperator(infix[i])) prefix.Add(infix[i].ToString()); else if (infix[i] == ')')

Page 88: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 88

stack.Push(infix[i].ToString()); else if (infix[i] == '(') { string x = stack.Pop(); while (x != ")") { prefix.Add(x); x = stack.Pop(); } } else { while (stack.Count > 0 && Priority(infix[i].ToString()) < Priority(stack.Peek())) prefix.Add(stack.Pop()); stack.Push(infix[i].ToString()); } } while (stack.Count > 0) prefix.Add(stack.Pop()); StringBuilder str = new StringBuilder(); for (int i = prefix.Count - 1; i >= 0; i--) { str.Append(prefix[i]); } return str.ToString(); } static double EvaluateExpressionTree(BinaryTreeNode node) { double t = 0; if (node.IsLeaf) t = double.Parse(node.Value); else { double x = EvaluateExpressionTree(node.LeftChild); double y = EvaluateExpressionTree(node.RightChild); switch (node.Value) { case "+": t = x + y; break; case "-": t = x - y; break; case "*": t = x * y; break; case "/": t = x / y; break; case "%": t = x % y; break;

Page 89: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 89

} } return t; } static void CreateSubTree(Stack<BinaryTreeNode> opStack, Stack<BinaryTreeNode> nodeStack) { BinaryTreeNode node = opStack.Pop(); node.RightChild = nodeStack.Pop(); node.LeftChild = nodeStack.Pop(); nodeStack.Push(node); } static BinaryTreeNode Infix2ExpressionTree(string infixExpression) { List<string> prefix = new List<string>(); Stack<BinaryTreeNode> operatorStack = new Stack<BinaryTreeNode>(); Stack<BinaryTreeNode> nodeStack = new Stack<BinaryTreeNode>(); for (int i = 0; i < infixExpression.Length; ++i) { if (IsOperator(infixExpression[i])) { while (operatorStack.Count > 0 && Priority(operatorStack.Peek().Value) >= Priority(infixExpression[i].ToString())) CreateSubTree(operatorStack, nodeStack); operatorStack.Push(new BinaryTreeNode(infixExpression[i].ToString())); } else if (infixExpression[i] == '(') operatorStack.Push(new BinaryTreeNode(infixExpression[i].ToString())); else if (infixExpression[i] == ')') { while (operatorStack.Peek().Value != "(") CreateSubTree(operatorStack, nodeStack); operatorStack.Pop(); } else nodeStack.Push(new BinaryTreeNode(infixExpression[i].ToString())); } while (operatorStack.Count > 0) CreateSubTree(operatorStack, nodeStack); return nodeStack.Peek(); } static bool IsOperator(char str) { return str == '+' || str == '-' || str == '*' || str == '/';

Page 90: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 90

} static bool IsOperand(char str) { return str >= '0' && str <= '9'; } public static int Priority(string op) { if (op == "*" || op == "/") return 2; if (op == "+" || op == "-") return 1; return 0; } static void LRN(BinaryTreeNode p) //phuong thuc duyet cay nhi phan { if (p != null) { LRN (p.LeftChild); LRN (p.RightChild); Console.Write("{0} -> ", p.Value); } } static void Main() { string x = "(5-3)*(3+1)/2"; BinaryTreeNode s = Expression.Infix2ExpressionTree(x); Console.WriteLine(Expression.EvaluateExpressionTree(s)); Expression. LRN (s); Console.ReadKey(); } }

Bài tập tự giải

Bài 1: Viết chương trình cài đặt một cây biểu thức, tính trị của cây biểu thức này.

Yêu cầu chi tiết:

1. Viết phần khai báo để cài đặt một cây biểu thức.

2. Viết thủ tục khởi tạo cây rỗng.

3. Viết hàm kiểm tra cây rỗng.

Page 91: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 91

4. Thiết kế hàm tạo cây từ cây con trái L, cây con phải R và nhản của nút n, bằng cách

xem đây là có nút gốc là n và 2 cây con tương ứng là L (con trái) và R (con phải).

5. Viết các thủ tục duyệt cây:

Duyệt tiền tự, trung tự, hậu tự .

Duyệt theo mức.

6. Viết hàm xác định số nút trong cây.

7. Thiết kế hàm xác định chiều cao của cây.

8. Viết hàm tính giá trị của cây biểu thức.

9. Viết hàm xác định mức của một nút trong cây.

Gợi ý:

1.Trước tiên ta khai báo 1 lớp node gồm 1 thành phần lưu trữ thông tin, 2 thành

phần chứa địa chỉ bên trái và bên phải và khai báo 1 node root(gốc)mới.

class node

{

public int x;

public node left, right;

}

2. Cây rỗng khi không có gốc nghĩa là root=null. Cây con trái rỗng root.left=null,

cây con phải rỗng root.next=null.

3.Trả về giá trị root=null.

4.-Đối với phép toán hai ngôi(chẳng hạn +.-,*,/) được biểu diễn gốc chứa toán tử,

cây con trái biểu diễn toán hạng bên trái, cây con phải biểu diễn toán hạng bên

phải.

-Đối với phép toán 1 ngôi như “phủ định” hoặc “lấy giá trị tuyệt đối”,hoặc các

hàm chuẩn như exp() hoặc cos()…thì cây con trái rỗng.

-Còn với các phép toán 1 toán hạng như phép “lấy đạo hàm” ()’ hoặc “hàm giai

thừa” ()! Thì cây con phải rỗng.

5. -Duyệt tiền tự: thăm gốc->duyệt cây con trái theo thứ tự trước->duyệt cây con

phải theo thứ tự trước.

-Duyệt trung tự: duyệt cây con trái theo thứ tự giữa->thăm gốc->duyệt cây con

phải theo thứ tự giữa

Page 92: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 92

-Duyệt hậu tự: duyệt cây con trái theo thứ tự sau->duyệt cây con phải theo thứ tự

sau->thăm gốc.

-Duyệt theo mức: ta sử dụng kiểu hàng đợi queue để duyệt. Nếu cây không rỗng

thì thực hiện đưa cây con vào queue, trong khi queue chưa rỗng thì in ra giá trị

trong queue, nếu cây con trái không rỗng thì duyệt mức cây bên trái,ngược lại

duyệt mức cây bên phải.

6. Duyệt cho đến khi cây rỗng số nút trong cây=gốc+cây con bên trái+cây con bên

phải.

7.Chiều cao của cây được xác định bằng công thức h=[log2(n+1)], trong đó n là số

nút trên cây đó.

8.Đầu tiên ta phải duyệt cây theo thứ tự trước để chuyển biểu thức về dạng tiền tố

hoặc duyệt theo thứ tự sau để chuyển biểu thức về dạng hậu tố. Sau đó ta thực hiện

tính toán giá trị biểu thức giống như bài tính toán biểu thức ở phần stack.

Bài 2: Viết chương trình cài đặt một cây tìm kiếm nhị phân (nhãn của mỗi nút được nhập

từ bàn phím) .

Yêu cầu chi tiết:

1. Viết phần khai báo để cài đặt một cây tìm kiếm nhị phân.

2. Viết thủ tục khởi tạo cây rỗng.

3. Viết hàm kiểm tra cây rỗng.

4. Viết thủ tục xen một nút vào cây tìm kiếm nhị phân.

5. Viết thủ tục xóa một nút trong cây tìm kiếm nhị phân.

6. Viết thủ tục nhập một cây tìm kiếm nhị phân với nhản của các nút của cây được nhập

vào từ bàn phím.

7. Viết các thủ tục duyệt cây:

Duyệt tiền tự, trung tự, hậu tự .

Duyệt theo mức.

8. Viết hàm xác định số nút trong cây.

9. Thiết kế hàm xác định chiều cao của cây.

10. Viết hàm xác định mức của một nút trong cây.

Gợi ý:

Page 93: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 93

1.Trước tiên ta khai báo 1 lớp node gồm 1 thành phần lưu trữ thông tin ,2 thành

phần chứa địa chỉ bên trái và bên phải và khai báo 1 node root (gốc)mới.

class node

{

public int info;

public node left, right;

}

2.Cây rỗng khi không có gốc nghĩa là root=null.cây con trái rỗng root.left=null,

cây con phải rỗng root.next=null.

3.Trả về giá trị root=null.

4.Ta có thể xen một nút vào cây nhị phân vào nhiều chỗ khác nhau nhưng thêm

vào một nút lá là thuận tiện nhất. Trước tiên ta tạo 1 node p mới và gán p.info=x(x

là giá trị của nút muốn thêm vào). Sau đó kiểm tra nếu gốc rỗng thì gán luôn nút

mới là gốc, cây con trái,phải của gốc bằng null, ngược lại nếu x mà lớn hơn giá trị

của gốc thì ta them vào cây con bên phải, nhỏ hơn them vào cây con bên trái.

5.Xóa nút trên cây có thể xảy ra 3 trường hợp:

-x là nút lá

-x là nút nửa lá(chỉ có một con trái hoặc con phải)

-x có đủ hai con(trường hợp tổng quát)

Nếu nút muốn xóa không có cây con trái và cây con phải thì ta chỉ cần xóa

nút đó là xong, ngược lại nếu có 1 cây con trái hoặc cây con phải thì thì cho cây

con trái hoặc cây con phải móc nối với cây cha của nút đó.

Nếu nút muốn xóa có cả 2 cây con phải và cây con trái thì ta so sánh cây

con phải và cây con trái của nút đó với cây cha nếu cây con trái nhỏ hơn cây cha

của nút cần xóa thì cho chúng móc nối với nhau, ngược lại ta cho cây con phải

móc nối với cây cha của nút cần xóa.

6.Nếu cây rỗng thì gán luôn giá trị nhập vào bằng gốc, ngược lại so sánh với gốc

nếu nhỏ hơn thì gán bằng cây con trái của gốc, ngược lại gán bằng cây con phải

của gốc,c ứ như vậy khi nào kết thúc việc nhập vào thì thôi.

7. Duyệt tiền tự: thăm gốc->duyệt cây con trái theo thứ tự trước->duyệt cây con

phải theo thứ tự trước.

Page 94: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 94

-Duyệt trung tự: duyệt cây con trái theo thứ tự giữa->thăm gốc->duyệt cây con

phải theo thứ tự giữa

-Duyệt hậu tự: duyệt cây con trái theo thứ tự sau->duyệt cây con phải theo thứ tự

sau->thăm gốc.

-Duyệt theo mức: ta sử dụng kiểu hàng đợi queue để duyệt. Nếu cây không rỗng

thì thực hiện đưa cây vào queue,trong khi queue chưa rỗng thì in ra giá trị trong

queue,nếu cây con trái không rỗng thì duyệt mức cây bên trái,ngược lại duyệt mức

cây bên phải.

8. Duyệt cho đến khi cây rỗng số nút trong cây=gốc+cây con bên trái+cây con bên

phải.

9. Chiều cao của cây được xác định bằng công thức h=[log2(n+1)],trong đó n là số

nút trên cây đó.

Bài 3: Viết chương trình cài đặt một cây tổng quát ( dùng mảng hay con trỏ ).

Yêu cầu chi tiết:

1. Viết phần khai báo để cài đặt một cây.

2. Viết thủ tục khởi tạo cây rỗng.

3. Viết hàm kiểm tra cây rỗng.

4. Viết thủ tục nhập một cây với nhản của các nút của cây được nhập từ bàn phím.

5. Viết các thủ tục duyệt cây:

Duyệt tiền tự.

Duyệt trung tự.

Duyệt hậu tự.

Duyệt theo mức.

6. Viết hàm xác định số nút trong cây.

7. Thiết kế hàm xác định chiều cao của cây.

8. Viết hàm xác định mức của một nút trong cây (nút đầu tiên có nhản cần xác định).

9. Thiết lập một hàm kiểm tra sự hiện hữu của một nút nào đó trong cây.

10. Thiết lập hàm xác định nhản của nút con trái nhất của một nút với nhản của nút được

nhập từ bàn phím.

11. Thiết lập hàm xác định nhản của nút anh ruột phải của một nút với nhản của nút

được nhập từ bàn phím.

Page 95: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 95

12. Thiết lập hàm xác định nhản của nút cha của một nút với nhản của nút với nhản của

nút được nhập từ bàn phím.

Gợi ý:

1.Khai báo một lớp node gồm thành phần lưu trữ kiểu giá trị của từng nút,1 trường lưu

trữ địa chỉ của các nút con.

Class node {

Public int x;

Public node con1;

Public node con2;

….

}

2.Cây khai báo rỗng khi nút gốc được khai báo rỗng

3.Hàm kiểm tra cây rỗng trả giá trị True khi nút gốc là rỗng (root=null)

4.Sử dụng đệ quy .Thực hiện kiểm tra cây

+ Nếu rỗng (root=null) gán gốc có giá trị vừa nhập và các nút con trỏ vào null

+Ngược lại,Kiểm tra cây con thứ nhất (root.con1) nếu rỗng gán cho giá trị vừa nhập và

các nút con của nó trỏ vào null,nếu không rỗng thực hiện kiểm tra các nút kế tiếp việc

gán thực hiện tương tự

5.Xây dựng một hàm duyệt hiển thị giá trị của một nút. Trong các thuật toán duyệt cây ta

sử dụng hàm đệ quy

*Duyệt tiền tự : gọi hàm duyệt hiển thị nút gốc ,rồi duyệt đệ quy lần lượt các nút con của

*Duyệt trung tự :

*Duyệt hậu tự: gọi hàm duyệt đệ quy từng nút con của nút gốc và gọi hàm duyệt hiển thị

nút gốc

*Duyệt mức:khởi tạo một QUEUE ,duyệt qua từng nút của cây,tại mỗi nút thực hiện đưa

tất cả các nút con của nó vào Queue và hiện ra các phần tử trong Queue.Tiếp đến thực

hiện gọi hàm đệ quy Duyệt mức của các cây con tiếp theo

6.Duyệt qua các nút trong cây ,qua mỗi nút ta thực hiện tăng giá trị của một biến đếm nút

với khởi tạo bằng 0

7.hàm xác định chiều cao của cây trả giá trị loga cơ số 2 của( số nút +1)

8.

Page 96: Bai Tap Thuc Hanh Cau Truc DL&GT(2012)

Bài tập thực hành CTDL & GT Trang 96

BÀI THỰC HÀNH 10. Kiểm tra thực hành

* Yêu cầu:

- Cài đặt được các thuật toán trên các kiểu dữ liệu

- Có khả năng áp dụng các thuật toán để lập trình giải các bài toán theo yêu cầu