Phân tích số m thành tổng các phần tử của dãy không dùng lặp lại và đưa ra cách phân tích có ít số hạng nhất... Bài tập thực hành môn CTDL> Trang 10 Bài 10: Thực hành cài đặt danh sách
Trang 1TRƯỜ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 Ngành đào tạo
: :
Đại học chính quy
CNTT, KTPM, KHMT
Hưng Yên, năm 2021
Trang 2Bài tập thực hành môn CTDL> Trang 2
MỤC LỤC
Bài 9: Thực hành cài đặt giải thuật đệ quy 3
Bài 10: Thực hành cài đặt danh sách bằng mảng 10
Bài 11: Thực hành cài đặt danh sách bằng danh sách liên kết đơn 17
Bài 12: Thực hành cài đặt danh sách Stack, Queue 23
Bài 13: Thực hành cài đặt cây nhị phân 33
Bài 14: Thực hành cài đặt các giải thuật sắp xếp - tìm kiếm 35
Trang 3Bài 9: Thực hành cài đặt giải thuật đệ quy Mục tiêu: Sau khi học xong bài này người học có khả năng:
- Cài đặt được giải thuật đệ qui theo yêu cầu của các bài toán
- Giải thích được trình tự máy tính thực hiện khi thực thi các chương trình
Từ công thức tính số fibonaci thứ n mà bài toán đặt rat a nhận thấy
- Trường hợp suy biến của bài toán xảy ra khi n<2 ta có f(n) =n
- Trường hợp đệ quy xảy ra khi n>1:
Trang 4Bài tập thực hành môn CTDL> Trang 4
LƯU PHẦN TỬ VÀO NGHIỆM;
GHI NHẬN TRẠNG THÁI MỚI CỦA BÀI TOÁN;
Theo yêu cầu của bài toán ta có thuật giải cho bài toán :
- Mảng luu để lưu giá trị của chuỗi nhị phân
- Đầu tiên ta sẽ tìm giá trị gán cho bít k=1 của chuỗi (là 0 or 1), sau đó gọi đệ quy tìm giá trị gán cho bít k=2, …
- Lời gọi đệ quy kết thúc khi k== n+1 (nghĩa là ta đã thực hiện gán được giá trị cho n bít) khi đó sẽ hiển thị ra kết quả của chuỗi nhị phân
Trang 5Lời giải mẫu
static int[] luu;
// Hien thi ket qua ra man hinh
static void Xuat(int[] luu)
// Thuc hien tao xau nhi phan voi do dai k
static void Tao(int k)
d = d + 1; // Dem so luong xau nhi phan duoc tao thanh
Xuat(luu); // Hien thi xau nhi phan ra man hinh
}
else
for (j = 0; j <= 1; j++)
{
luu[k-1] = j; // gan gia tri cho bit thu k
Tao(k + 1); // Tao xau nhi phan co do dai k+1
Trang 6Bài tập thực hành môn CTDL> Trang 6
Kết quả chạy chương trình
- Ta nhận thấy trường hợp suy biến: n=1 khi đó hàm nhận giá trị là 1
- Trường hợp đệ qui: n>1 khi đó ta có S(n) = S(n-1) +n
Bài 2: Tính S(n) = 1 + 22+ 32+ ….+ (n-1)2 + n2
Gợi ý:
- Ta nhận thấy trường hợp suy biến: n=1 khi đó hàm nhận giá trị là 1
- Trường hợp đệ qui: n>1 khi đó ta có S(n) = S(n-1) +n2
Bài 3: Tính S(n) = 1 + 1/2+ 1/3+ ….+1/ (n-1) +1/ n
Gợi ý:
- Ta nhận thấy trường hợp suy biến: n=1 khi đó hàm nhận giá trị là 1
- Trường hợp đệ qui: n>1 khi đó ta có S(n) = S(n-1) + 1.0/n
Bài 4: Tính S(x, n) = xn
Gợi ý: Ta xây dựng hàm LuyThua(X, N) để tính XN với N dương
- Ta nhận thấy trường hợp suy biến: N=0 khi đó hàm nhận giá trị là 1
- Trường hợp đệ qui: N > 0 khi đó ta có LuyThua(X, N) = LuyThua(X, 1)*X
N-Hàm S(x, n) sẽ được định nghĩa như sau:
double S(x, n){
Trang 7if(n<0) return 1.0/LuyThua(x, -n);
else return LuyThua(x, n);
}
Bài 5: Tìm ước số lẻ lớn nhất của số nguyên dương n Ví dụ : n = 100 ước lẻ lớn
nhất của 100 là 25
Gợi ý:
- Ta nhận thấy trường hợp suy biến: Nếu n%2==1 khi đó UocLeMax(n)= n
- Trường hợp đệ qui: Ngược lại ta có UocLeMax(n) = UocLeMax(n/2)
Bài 6: Tìm ước chung lớn nhất của 2 số nguyên dương a,b
Gợi ý: Theo thuật toán Euclid:
- Ta nhận thấy trường hợp suy biến: Nếu a%b ==0 thì UCLN(a, b) =b
- Trường hợp đệ qui: ngược lại thì UCLN(a, b)= UCLN(b, a%b)
Bài 7: Đếm số chữ số của số nguyên dương n
Gợi ý:
- Ta nhận thấy trường hợp suy biến: Nếu n==0 thì SoChuSo(n) =0
- Trường hợp đệ qui: ngược lại thì SoChuSo(n) = SoChuSo(n/10) +1
Bài 8: Tính S(n) = √1 + √2 + √3 + √4 + ⋯ … + √𝑛 − 1 + √𝑛
Gợi ý:
Ta có giải thuật tính tổng căn như sau:
float Can(int i, int n){
Trang 8Bài tập thực hành môn CTDL> Trang 8
Bài 9: Hãy viết giải thuật cho bài toán: phân tích số N thành tổng các số tự nhiên
Viết chương trình hiển thị ra tất cả các cách có thể để phân tích số N thành tổng các số tự nhiên
Gợi ý
5 = 1+4; =2+3=0+5
Theo yêu cầu của bài toán ta có thuật giải cho bài toán :
- Mảng luu để lưu giá trị của các các số hạng được phân tích; tối đa có Số N được phân tích thành tổng có tối đa N số hạng, và ta cần 1 phần tử đầu tiên của mảng làm cờ; do đó Ta cần tạo luu là mảng có N+1 phần tử và được khởi gán giá trị ban đầu là 0
- Giả sử t là giá trị số được phân tích tính đến bước hiện tại, t ban đầu được khởi gán bằng 0
- Đầu tiên ta sẽ tìm giá trị gán cho số hạng đầu tiên (k=1), rồi gọi đệ quy tìm giá trị cho số hạng k = 2, quá trình đệ qui kết thúc khi t ==
N(nghĩa là ta đã thực hiện tìm được lời giải) khi đó sẽ hiển thị ra kết quả
của phép phân tích
Giải thuật để phân tích số n thành tổng các số tự nhiên
// k là số lượng số hạng được phân tích của tổng
void Tao( int k)
Trang 9Bài 10:
Cho dãy số nguyên a1, a2, a3, an; và một số nguyên Phân tích số m thành tổng các phần tử của dãy không dùng lặp lại và đưa ra cách phân tích có ít số hạng nhất
Gợi ý
- Mảng Kt để đánh dấu phần tử của mảng a đa được sử dụng, kt[i] = false
nghĩa là a[i] đã được sử dụng, không thể dùng được nữa
- Mảng luu để lưu nghiệm hiện tại
- Mảng mluu để lưu nghiệm tối ưu thỏa mãn yêu cầu bài toán
- Min để lưu số lượng phần tử ít nhất dùng để phân tích số m, min được
khởi gán bởi giá trị min = 0
Thuật toán đệ qui tìm nghiệm tối ưu
của bài toán
Thuật toán hiển thị kết quả nghiệm tối ưu
static void Tao( int k) {
t = t - a[j];
kt[j] = true; luu[k]=0;
}
}
static void Xuat(){
if(min==0) Console.Write("Khong co cach phan tich thoa man yeu cau bai toan");
Bài 11: Viết giải thuật đệ qui tìm USCLN của 2 số nguyên, áp dụng viết chương
trình thực hiện nhập 2 số nguyên từ bàn phím, hiển thị ra màn hình USCLN,
BSCNN của 2 số nguyên đó
Trang 10Bài tập thực hành môn CTDL> Trang 10
Bài 10: Thực hành cài đặt danh sách bằng mảng Mục tiêu:
- Hệ thống lại các kiến thức về mảng như: cách khai báo, cách thức tổ chức dữ liệu trên mảng, các thao tác trên mảng
- Áp dụng các kiến thức về mảng để cài đặt được bài toán lưu trữ danh sách và thực hiện các thao tác trên mảng
- Có khả năng nhận xét các ưu, nhược điểm khi cài đặt danh sách bằng mảng
Bài tập mẫu:
Bài 1: Cho n số nguyên dương a0,a1,a2, ,an-1
a.Chèn phần tử x vào vị trí k của dãy
b.Xóa tất cả các số nguyên tố trong dãy
Gợi ý:
a.Khởi tạo một mảng trung gian tmp có độ dài là (a.Length+1) sau đó gán các giá trị : tmp[i]=a[i] với i từ 0 ->k-1 (k-1 là vị trí trước vị trí cần chèn) tmp[k]=giá trị cần chèn
tmp[i+1]=a[i] với i từ k->a.Length-1
Cuối cùng gán mảng a=tmp
b.Thực hiện duyệt các phần tử trong mảng kiểm tra xem phần tử đó có phải là số nguyên tố hay không (số nguyến tố là số chỉ chia hết cho 1 và chính nó) :
+ Nếu là số nguyên tố: Duyệt mảng từ trái sang phải.Từ vị trí số nguyên tố
đó tiến hành dời các phần tử về phía trước cho đến khi kết thúc mảng, sau
đó giảm kích thước mảng
+Ngược lại, chuyển sang kiểm tra phần tử kế tiếp
Lời giải mẫu
using System;
classVD
{
staticint[] a; //Mảng a chứa các phần tử số nguyên
staticvoid Nhap()
{
int n;
Trang 11Console.Write("Nhap n=");
n = int.Parse(Console.ReadLine());
a = newint[n]; //Cấp phát cho mảng a số phần tử là n
for (int i = 0; i < a.Length; ++i)
{
Console.Write("a[" + i + "]=");
a[i] = int.Parse(Console.ReadLine());
bool ok = true; //ban đầu giả sử x là số nguyên tố
for (int i = 2; i < x - 1; ++i) // duyệt i từ 2 đến x-1 xem x có chia hết cho số nào không
if (x % i == 0) { ok = false; break; } //nếu x chia hết cho I thì x không phải là số nguyên tố return ok;
}
Trang 12Bài tập thực hành môn CTDL> Trang 12
staticvoid Xoa()
int[] tmp = newint[n]; //mảng sau khi xóa có kích thước bằng n mới
for (int i = 0; i < n; ++i)
Trang 13- Hơn nữa, khi khai báo chúng ta đã cấp phát cho mảng số phần tử cố định Vì thế, khi thêm các phần tử vào mảng sẽ dẫn đến không đủ bộ nhớ, còn khi xóa các phần tử trong mảng sẽ dẫn đến thừa bộ nhớ (lãng phí bộ nhớ)
Bài tập thực hành
Bài 1: Cho ma trận vuông n dòng và n cột; các phần tử là các số nguyên (0≤ n <
100) Viết các hàm thực hiện các yêu cầu sau:
a.Tính tổng tất cả các phần tử của ma trận
b.Tìm giá trị dương nhỏ nhất của ma trận
c.Tính tổng các phần tử nằm trên đường chéo phụ
d.Kiểm tra xem các phần tử nằm trên đuờng chéo chính có tăng dần hay không ? (theo chiều từ góc trên bên trái xuống góc dưới bên phải)
Gợi ý:
a Khởi tạo 1 giá trị t=0.Sau đó duyệt qua từng phần tử của ma trận , thực hiện cộng t với từng phần tử trong ma trận:
b Khởi tạo giá trị min bằng dương vô cùng int min = int.MaxValue;
Thực hiện duyệt qua các phần tử của ma trận, nếu thấy phần tử đó nhỏ hơn min và lớn hơn 0 thì gán vào min
c.Ta nhận thấy rằng các phần tử a[i,j] thuộc đường chéo chính của ma trận cấp n thì có j=(n-1)-i với i ,j chạy từ 0 ->n-1
Để tính tổng các phần tử đường chéo phụ ta duyệt qua các phần tử a[i,j] của ma trận nếu phần tử nào thỏa mãn j=(n-1)-i thì ta thực hiện cộng các phần tử đó lại
d.Ta thấy trong ma trận cấp n thì số phần tử trên đường chéo chính la n + Đầu tiên , ta thực hiện việc khai báo một mảng một chiều []tg có n phần
tử chứa các phần tử a[i,j] trên đường chéo chính của ma trận(với i=j) theo chiều từ góc bên trái phía trên đến bên phải phía dưới
Trang 14Bài tập thực hành môn CTDL> Trang 14
+ 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 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,
a.Tính tổng thực lĩnh tháng của tất cả nhân viên trong công ty
b In danh sách những nhân viên có mức lương cơ bản thấp nhất
c Đếm số lượng nhân viên có mức thưởng >= 1200000
d In danh sách các nhân viên tăng dần theo phòng ban, nếu phòng ban trùng nhau thì giảm dần theo mã nhân viên
e Cập nhật tăng lương của tất cả các nhân viên lên 5%
Gợi ý: Để lưu trữ thông tin của từng nhân viên ta khai báo một trường lưu trữ các
thông tin
structNhanVien
{
publicstring MaNV;
publicstring Hoten;
publicint Namsinh;
publicstring Phongban;
publicint LuongCB;
publicint Thuong;
}
Trang 15b Đầu tiên ta gán một biến min=int.MaxValue(giá trị dương vô cùng)
+Tiếp theo duyệt qua tất cả các nhân viên kiểm tra xem min>DS[i].LuongCB hay
không?
- Nếu thoả mãn min = DS[i].LuongCB
- Ngược lại,tiếp tục duyệt các nhân viên tiếp theo
+ Khi kết thúc vòng lặp kiểm tra đó ta sẽ tìm được danh sách những người có mức lương cơ bản thấp nhất
Bài 3: Hãy viết chương trình quản lý điểm cho các sinh viên trong lớp
Thông tin sinh viên bao gồm:
- Mã sinh viên
- Họ và tên
- Năm sinh (số nguyên)
- Giới tính (‘Nam’ hoặc ‘Nữ’)
Trang 16Bài tập thực hành môn CTDL> Trang 16
- Tên học phần
- Số tín chỉ
- Điểm học phần
a Hãy nhập thông tin về các sinh viên
b Hãy nhập thông tin về điểm của từng học, từng sinh viên
c Hiển thị thông tin về điểm của các sinh viên
Thông tin hiển thị bao gồm:
Tên học phần
Số tín chỉ
Điểm học phần
d Hiển thị thông tin về điểm trung bình chung của từng sinh viên
e Hiển thị danh sách sinh viên đủ điều kiện nhận học bổng
SV đủ điều kiện nhận học bổng: Không có học phần nào có điểm HP <5
f Hiển thị thông tin sinh viên có điểm trung bình chung cao nhất
Trang 17Bài 11: Thực hành cài đặt danh sách bằng danh sách liên kết đơn Mục tiêu:
- Trình bày được cấu trúc của mỗi nút trong danh sách liên kết đơn
- Khai báo được các thành phần của mỗi nút, các biến liên quan trong danh sách
- Cài đặt được các thao tác cơ bản trên danh sách như: khởi tạo, nhập dữ liệu, thêm, xóa phần tử trong danh sách, duyệt, tìm kiếm phần tử thỏa mãn điều kiện
- Nhận xét được ưu, nhược điểm khi cài đặt danh sách bằng lưu trữ móc nối
A Bài tập mẫu
Bài 1: Cho một danh sách liên kết đơn (có pHead 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 pHead
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=pHead, 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
Trang 18Bài tập thực hành môn CTDL> Trang 18
Lời giản mẫu
public int info;
public Node link;
}
class Program
{
static Node pHead = new Node();
// pHead dùng để chứa địa chỉ của nút đầu tiên trong danh sách static void Nhap()
{
Console.WriteLine( "Nhap vao day so nguyen" );
int i = 0; pHead = null; Node tg;
// bổ sung nút tg vào đầu danh sách list
if (pHead == null) pHead = tg;
else { tg.link = pHead ; pHead = tg; }
Console.Write( "Ban nhap tiep C/K " );
Trang 19Node t = p;//t chứa địa chỉ nút đứng trước nút p
//tìm p chứa địa chỉ nút có info là x
while (p != null && p.info != x)
if (p == pHead ) pHead = pHead.link;
else if (p.link == null) t.link = null;
else t.link = p.link;
Trang 20Bài tập thực hành môn CTDL> Trang 20
Nhận xét:
- Khi thêm hay xóa các phần tử trong danh sách, chúng ta chỉ cần xác định lại các mối liên kết giữa phần tử đó với các phần tử đứng trước và sau phần tử đó (nếu có) mà không ảnh hưởng đến các phần tử còn lại Như vậy, số thao tác cần thực hiện so với thao tác thêm, xóa trên mảng là ít hơn
- Hơn nữa, bộ nhớ lưu trữ các phần tử trong danh sách được cấp phát động, nghĩa
là khi cần thì cấp phát, khi không cần thì thu hồi lại nên rất linh hoạt Từ đó, tránh được nhược điểm thiếu hay tràn bộ nhớ của mảng
- Nhược điểm của danh sách liên kết: muốn truy nhập tới một phần tử thứ n ta phải duyệt từ đầu qua n-1 phần tử
Bài tập thực hành
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
a Tìm phần tử lớn nhất danh sách l
b Tính tổng các phần tử của danh sách l
c Đếm xem trong danh sách l có bao nhiêu số nguyên tố ?
d Đếm xem trong danh sách có bao nhiêu số âm ? bao nhiêu số bằng 0 ? bao nhiêu số dương ?
e Đếm xem trong danh sách có bao nhiêu số bằng x ?
f Tìm phần tử dương nhỏ nhất trong danh sách
Gợi ý: Khai báo danh sách toàn cục l
a Khởi tạo giá trị max=int.MinValue Duyệt qua các phần tử của danh sách tại mỗi phần tử so sánh với max, nếu lớn hơn max gán max bằng phần tử đó
b Khởi tạo t=0 Duyệt qua các phần tử của danh sách và thực hiện cộng dồn các giá trị của nó vào t
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