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 : Đại học Hệ đào tạo : Chính quy
Hưng Yên năm 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........................................... ĐƠ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
Bài tập thực hành CTDL & GT
BÀI THỰC HÀNH 1.
Trang 3
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 (k-1 là vị trí trước trước vị trí cần chèn) tmp[k]=giá trị cần chèn tmp[i+1]=a[i] vớ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 du yệt các c ác phần tử trong mảng kiểm tra xem phần tử đó có phải 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 int[] [] a; static void Nhap() {
int n; Console.Write( Console .Write("Nhap "Nhap n="); n="); n = int int.Parse( .Parse(Console Console.ReadLine()); .ReadLine()); a = new int int[n]; [n];
Bài tập thực hành CTDL & GT
for ((int i = 0; i < a.Length; ++i) for { Console.Write( Console .Write("a[" "a[" + i + "]=" "]="); ); a[i] = int int.Parse( .Parse(Console Console.ReadLine()); .ReadLine()); } } static void Chen(int Chen(int x, int k) { if (k if (k >= 0 && k <= a.Length - 1) { int[] int [] tmp = new int int[a.Length [a.Length + 1]; for ((int i = 0; i < k; ++i) for tmp[i] = a[i]; tmp[k] = x; for ((int i = k; i < a.Length; ++i) for tmp[i + 1] = a[i]; a = tmp; } else Console Console.WriteLine( .WriteLine("Du "Du lieu khong hop le"); le"); } static bool static bool ngto(int ngto(int x) { bool ok = true true;; for ((int i = 2; i < x - 1; ++i) for if (x if (x % i == 0) { ok = false false;; break ; } return ok; } static void Xoa() { int n = a.Length; for ((int i = 0; i < n; ) for if (ngto(a[i])) if (ngto(a[i]))
Trang 4
Bài tập thực hành CTDL & GT
Trang 5
{ for ((int j = i; j < a.Length - 1; ++j) for a[j] = a[j + 1]; n = n - 1; } else ++i; int[] int [] tmp = new int int[n]; [n]; for ((int i = 0; i < n; ++i) for tmp[i] = a[i]; a = tmp; } static void Hien() { for ((int i = 0; i < a.Length; ++i) for Console.Write(a[i] Console .Write(a[i] + "\t" "\t"); ); Console.WriteLine(); Console .WriteLine(); } static void Main() { Nhap(); Chen(333, 1); Hien(); Xoa(); Hien(); Console.ReadKey(); 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)
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 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 struct NhanVien { public string MaNV; public string Hoten; public int Namsinh; public string Phongban; public int LuongCB; public int Thuong; } class VD { static NhanVien 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 int.MaxValue; .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 struct NhanVien {
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 static NhanVien[] [] DS; static void Nhap() { int n; Console.Write( Console .Write("Nhap "Nhap n="); n="); n = int int.Parse( .Parse(Console Console.ReadLine()); .ReadLine()); DS = new new NhanVien NhanVien[n]; [n]; for ((int i = 0; i < DS.Length; ++i) for { Console.WriteLine( Console .WriteLine("Nhap "Nhap thong tin NV thu:" + i); Console.Write( Console .Write("Ma "Ma nhan vien:"); vien:"); DS[i].MaNV = Console Console.ReadLine(); .ReadLine(); Console.Write( Console .Write("Ho "Ho ten:"); ten:"); DS[i].Hoten = Console Console.ReadLine(); .ReadLine(); Console.Write( Console .Write("Nam "Nam sinh:"); sinh:"); DS[i].Namsinh = int int.Parse( .Parse(Console Console.ReadLine()); .ReadLine()); Console.Write( Console .Write("Phong "Phong ban:"); ban:"); DS[i].Phongban = Console Console.ReadLine(); .ReadLine(); Console.Write( Console .Write("Luong "Luong co ban:"); ban:"); DS[i].LuongCB = int.Parse( int .Parse(Console Console.ReadLine()); .ReadLine()); Console.Write( Console .Write("Thuong:" "Thuong:"); ); DS[i].Thuong = int int.Parse( .Parse(Console Console.ReadLine()); .ReadLine()); } } static int ThucLinh(int ThucLinh(int i) { return DS[i].Thuong + DS[i].LuongCB; } static void HienMin()
Bài tập thực hành CTDL & GT
Trang 8
{ int min = int int.MaxValue; .MaxValue; for ((int i = 0; i < DS.Length; ++i) for if (min if (min > DS[i].LuongCB) min = DS[i].LuongCB; Console.WriteLine( Console .WriteLine("Danh "Danh sach luong cb min"); min"); for ((int i = 0; i < DS.Length; ++i) for if (DS[i].LuongCB if (DS[i].LuongCB == min) Console.WriteLine(DS[i].MaNV 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) for t += ThucLinh(i); Console.WriteLine( Console .WriteLine("Tong "Tong luong cty:" + t); } static void Main() { Nhap(); TongLuongCTy(); HienMin(); Console.ReadKey(); 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.
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) chèn) tmp[k]=giá trị cần chèn tmp[i+1]=a[i] vớ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]
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 n hấ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 int.MaxValue; .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)
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 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í t rí hàng nhỏ hơn vị trí cột (i
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
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 v iê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 struct NhanVien { public string MaNV; public string Hoten; public int Namsinh; public string Phongban; public int LuongCB; public int Thuong; } class VD { static NhanVien 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 b.Đầu tiên ta gán một biến min=int.MaxValue(giá trị dương vô cùng).
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 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 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 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:
Bài tập thực hành CTDL & GT
*Với
đường
chéo
thuộc
Trang 14
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 ghi n (n là số nguyên dương 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. DAY SO.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”.
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ố 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.
Bài tập thực hành CTDL & GT
Trang 16
BÀI THỰC HÀNH HÀNH 2. ĐỘ PHỨC TẠP TÍNH 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(N 2), 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 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(N 2), 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++) {
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( Console .Write("Nhap "Nhap n="); n="); n = int int.Parse( .Parse(Console Console.ReadLine()); .ReadLine()); Console.Write( Console .Write("Nhap "Nhap x="); x="); x = double double.Parse( .Parse(Console Console.ReadLine()); .ReadLine()); for ((int i = 1; i <= n; i++) for { p = p * x / i; s = s + p; } Console.WriteLine( Console .WriteLine("Ket "Ket qua:" + s); Console.ReadKey(); 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 ý 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
Bài tập thực hành CTDL & GT
Lời giản mẫu using System; using System.Text; class BaiXau { static void chuanHoaSo(ref chuanHoaSo(ref string string so1, ref ref string string so2) { StringBuilder s1 StringBuilder s1 = new StringBuilder (so1); (so1); StringBuilder s2 StringBuilder s2 = new StringBuilder (so2); (so2); if (s1.Length if (s1.Length > s2.Length) while (s2.Length < s1.Length) s2.Insert(0, "0" "0"); ); else if (s2.Length if (s2.Length > s1.Length) while (s1.Length < s2.Length) s1.Insert(0, "0" "0"); ); so1 = s1.ToString(); so2 = s2.ToString(); } static string tinhTong(string tinhTong(string so1, string so2) { string s; int t, a, b, nho = 0; int n; chuanHoaSo(ref chuanHoaSo(ref so1, so1, ref ref so2); so2); StringBuilder kq StringBuilder kq = new StringBuilder ("" ""); ); n = so1.Length - 1; while (n >= 0) { a = so1[n] - 48; b = so2[n] - 48;
Trang 18
Bài tập thực hành CTDL & GT
Trang 19
t = a + b + nho; s = t.ToString(); if (s.Length if (s.Length == 1) s = "0" + s; nho = s[0] - 48; kq.Insert(0, s[1]); n = n - 1; } if (nho if (nho == 1) kq.Insert(0, "1" "1"); ); return kq.ToString(); } static void Main() { string so1, so2; StringBuilder xx = new StringBuilder ("" StringBuilder ""); ); StringBuilder yy = new StringBuilder ("" StringBuilder ""); ); StringBuilder ss = new StringBuilder ("" StringBuilder ""); ); Console.WriteLine( Console .WriteLine("\t\t "\t\t BAN HAY NHAP VAO HAI SO NGUYEN"); NGUYEN"); Console.Write( Console .Write("" "); so1 = Console Console.ReadLine(); .ReadLine(); Console.WriteLine( Console .WriteLine("+" "+"); ); Console.Write( Console .Write("" "); so2 = Console Console.ReadLine(); .ReadLine(); x.Append('-' x.Append('-',, so1.Length > so2.Length ? so1.Length : so2.Length); y.Append(' y.Append(' ',', Math Math.Abs(so1.Length .Abs(so1.Length - so2.Length)); s.AppendFormat("\t\t{0}\n\n" s.AppendFormat("\t\t{0}\n\n",, "BAN HAY NHAP VAO HAI SO NGUYEN"); NGUYEN"); if (so1.Length if (so1.Length < so2.Length) s.AppendFormat(" s.AppendFormat(" {0}{1}\n", {0}{1}\n", y.ToString(), so1); else s.AppendFormat(" s.AppendFormat(" {0}\n", {0}\n", so1); s.AppendFormat("{0}\n" s.AppendFormat("{0}\n",, "+" "+"); ); if (so2.Length if (so2.Length < so1.Length) s.AppendFormat(" s.AppendFormat(" {0}{1}\n", {0}{1}\n", y.ToString(), so2);
Bài tập thực hành CTDL & GT
Trang 20
else s.AppendFormat(" s.AppendFormat(" {0}\n", {0}\n", so2); s.AppendFormat(" s.AppendFormat(" {0}\n", {0}\n", x.ToString()); s.AppendFormat(" s.AppendFormat(" {0}", {0}", tinhTong(so1, so2)); Console.Clear(); Console .Clear(); Console.WriteLine(s); Console .WriteLine(s); Console.ReadKey(); 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à 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
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ả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ố
Bài tập thực hành CTDL & GT
Trang 22
BÀI THỰC HÀNH 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 class Node { public int info; public Node public Node link; } class DSLKD
Bài tập thực hành CTDL & GT
Trang 23
{ static Node static Node l = new new Node Node(); (); // l dùng để chứa chứa địa chỉ của nút đầu tiên trong danh sách static void Nhap() { Console.WriteLine( Console .WriteLine("Nhap "Nhap vao day so nguyen"); nguyen"); int i = 0; l = null null;; Node tg; char char kt; kt; do { Console.WriteLine( Console .WriteLine("Nhap "Nhap so nguyen thu:" + ++i); tg = new new Node Node(); (); Console.Write( Console .Write("Info=" "Info="); ); tg.info = int int.Parse( .Parse(Console Console.ReadLine()); .ReadLine()); tg.link = null null;; // bổ sung nút tg vào đầu danh sách l if (l if (l == null null)) l = tg; else { tg.link = l; l = tg; } Console.WriteLine( Console .WriteLine("Ban "Ban nhap tiep C/K"); C/K"); kt = char .Parse(Console .Parse(Console.ReadLine()); .ReadLine()); } while (char .ToUpper(kt) .ToUpper(kt) == 'C' 'C'); ); } static void Hien() { Console.WriteLine( Console .WriteLine("Cac "Cac phan tu co trong danh sach"); sach"); Node tg = l; while (tg != null null)) { Console.Write(tg.info Console .Write(tg.info + "\t" "\t"); ); tg = tg.link; } Console.WriteLine(); Console .WriteLine(); } static int Dem(int Dem(int x) { int d = 0;
Bài tập thực hành CTDL & GT
Node tg = l; while (tg != null null)) { if (x if (x == tg.info) d++; tg = tg.link; } return d; } static int MinDuong() { if (l if (l == null null)) throw new Exception Exception(("Danh sach rong"); rong"); else { int m = int int.MaxValue; .MaxValue; Node tg = l; while (tg != null null)) { if (m if (m > tg.info && tg.info >= 0) m = tg.info; tg = tg.link; } return m; } } static void Xoa(int Xoa(int x) { Node p = l; Node t = p; while (p != null && p.info != x) { t = p; p = p.link; }
Trang 24
Bài tập thực hành CTDL & GT
Trang 25
if (p if (p == null null)) Console Console.WriteLine( .WriteLine("x "x khong ton tai trong danh sach"); sach"); else { if (p if (p == l) l = l.link; else if if (p.link (p.link == null null)) t.link = null null;; else t.link = p.link; } } //Ham thuc hien cac chuc nang cua chuong trinh static void Main() { Nhap(); Xoa(3); Hien(); Console.WriteLine( Console .WriteLine("Min "Min duong nho nhat:" + MinDuong()); Console.ReadKey(); Console .ReadKey(); } } Bài 2: Hãy viết phần khai báo cấu 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;
Bài tập thực hành CTDL & GT
Trang 26
class Node class Node { public int info; public Node public Node link; } class DSLKD { static Node static Node l; static void Nhap() { Console.WriteLine( Console .WriteLine("Nhap "Nhap vao day so nguyen"); nguyen"); int i = 1; l = null null;; Node tg; char char kt; kt; do { Console.WriteLine( Console .WriteLine("Nhap "Nhap so nguyen thu:" + i); tg = new new Node Node(); (); Console.Write( Console .Write("Info=" "Info="); ); tg.info = int int.Parse( .Parse(Console Console.ReadLine()); .ReadLine()); tg.link = null null;; if (l if (l == null null)) l = tg; else { tg.link = l; l = tg; } Console.WriteLine( Console .WriteLine("Ban "Ban nhap tiep C/K"); C/K"); kt = char .Parse(Console .Parse(Console.ReadLine()); .ReadLine()); } while (char .ToUpper(kt) .ToUpper(kt) == 'C' 'C'); ); } static void Hien( Node Node l) { Console.WriteLine( Console .WriteLine("Cac "Cac phan tu co trong danh sach"); sach"); Node tg = l; while (tg != null null)) { Console.Write(tg.info Console .Write(tg.info + "\t" "\t"); ); tg = tg.link; }
Bài tập thực hành CTDL & GT
Console.WriteLine(); Console .WriteLine(); } static Node static Node Tach() { Node tg = l, tmp, l1 = null null;; while (tg != null null)) { if (tg.info if (tg.info % 3 == 0 && tg.info % 2 == 0) { tmp = new new Node Node(); (); tmp.info = tg.info; tmp.link = null null;; //bổ sung nút tmp vào đầu danh sách l1 if (l1 if (l1 == null 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 null)) { j = i.link; while (j != null null)) { if (i.info if (i.info > j.info) { int tg = i.info; i.info = j.info; j.info = tg; }
Trang 27
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(); 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+a1xn-1+…+an Q(x)=b0xm+b1xm-1+…+bm Gợi ý: 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
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 class Node { public int hs; public int mu; public Node public Node next; } class DaThuc { static Node 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 Nhap(out Node Node l) { Console.WriteLine( Console .WriteLine("Nhap "Nhap thong tin cho da thuc"); thuc" ); int i = 1; l = null null;; Node tg; char char kt; kt; do { Console.WriteLine( Console .WriteLine("Nhapa "Nhapa thong tin cho phan tu thu:" + i); tg = new new Node Node(); (); Console.Write( Console .Write("He "He so:"); so:"); tg.hs = int int.Parse( .Parse(Console Console.ReadLine()); .ReadLine()); Console.Write( Console .Write("Mu:" "Mu:"); ); tg.mu = int int.Parse( .Parse(Console Console.ReadLine()); .ReadLine()); tg.next = null null;; Add(ref Add(ref l,l, tg); // bổ sung nút tg vào vị trí thích hợp theo số mũ Console.WriteLine( Console .WriteLine("Ban "Ban nhap tiep C/K"); C/K"); kt = char .Parse(Console .Parse(Console.ReadLine()); .ReadLine()); } while (char .ToUpper(kt) .ToUpper(kt) == 'C' 'C'); ); } static void Add(ref Add(ref Node Node l, Node l, Node tg) { if (l if (l == null null)) l = tg;
Bài tập thực hành CTDL & GT
else { Node p = l, t = l; while (p != null && p.mu < tg.mu) { t = p; p = p.next; } //Neu mu da co if (p if (p != null && tg.mu == p.mu) p.hs = p.hs + tg.hs; else //Them vao dau if (p if (p == l) { tg.next = l; l = tg; } //Them vao sau else if if (p (p == null && t.next == null null)) t.next = tg; //Them vao giua else { tg.next = p; t.next = tg; } } } static void Hien( Node Node l) { Node tg = l; string kq = "" "";;
Trang 30
Bài tập thực hành CTDL & GT
while (tg != null null)) { if (tg.mu if (tg.mu == 0) kq = kq + tg.hs; else if if (tg.mu (tg.mu == 1) kq = kq + (tg.hs > 0 ? "+" : "-" "-")) + tg.hs + "X" "X";; else kq = kq + (tg.hs > 0 ? "+" : "-" "-")) + tg.hs + "X^" + tg.mu; tg = tg.next; } Console.WriteLine(kq); Console .WriteLine(kq); } static void Tong() { R = null null;; Node tmp = P, tg; while (tmp != null null)) { tg = new new Node Node(); (); tg.hs = tmp.hs; tg.mu = tmp.mu; tg.next = null null;; Add(ref Add(ref R, R, tg); tmp = tmp.next; } tmp = Q; while (tmp != null null)) { tg = new new Node Node(); (); tg.hs = tmp.hs; tg.mu = tmp.mu; tg.next = null null;; Add(ref Add(ref R, R, tg); tmp = tmp.next; }
Trang 31
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( Console .WriteLine("Nhap "Nhap thong tin da thuc P"); P"); Nhap(out Nhap(out P); Hien(P); Console.WriteLine( Console .WriteLine("Nhap "Nhap thong tin da thuc Q"); Q" ); Nhap(out Nhap(out Q); Hien(Q); Console.WriteLine( Console .WriteLine("Tong "Tong hai da thuc"); thuc"); Tong(); Hien(R); Console.ReadKey(); 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 hi ện cộng dồn các giá trị của nó vào t
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
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 t oà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 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 t iế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:
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 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 ý 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 t hô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
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 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ỉ c hỉ 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; }
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 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 tg. info chúng ta đang kiểm tra là số nguyên tố ta tăng tă ng biến đếm đ ếm khởi tạo 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 l1= null,một ,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 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
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
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 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+x2y3x3y2+….+(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 da nh 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.
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 da nh sách tổng 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ỏ.
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.
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 int[] [] s; public bool public bool isEmpty() { return top == -1;
Bài tập thực hành CTDL & GT
Trang 43
} public bool public bool isFull() { return top >= s.Length; } public void Init() { s = new int int[20]; [20]; top = -1; } public void Push(int Push(int x) { if (!isFull()) if (!isFull()) s[++top] = x; else Console Console.Write( .Write("Stack "Stack tran"); tran"); } public int Pop() { if (isEmpty()) if (isEmpty()) throw new Exception Exception(("Tack Empty"); 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" "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.
Bài tập thực hành CTDL & GT
Lời giải mẫu using System; class Stack { public int top; public int int[] [] s; public bool public bool isEmpty() { return top == -1; } public bool public bool isFull() { return top >= s.Length; } public void Init() { s = new int int[20]; [20]; top = -1; } public void Push(int Push(int x) { if (!isFull()) if (!isFull()) s[++top] = x; else Console Console.Write( .Write("Stack "Stack tran"); tran"); } public int Pop() { if (isEmpty()) if (isEmpty()) throw new Exception Exception(("Tack Empty"); Empty"); else return s[top--]; } } class App {
Trang 44
Bài tập thực hành CTDL & GT
Trang 45
static void Main() { Stack tt = new Stack (); Stack (); int n; Console.Write( Console .Write("Nhap "Nhap vao so can doi:"); doi:"); n = int int.Parse( .Parse(Console Console.ReadLine()); .ReadLine()); t.Init(); string st = "0123456789ABCDEF" "0123456789ABCDEF";; while (n != 0) { t.Push((int t.Push((int)st[n )st[n % 16]); n = n / 16; } Console.Write( Console .Write("Ket "Ket qua chuyen sang he thap luc phan:"); phan:"); while (!t.isEmpty()) { Console.Write( Console .Write("{0}" "{0}",, (char (char )t.Pop()); )t.Pop()); } Console.ReadKey(); 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
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 object[] [] s; public bool isEmpty() { return top == -1; } public bool isFull() { return top >= s.Length; } public void Init() { s = new object object[20]; [20]; top = -1; } public object Top() {
Bài tập thực hành CTDL & GT
if (isEmpty()) if (isEmpty()) throw new Exception Exception(("Tack Empty"); Empty"); else return s[top]; } public void Push(object Push(object x) { if (!isFull()) if (!isFull()) s[++top] = x; else Console Console.Write( .Write("Stack "Stack tran"); tran"); } public object Pop() { if (isEmpty()) if (isEmpty()) throw new Exception Exception(("Tack Empty"); Empty"); else return s[top--]; } } public class TBT { static int Pri(char Pri(char k) k) { int kq = 0; switch (k) { case '+' '+':: kq = 1; break 1; break ; case '-' '-':: kq = 1; break 1; break ; case '*' '*':: kq = 2; break 2; break ; case '/' '/':: kq = 2; break 2; break ; } return kq; } static string PostFix(string PostFix(string E) { Stack tt = new Stack (); Stack (); t.Init();
Trang 47
Bài tập thực hành CTDL & GT
string E1 = "" "";; for ((int i = 0; i < E.Length; ++i) for if (E[i] if (E[i] >= '0' && E[i] <= '9' '9')) E1 = E1 + E[i].ToString(); else if if (E[i] (E[i] == '(' '(')) t.Push('(' t.Push('('); ); else if if (E[i] (E[i] == ')' ')')) { while ((char ((char )t.Top() )t.Top() != '(' '(')) { E1 = E1 + t.Pop(); } t.Pop(); } else { while (!t.isEmpty() && Pri((char Pri((char )t.Top()) )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 Calculator(string E) { double y, x, z; Stack tt = new Stack (); Stack (); t.Init(); for ((int i = 0; i < E.Length; ++i) for if (E[i] if (E[i] >= '0' && E[i] <= '9' '9')) t.Push((double t.Push((double)E[i] )E[i] - 48); else switch (E[i]) {
Trang 48
Bài tập thực hành CTDL & GT
case '+' '+':: y = (double (double)t.Pop(); )t.Pop(); x = (double (double)t.Pop(); )t.Pop(); z = x + y; t.Push((double t.Push((double)z); )z); break ; case '-' '-':: y = (double (double)t.Pop(); )t.Pop(); x = (double (double)t.Pop(); )t.Pop(); z = x + y; t.Push((double t.Push((double)z); )z); break ; case '*' '*':: y = (double (double)t.Pop(); )t.Pop(); x = (double (double)t.Pop(); )t.Pop(); z = x + y; t.Push((double t.Push((double)z); )z); break ; case '/' '/':: y = (double (double)t.Pop(); )t.Pop(); x = (double (double)t.Pop(); )t.Pop(); z = x + y; t.Push((double t.Push((double)z); )z); break ; } return (double double)t.Pop(); )t.Pop(); } //Ham thuc hien cac chuc nang cua chuong trinh static void Main() { string E = "5+(5+3*2)+3+6/2" "5+(5+3*2)+3+6/2";; string E1 = PostFix(E);
Trang 49
Bài tập thực hành CTDL & GT
Trang 50
Console.WriteLine(Calculator(E1)); Console .WriteLine(Calculator(E1)); Console.ReadKey(); 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 n,n hập hệ cần đổi k. 3. Khai báo string st = "0123456789ABCDEF" "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.
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ệ. 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.
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).
Bài tập thực hành CTDL & GT
BÀI THỰC HÀNH 6.
Trang 53
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 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
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 class Node { public int value; public Node public Node next; } class Queue { public Node public Node first; public bool public bool EmptyQueue() { return first == null null;; } public void EnQueue(int EnQueue(int x) { Node tg = new new Node Node(); (); tg.value = x; tg.next = first; first = tg; } public int DeQueue() { int value; if (first if (first == null null)) throw new Exception Exception(("Queue empty"); empty"); else { if (first.next if (first.next == null null)) {
Bài tập thực hành CTDL & GT
value = first.value; first = null null;; } else { Node c = first; while (c.next.next != null null)) c = c.next; value = c.next.value; c.next = null null;; } return value; } } public void Cleanup() { first = null null;; } public int Front() { int value; if (first if (first == null null)) throw new Exception Exception(("Queue empty"); empty"); { if (first.next if (first.next == null null)) { value = first.value; } else { Node c = first; while (c.next.next != null null)) c = c.next; value = c.next.value; }
Trang 55
Bài tập thực hành CTDL & GT
Trang 56
return value; } } } class App { static void Main() { Queue t = new Queue Queue(); (); int x; char char kt; kt; do { Console.Write( Console .Write("Nhap "Nhap mot so nguyen:"); nguyen:"); x = int int.Parse( .Parse(Console Console.ReadLine()); .ReadLine()); t.EnQueue(x); Console.Write( Console .Write("Ban "Ban co nhap tiep C/K"); C/K" ); kt = char .Parse(Console .Parse(Console.ReadLine()); .ReadLine()); } while (char .ToUpper(kt) .ToUpper(kt) == 'C' 'C'); ); Console.WriteLine( Console .WriteLine("Cac "Cac so nguyen da nhap"); nhap" ); while (!t.EmptyQueue()) Console.Write(t.DeQueue() Console .Write(t.DeQueue() + "\t" "\t"); ); Console.WriteLine(); Console .WriteLine(); Console.ReadKey(); 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.
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
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.
Bài tập thực hành CTDL & GT
BÀI THỰC HÀNH 7.
Trang 59
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ử 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 class Node {
Bài tập thực hành CTDL & GT
Trang 60
public int info; public Node 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( Console .WriteLine("Nhap "Nhap vao day so nguyen"); nguyen"); int i = 1; Node 1; Node tg; char char kt; kt; L =R = null null;; do { Console.WriteLine( Console .WriteLine("Nhap "Nhap so nguyen thu:" + i); tg = new new Node Node(); (); Console.Write( Console .Write("Info=" "Info="); ); tg.info = int int.Parse( .Parse(Console Console.ReadLine()); .ReadLine()); tg.pre = null null;; tg.next = null null;; if (L if (L == null && R == null null)) L = R = tg; else { tg.pre = R; R.next = tg; R = tg; } Console.WriteLine( Console .WriteLine("Ban "Ban nhap tiep C/K"); C/K"); kt = char .Parse(Console .Parse(Console.ReadLine()); .ReadLine()); } while (char .ToUpper(kt) .ToUpper(kt) == 'C' 'C'); ); } static void Hien() { Console.WriteLine( Console .WriteLine("Cac "Cac phan tu co trong danh sach"); sach"); Node tg = L;
Bài tập thực hành CTDL & GT
while (tg != null null)) { Console.Write(tg.info Console .Write(tg.info + "\t" "\t"); ); tg = tg.next; } Console.WriteLine(); Console .WriteLine(); } public static int Dem(int Dem(int x) { int d = 0; Node tg = L; while (tg != null null)) { if (x if (x == tg.info) d++; tg = tg.next; } return d; } static int MinDuong() { if (L if (L == null && R == null null)) throw new Exception Exception(("Danh sach rong"); rong"); else { int m = int int.MaxValue; .MaxValue; Node tg = L; while (tg != null null)) { if (m if (m > tg.info && tg.info >= 0) m = tg.info; tg = tg.next; } return m; }
Trang 61
Bài tập thực hành CTDL & GT
Trang 62
} static void Xoa(int Xoa(int x) { Node p = L; while (p != null && p.info != x) p = p.next; if (p if (p == null null)) Console Console.WriteLine( .WriteLine("x "x khong ton tai trong danh sach"); sach"); else { if (p if (p == L) L = L.next; else if if (p.next (p.next == null null)) p.pre.next = null 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( Console .WriteLine("Min "Min duong trong danh sach:" + MinDuong()); Console.ReadKey(); 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 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.
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 class Node { public int info; public Node 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( Console .WriteLine("Nhap "Nhap vao day so nguyen"); nguyen"); int i = 1; Node 1; Node tg; char char kt; kt; pHead = pTail = null null;;
Bài tập thực hành CTDL & GT
Trang 64
do { Console.WriteLine( Console .WriteLine("Nhap "Nhap so nguyen thu:" + i); tg = new new Node Node(); (); Console.Write( Console .Write("Info=" "Info="); ); tg.info = int int.Parse( .Parse(Console Console.ReadLine()); .ReadLine()); tg.pre = null null;; tg.next = null null;; if (pHead if (pHead == null && pTail == null null)) pHead = pTail = tg; else { tg.pre = pTail; pTail.next = tg; pTail = tg; } Console.WriteLine( Console .WriteLine("Ban "Ban nhap tiep C/K"); C/K"); kt = char .Parse(Console .Parse(Console.ReadLine()); .ReadLine()); } while (char .ToUpper(kt) .ToUpper(kt) == 'C' 'C'); ); } static void Hien() { Node tg = pHead; while (tg != null null)) { Console.Write(tg.info Console .Write(tg.info + "\t" "\t"); ); tg = tg.next; } Console.WriteLine(); Console .WriteLine(); } //Hàm kiểm tra n có phải là số nguyên tố không? static bool NguyenTo(int NguyenTo(int n) { bool ok = true true;; for ((int i = 2; i <= n - 1; ++i) for
Bài tập thực hành CTDL & GT
if (n if (n % i == 0) { ok = false false;; break ; } return ok; } static void HienNT() { Console.WriteLine( Console .WriteLine("Cac "Cac phan tu la so nguyen to co trong danh sach"); sach" ); Node tg = pHead; while (tg != null null)) { if (NguyenTo(tg.info)) if (NguyenTo(tg.info)) Console.Write(tg.info Console .Write(tg.info + "\t" "\t"); ); tg = tg.next; } Console.WriteLine(); Console .WriteLine(); } static void SapXep() { Node i = pHead; while (i.next != null null)) { Node j = i.next; while (j != null null)) { if (i.info if (i.info < j.info) { int tg = i.info; i.info = j.info; j.info = tg; } j = j.next; } i = i.next;
Trang 65
Bài tập thực hành CTDL & GT
} } static void Them(int Them(int x) { Node tg = new new Node Node(); (); tg.info = x; tg.pre = tg.next = null null;; if (pHead if (pHead == null && pTail == null null)) pHead = pTail = tg; else { Node p = pHead; while (p != null && p.info > tg.info) p = p.next; if (p if (p == pHead)//Them pHead)//Them đầu danh sách { tg.next = pHead; pHead.pre = tg; pHead = tg; } else if if (p (p == null null))//Them cuối danh sách { tg.pre = pTail; pTail.next = tg; pTail = tg; } else//Them else //Them o giua { tg.next = p; tg.pre = p.pre; p.pre.next = tg; p.pre = tg; } }
Trang 66
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( Console .WriteLine("Danh "Danh sach luc dau"); dau"); Hien(); Console.WriteLine( Console .WriteLine("Danh "Danh sach sau khi sap xep"); xep" ); SapXep(); Hien(); Console.WriteLine( Console .WriteLine("Danh "Danh sach sau khi chen"); chen" ); Them(5); Hien(); Console.WriteLine( Console .WriteLine("Danh "Danh sach cac so nguyen to"); to" ); HienNT(); Console.ReadKey(); 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 trình lưu trữ một danh sách 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 các số nguyên. Gợi ý: 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 ý: 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 ý: 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.
Bài tập thực hành CTDL & GT
Trang 68
Gợi ý: 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 ý: 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 ý: 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 ý: 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 ý 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ự.
Bài tập thực hành CTDL & GT
Trang 69
Gợi ý: 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+a1xn-1+…+an Q(x)=b0xm+b1xm-1+…+bm Sau đó tính giá trị của một đa thức R tại điểm x 0 Gợi ý: 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
Bài tập thực hành CTDL & GT
BÀI THỰC HÀNH 8.
Trang 70
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 class Node { public int info; public Node public Node link; } class DSLKDV { static Node l, l1, l2; static void Nhap() {
Bài tập thực hành CTDL & GT
Trang 71
Console.WriteLine( Console .WriteLine("Nhap "Nhap vao day so nguyen"); nguyen"); int i = 1; l = null null;; Node tg; char char kt; kt; do { Console.WriteLine( Console .WriteLine("Nhap "Nhap so nguyen thu:" + i); tg = new new Node Node(); (); Console.Write( Console .Write("Info=" "Info="); ); tg.info = int int.Parse( .Parse(Console Console.ReadLine()); .ReadLine()); tg.link = null null;; ThemDau(ref ThemDau(ref l,l, tg);//Hoac tg);//Hoac ThemCuoi(ref l,tg); Console.WriteLine( Console .WriteLine("Ban "Ban nhap tiep C/K"); C/K"); kt = char .Parse(Console .Parse(Console.ReadLine()); .ReadLine()); } while (char .ToUpper(kt) .ToUpper(kt) == 'C' 'C'); ); } static void ThemDau(ref ThemDau(ref Node Node l, Node l, Node tg) { Node c; if (l if (l == null 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 ThemCuoi(ref Node Node l, Node l, Node tg) { if (l if (l == null null)) l = tg; else { Node c = l;
Bài tập thực hành CTDL & GT
//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 Node l) { if (l if (l == null null)) Console.WriteLine( Console .WriteLine("Danh "Danh sach rong"); rong"); else { Node tg = l; do { Console.Write(tg.info Console .Write(tg.info + "\t" "\t"); ); tg = tg.link; } while (tg != l); Console.WriteLine(); Console .WriteLine(); } } static void Tong() { int t = 0; if (l if (l == null null)) Console.WriteLine( Console .WriteLine("Danh "Danh sach rong"); rong"); else { Node tg = l; do { if (tg.info if (tg.info > 0 && tg.info % 3 == 0)
Trang 72
Bài tập thực hành CTDL & GT
t = t + tg.info; tg = tg.link; } while (tg != l); Console.WriteLine( Console .WriteLine("Ket "Ket qua la:" + t); } } static void Tach() { l1 = l2 = null null;; //l1 chua cac so chan, l2 chua cac so le if (l if (l == null null)) Console.WriteLine( Console .WriteLine("Danh "Danh sach rong"); rong"); else { Node p = l, tg; do { tg = new new Node Node(); (); tg.info = p.info; tg.link = null null;; if (p.info if (p.info % 2 == 0) ThemDau(ref ThemDau(ref l1, l1, tg); else ThemDau(ref ThemDau(ref l2, l2, tg); p = p.link; } while (p != l); Console.WriteLine(); Console .WriteLine(); } } //Ham thuc hien cac chuc nang cua chuong trinh static void Main() { Nhap();
Trang 73
Bài tập thực hành CTDL & GT
Trang 74
Console.WriteLine( Console .WriteLine("Danh "Danh sach luc dau"); dau"); Hien(l); Tach(); Console.WriteLine( Console .WriteLine("Danh "Danh sach so chan"); chan"); Hien(l1); Console.WriteLine( Console .WriteLine("Danh "Danh sach so e"); e"); Hien(l2); Tong(); Console.ReadKey(); 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 ó đượ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 i.i nfo=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 class Node {
Bài tập thực hành CTDL & GT
Trang 75
public int info; public Node public Node pre, next; } class DSLKKV { static Node static Node pHead, pTail; static void Nhap() { Console.WriteLine( Console .WriteLine("Nhap "Nhap vao day so nguyen"); nguyen"); int i = 1; Node 1; Node tg; char char kt; kt; pHead = pTail = null null;; do { Console.WriteLine( Console .WriteLine("Nhap "Nhap so nguyen thu:" + (i++)); tg = new new Node Node(); (); Console.Write( Console .Write("Info=" "Info="); ); tg.info = int int.Parse( .Parse(Console Console.ReadLine()); .ReadLine()); tg.pre = null null;; tg.next = null null;; ThemDauTrai(tg); Console.WriteLine( Console .WriteLine("Ban "Ban nhap tiep C/K"); C/K"); kt = char .Parse(Console .Parse(Console.ReadLine()); .ReadLine()); } while (char .ToUpper(kt) .ToUpper(kt) == 'C' 'C'); ); } static void ThemDauTrai( Node Node tg) { if (pHead if (pHead == null && pTail == null null)) { pHead = pTail = tg; tg.next = pHead; tg.pre = pTail; } else {
Bài tập thực hành CTDL & GT
tg.next = pHead; tg.pre = pTail; pHead.pre = tg; pTail.next = tg; pHead = tg; } } static void Rutgon() { if (pHead if (pHead == null && pTail == null null)) Console.WriteLine( Console .WriteLine("Danh "Danh sach rong"); rong"); else { Node i = pHead, j; do { j = i.next; do { if (i.info if (i.info == j.info) Xoa(j); j = j.next; } while (j != pHead); i = i.next; } while (i != pHead); Console.WriteLine(); Console .WriteLine(); } } static void Xoa( Node Node p) { if (pHead if (pHead == null && pTail == null null)) return return;; else {
Trang 76
Bài tập thực hành CTDL & GT
if (p if (p == pHead && p == pTail) pHead = pTail = null null;; else if if (p (p == pHead) { pTail.next = pHead.next; pHead.next.pre = pTail; pHead = pHead.next; } else if if (p (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 true;; if (pHead if (pHead == null && pTail == null null)) Console.WriteLine( Console .WriteLine("Danh "Danh sach rong"); rong"); else { Node tg = pHead; do { if (tg.next if (tg.next != pHead && tg.info > tg.next.info) { ok = false false;; break ; } tg = tg.next;
Trang 77
Bài tập thực hành CTDL & GT
} while (tg != pHead); Console.WriteLine(); Console .WriteLine(); } if (ok) if (ok) Console Console.WriteLine( .WriteLine("Day "Day da cho la day tang dan"); dan"); else Console Console.WriteLine( .WriteLine("Day "Day da cho khong la day tang dan"); dan" ); } static void Hien() { if (pHead if (pHead == null && pTail == null null)) Console.WriteLine( Console .WriteLine("Danh "Danh sach rong"); rong"); else { Node tg = pHead; do { Console.Write(tg.info Console .Write(tg.info + "\t" "\t"); ); tg = tg.next; } while (tg != pHead); Console.WriteLine(); Console .WriteLine(); } } //Ham thuc hien cac chuc nang cua chuong trinh static void Main() { Nhap(); Console.WriteLine( Console .WriteLine("Day "Day ban dau"); dau"); Hien(); Rutgon(); Console.WriteLine( Console .WriteLine("Day "Day sau khi rut gon"); gon" ); Hien(); KiemTra(); Console.ReadKey(); Console .ReadKey();
Trang 78
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 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 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 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 pHead=null thì gán pHead=tg; pHead=tg; c=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.pre=pTa =pTail. il. 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
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
Bài tập thực hành CTDL & GT
BÀI THỰC HÀNH 9.
Trang 81
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 class Node { public int Data; public Node public Node Left, Right; } class Trees { static void InSert(ref InSert(ref Node Node root, int newdata) { if (root if (root == null null)) { root = new new Node Node(); (); root.Data = newdata; root.Left = null null;; root.Next = null null;; } else if if (newdata (newdata < root.Data) InSert(ref InSert(ref root.Left, root.Left, newdata); else if if (newdata (newdata > root.Data) InSert(ref InSert(ref root.Right, root.Right, newdata); else Console Console.WriteLine( .WriteLine("Error: "Error: Trung lap du lieu"); lieu"); } static void Duyet( Node Node nut) {
Bài tập thực hành CTDL & GT
Console.Write(nut.Data Console .Write(nut.Data + "->" "->"); ); } static void Pinorder( Node Node nut) { if (nut if (nut != null null)) { Pinorder(nut.Left); Duyet(nut); Pinorder(nut.Right); } } //Ham thuc hien cac chuc nang cua chuong trinh static void Main() { Node root = null null;; int newdata; do { Console.Write( Console .Write("Ket "Ket thuc nhap nhan Enter"); Enter"); newdata = int int.Parse( .Parse("0" "0" + Console Console.ReadLine()); .ReadLine()); if (newdata if (newdata != 0) InSert(ref InSert(ref root, root, newdata); } while (newdata != 0); Console.WriteLine( Console .WriteLine("Duyet "Duyet thu tu giua_LNR su dung de quy:"); quy:" ); Pinorder(root); Console.ReadKey(); 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
Trang 82
Bài tập thực hành CTDL & GT
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 class Node { public int value; public Node public Node left, right; } class Tree { static Node static Node Root = null null;;//Goc cua cay nhi phan //Phuong thuc them mot nut co khoa la X vao cay nhi phan p static void Insert(ref Insert(ref Node Node Root, int X) { if (Root if (Root == null null)) { Root = new new Node Node(); (); Root.value = X; Root.left = null null;; Root.right = null null;; } else { if (Root.value if (Root.value < X) Insert(ref Insert(ref Root.right, Root.right, X); else if if (Root.value (Root.value > X) Insert(ref Insert(ref Root.left, Root.left, X); } } static void Search( Node Node Root, int x, ref Node 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 if (p != null null)) if (x if (x < p.value) Search(Root.left, x, ref ref p); p); else if if (x (x > p.value) Search(Root.right, x, ref ref p); p); else Console Console.WriteLine( .WriteLine("Da "Da tim thay nut co gia tri"+x); tri"+x); else Console.WriteLine( Console .WriteLine("Khong "Khong tim thay nut co gia tri" + x); } //Phuong thuc duyet cay nhi phan tho thu tu giua static void LNR( Node Node Root) { if (Root if (Root != null null))
Trang 83
Bài tập thực hành CTDL & GT
{ LNR(Root.left); Console.Write( Console .Write("{0} "{0} -> ", ", Root.value); LNR(Root.right); }
} //Dem so nut cua cay nhi phan, luu trong bien dem static void CountNode( Node Node Root,ref Root,ref int int dem) { if (Root if (Root != null null)) { dem++; CountNode(Root.left, ref ref dem); dem); CountNode(Root.right, ref ref dem); dem); } } static int Count1Node( Node Node Root) { if (Root if (Root == null null)) return 0; else if if ((Root.left ((Root.left == null null)) && (Root.right == null null)) )) return 0; else if if (Root.left (Root.left == null null)) return 1 + Count1Node(Root.right); else if if (Root.right (Root.right == null null)) return 1 + Count1Node(Root.left); else return Count1Node(Root.left) + Count1Node(Root.right); } static int Count2Node( Node Node Root) { if (Root if (Root == null null)) return 0; else if if ((Root.left ((Root.left == null null)) && (Root.right == null null)) )) return 0; else if if (Root.left (Root.left == null null)) return Count2Node(Root.right); else if if (Root.right (Root.right == null null)) return Count2Node(Root.left); else return 1 + Count2Node(Root.left) + Count2Node(Root.right); } static int CountLeaf( Node Node Root) { if (Root if (Root == null null)) return 0; else if if ((Root.left ((Root.left == null null)) && (Root.right == null null)) )) return 1;
Trang 84
Bài tập thực hành CTDL & GT
Trang 85
else return CountLeaf(Root.left) + CountLeaf(Root.right); } static int max(int max(int a, int b) { int max; if (a if (a > b) max = a; else max = b; return max; } static int high_tree( Node Node Root) { if (Root if (Root == null null)) return 0; else return 1 + max(high_tree(Root.left), high_tree(Root.right)); } static void Main() { int[] int [] A = new int 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++) for Insert(ref Insert(ref Root, Root, A[i]); //In ra cay nhi phan bang cach duyet theo thu tu giua LNR(Root); Console.WriteLine(); Console .WriteLine(); Node p = null null;; Search(Root, 56, ref ref p); p); //Dem so luong nut tren cay nhi phan int dem = 0; CountNode(Root, ref ref dem); dem); Console.Write( Console .Write("\nSo "\nSo nut tren cay nhi phan {0}", {0}", dem); Console.Write( Console .Write("\nSo "\nSo node co mot con: {0}", {0}", Count1Node(Root)); Console.Write( Console .Write("\nSo "\nSo node co hai con: {0}", {0}", Count2Node(Root)); Console.Write( Console .Write("\nSo "\nSo la: {0}", {0}", CountLeaf(Root)); Console.Write( Console .Write("\nChieu "\nChieu cao: {0}", {0}", high_tree(Root)); Console.ReadKey(); 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 ý
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() 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 toán tử Pop ra từ OperatorStack, hai node lá là toán 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 hoặc độ ưu tiên của toán 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}
a
(
a
Push “a” vào NodeStack
+
(+
a
Push “+” vào OperatorStack
b
(+
ab
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
-
-
*
d
-
*d
Push “(“ vào OperatorStack
Push “c” vào NodeStack Cho “+”, “c” thành node con của “*” Push “*” vào node Stack Push “-“ vào OperatorStack Push “d” vào NodeStack
Bài tập thực hành CTDL & GT
Trang 87
/
-/
*d
Push “/” vào OperatorStack
e
-/
*de
Push “e” vào NodeStack
-/
*de
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 public bool { get { return this this.LeftChild .LeftChild == null && this this.RightChild .RightChild == null null;; } } public BinaryTreeNode(string BinaryTreeNode(string value) { Value = value; } } class Expression { static string Infix2Prefix(string Infix2Prefix(string infix) { List< List > prefix = new List List< (); >(); Stack > stack = new Stack (); >(); for (int i=0;i
Bài tập thực hành CTDL & GT
stack.Push(infix[i].ToString()); else if if (infix[i] (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 (); StringBuilder str (); for ((int i = prefix.Count - 1; i >= 0; i--) for { str.Append(prefix[i]); } return str.ToString(); } static double EvaluateExpressionTree(BinaryTreeNode EvaluateExpressionTree(BinaryTreeNode node) { double t = 0; if (node.IsLeaf) if (node.IsLeaf) t = double double.Parse(node.Value); .Parse(node.Value); else { double x = EvaluateExpressionTree(node.LeftChild); double y = EvaluateExpressionTree(node.RightChild); switch (node.Value) { case "+" "+":: t = x + y; break y; break ; case "-" "-":: t = x - y; break y; break ; case "*" "*":: t = x * y; break y; break ; case "/" "/":: t = x / y; break y; break ; case "%" "%":: t = x % y; break y; break ;
Trang 88
Bài tập thực hành CTDL & GT
Trang 89
} } return t; } static void CreateSubTree(Stack CreateSubTree(Stack > opStack, Stack > nodeStack) { BinaryTreeNode node = opStack.Pop(); node.RightChild = nodeStack.Pop(); node.LeftChild = nodeStack.Pop(); nodeStack.Push(node); } static BinaryTreeNode Infix2ExpressionTree(string Infix2ExpressionTree(string infixExpression) { List< List > prefix = new List List< (); >(); Stack > operatorStack = new Stack (); >(); Stack > nodeStack = new Stack (); >(); for ((int i = 0; i < infixExpression.Length; ++i) for { if (IsOperator(infixExpression[i])) if (IsOperator(infixExpression[i])) { while (operatorStack.Count > 0 && Priority(operatorStack.Peek().Value) >= Priority(infixExpression[i].ToString())) CreateSubTree(operatorStack, nodeStack); operatorStack.Push(new operatorStack.Push(new BinaryTreeNode BinaryTreeNode(infixExpression[i].ToString())); (infixExpression[i].ToString())); } else if if (infixExpression[i] (infixExpression[i] == '(' '(')) operatorStack.Push(new operatorStack.Push(new BinaryTreeNode BinaryTreeNode(infixExpression[i].ToString())); (infixExpression[i].ToString())); else if if (infixExpression[i] (infixExpression[i] == ')' ')')) { while (operatorStack.Peek().Value != "(" "(")) CreateSubTree(operatorStack, nodeStack); operatorStack.Pop(); } else nodeStack.Push(new nodeStack.Push(new BinaryTreeNode BinaryTreeNode(infixExpression[i].ToString())); (infixExpression[i].ToString())); } while (operatorStack.Count > 0) CreateSubTree(operatorStack, nodeStack); return nodeStack.Peek(); } static bool static bool IsOperator(char IsOperator(char str) str) { return str == '+' || str == '-' || str == '*' || str == '/' '/';;
Bài tập thực hành CTDL & GT
Trang 90
} static bool IsOperand(char static bool IsOperand(char str) str) { return str >= '0' && str <= '9' '9';; } public static int Priority(string Priority(string op) { if (op if (op == "*" || op == "/" "/")) return 2; if (op if (op == "+" || op == "-" "-")) return 1; return 0; } static void LRN(BinaryTreeNode LRN(BinaryTreeNode p) //phuong thuc duyet cay nhi phan { if (p if (p != null null)) { LRN (p.LeftChild); LRN (p.RightChild); Console.Write( Console .Write("{0} "{0} -> ", ", p.Value); } } static void Main() { string x = "(5-3)*(3+1)/2" "(5-3)*(3+1)/2";; BinaryTreeNode s = Expression Expression.Infix2ExpressionTree(x); .Infix2ExpressionTree(x); Console.WriteLine( Console .WriteLine(Expression Expression.EvaluateExpressionTree(s)); .EvaluateExpressionTree(s)); Expression.. LRN (s); Expression Console.ReadKey(); 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.
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
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 ý:
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. (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.
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 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.
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 nó *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.
Bài tập thực hành CTDL & GT
BÀI THỰC HÀNH 10.
Trang 96
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