Lab 03 — Điểm học phần, Sinh viên, HCN
LAB 03 — GIẢI CHI TIẾT (ĐIỂM HỌC PHẦN, SINH VIÊN, HÌNH CHỮ NHẬT)
Nguồn:
lab03.doc(Bài thực hành số 3). Bám lý thuyết buổi 8, 10, 11. Gồm 3 phần: bài chính (Diem+SinhVien), phần mở rộng (nhiều học phần), bài ở nhà (Diemtoạ độ +HCN).
0. Bản đồ bài làm
| Phần | Lớp | Tệp | Quan hệ |
|---|---|---|---|
| Chính | Diem, SinhVien |
Diem.java, SinhVien.java,
QuanLySV.java |
HAS-A (SinhVien có 2 Điểm) |
| Mở rộng | SinhVienMoRong |
SinhVienMoRong.java + QuanLySV2.java |
HAS-A với mảng |
| Ở nhà | DiemToaDo, HCN |
DiemToaDo.java, HCN.java,
QuanLyHCN.java |
HAS-A (HCN có 2 điểm) |
Cảnh báo trùng tên: bài chính có lớp
Diem(điểm học phần), bài ở nhà cũng có lớpDiem(toạ độ). Trong tài liệu này bài ở nhà dùng tênDiemToaDođể hai lớp không đè nhau trong cùng thư mục. Khi nộp, bạn có thể đổi lại thànhDiemvà để trong thư mục riêng.
PHẦN 1 — Diem VÀ
SinhVien
0. Đề bài
Khai báo lớp Diem: tenHocPhan,
soTinChi (1..4), chuyenCan,
giuaKy, cuoiKy (0..10); constructor;
tinhDiem() theo tỷ lệ 10% – 20% – 70%. Khai báo lớp
SinhVien: hoTen, dm1,
dm2 (hai Diem); constructor;
tinhDTB() trung bình theo tín chỉ. Tạo mảng 3 sinh viên, in
thông tin và điểm trung bình.
1. Yêu cầu ẩn
soTinChingoài 1..4 phải bị từ chối; điểm ngoài 0..10 phải bị từ chối (buổi 10).- Tổng tín chỉ bằng 0 (nếu dữ liệu sai) → không được chia 0.
tinhDTBkhông phải trung bình cộng đơn giản: phải nhân trọng số tín chỉ.- In điểm nên làm tròn 2 chữ số, tránh
7.480000000000001.
2. Input → Output
| Lớp | Thuộc tính | Kiểu | Miền | Phương thức chính |
|---|---|---|---|---|
Diem |
tenHocPhan | String | khác rỗng | tinhDiem() |
| soTinChi | int | 1..4 | ||
| chuyenCan/giuaKy/cuoiKy | double | 0..10 | ||
SinhVien |
hoTen | String | tinhDTB() |
|
| dm1, dm2 | Diem | object hợp lệ |
3. Thiết kế
Diem SinhVien
- tenHocPhan : String - hoTen : String
- soTinChi : int - dm1 : Diem
- chuyenCan, giuaKy, cuoiKy - dm2 : Diem
+ Diem(ten, tc) + SinhVien(hoTen, dm1, dm2)
+ set/get (co kiem tra) + tinhDTB() : double
+ tinhDiem() : double + toString()
+ toString() : String
^ |
| | chứa (HAS-A)
+-----------------------------------+
Quyết định thiết kế:
- HAS-A, không phải IS-A:
SinhViencó điểm, không là điểm → dùng thuộc tính, khôngextends. - Constructor
Diem(ten, tc)gọi setter để dùng chung logic kiểm tra (tránh viết 2 lần). tinhDTB()đặt trongSinhVien(không phảiDiem) vì nó phụ thuộc nhiều học phần.
4. Code từng bước
Bước 1 — khung Diem + constructor có kiểm
tra.
public class Diem {
private String tenHocPhan;
private int soTinChi;
private double chuyenCan, giuaKy, cuoiKy;
public Diem(String tenHocPhan, int soTinChi) {
this.tenHocPhan = tenHocPhan;
setSoTinChi(soTinChi);
}
public void setSoTinChi(int tc) {
if (tc >= 1 && tc <= 4) this.soTinChi = tc;
}Bước 2 — setter cho 3 loại điểm (cùng một điều kiện).
public void setChuyenCan(double d) { if (d >= 0 && d <= 10) chuyenCan = d; }
public void setGiuaKy(double d) { if (d >= 0 && d <= 10) giuaKy = d; }
public void setCuoiKy(double d) { if (d >= 0 && d <= 10) cuoiKy = d; }Bước 3 — công thức tính điểm +
toString.
public double tinhDiem() {
return chuyenCan * 0.1 + giuaKy * 0.2 + cuoiKy * 0.7;
}
@Override
public String toString() {
double d = Math.round(tinhDiem() * 100) / 100.0;
return tenHocPhan + " (" + soTinChi + " TC): " + d;
}Bước 4 — SinhVien và công thức trung bình có
trọng số.
public class SinhVien {
private String hoTen;
private Diem dm1, dm2;
public SinhVien(String hoTen, Diem dm1, Diem dm2) {
this.hoTen = hoTen;
this.dm1 = dm1;
this.dm2 = dm2;
}
public double tinhDTB() {
int tc1 = dm1.getSoTinChi(), tc2 = dm2.getSoTinChi();
if (tc1 + tc2 == 0) return 0; // chan chia 0
return (dm1.tinhDiem() * tc1 + dm2.tinhDiem() * tc2) / (tc1 + tc2);
}
}5. Lời giải hoàn chỉnh
// ===== Diem.java =====
public class Diem {
private String tenHocPhan;
private int soTinChi;
private double chuyenCan, giuaKy, cuoiKy;
public Diem(String tenHocPhan, int soTinChi) {
this.tenHocPhan = tenHocPhan;
setSoTinChi(soTinChi);
}
public String getTenHocPhan() { return tenHocPhan; }
public int getSoTinChi() { return soTinChi; }
public void setSoTinChi(int tc) {
if (tc >= 1 && tc <= 4) this.soTinChi = tc;
}
public double getChuyenCan() { return chuyenCan; }
public void setChuyenCan(double d) { if (d >= 0 && d <= 10) chuyenCan = d; }
public double getGiuaKy() { return giuaKy; }
public void setGiuaKy(double d) { if (d >= 0 && d <= 10) giuaKy = d; }
public double getCuoiKy() { return cuoiKy; }
public void setCuoiKy(double d) { if (d >= 0 && d <= 10) cuoiKy = d; }
public double tinhDiem() {
return chuyenCan * 0.1 + giuaKy * 0.2 + cuoiKy * 0.7;
}
@Override
public String toString() {
double d = Math.round(tinhDiem() * 100) / 100.0;
return tenHocPhan + " (" + soTinChi + " TC): " + d;
}
}// ===== SinhVien.java =====
public class SinhVien {
private String hoTen;
private Diem dm1, dm2;
public SinhVien(String hoTen, Diem dm1, Diem dm2) {
this.hoTen = hoTen;
this.dm1 = dm1;
this.dm2 = dm2;
}
public String getHoTen() { return hoTen; }
public Diem getDm1() { return dm1; }
public Diem getDm2() { return dm2; }
public double tinhDTB() {
int tc1 = dm1.getSoTinChi();
int tc2 = dm2.getSoTinChi();
if (tc1 + tc2 == 0) return 0;
return (dm1.tinhDiem() * tc1 + dm2.tinhDiem() * tc2) / (tc1 + tc2);
}
@Override
public String toString() {
double dtb = Math.round(tinhDTB() * 100) / 100.0;
return hoTen + " | " + dm1 + " | " + dm2 + " | DTB = " + dtb;
}
}// ===== QuanLySV.java =====
public class QuanLySV {
static Diem taoDiem(String ten, int tc, double cc, double gk, double ck) {
Diem d = new Diem(ten, tc);
d.setChuyenCan(cc);
d.setGiuaKy(gk);
d.setCuoiKy(ck);
return d;
}
public static void main(String[] args) {
Diem d1 = taoDiem("Lap trinh Java", 3, 9, 8, 7);
Diem d2 = taoDiem("Toan roi rac", 2, 6, 7, 8);
Diem d3 = taoDiem("Co so du lieu", 3, 10, 9, 8);
Diem d4 = taoDiem("Ky nang mem", 2, 5, 6, 5);
Diem d5 = taoDiem("Cau truc du lieu", 4, 7, 7, 7);
Diem d6 = taoDiem("Thuc tap", 1, 8, 9, 10);
SinhVien[] ds = new SinhVien[3];
ds[0] = new SinhVien("Nguyen Van An", d1, d2);
ds[1] = new SinhVien("Tran Thi Binh", d3, d4);
ds[2] = new SinhVien("Le Van Chi", d5, d6);
for (int i = 0; i < ds.length; i++) {
System.out.println(ds[i]);
}
// kiem tra validation: gan diem sai
d1.setCuoiKy(15);
System.out.println("Cuoi ky sau khi gan 15: " + d1.getCuoiKy());
}
}6. Cách chạy
javac Diem.java SinhVien.java QuanLySV.java
java QuanLySV
7. Kết quả chạy mẫu
Nguyen Van An | Lap trinh Java (3 TC): 7.4 | Toan roi rac (2 TC): 7.6 | DTB = 7.48
Tran Thi Binh | Co so du lieu (3 TC): 8.4 | Ky nang mem (2 TC): 5.2 | DTB = 7.12
Le Van Chi | Cau truc du lieu (4 TC): 7.0 | Thuc tap (1 TC): 9.6 | DTB = 7.52
Cuoi ky sau khi gan 15: 7.0
Kiểm tra tay:
9×0.1 + 8×0.2 + 7×0.7 = 0.9 + 1.6 + 4.9 = 7.4✓(7.4×3 + 7.6×2)/5 = (22.2 + 15.2)/5 = 7.48✓- Chi:
(7.0×4 + 9.6×1)/5 = (28 + 9.6)/5 = 7.52✓
8. Bảng kiểm thử
| # | Ca | Kỳ vọng |
|---|---|---|
| 1 | tc = 3, 9/8/7 |
7.4 |
| 2 | tc = 4 với 7/7/7 |
7.0 |
| 3 | setSoTinChi(5) |
giữ nguyên giá trị cũ |
| 4 | setCuoiKy(15) |
giữ nguyên |
| 5 | Tổng tín chỉ 0 (dữ liệu sai) | tinhDTB() trả 0, không chia 0 |
9. Trace
SV "Le Van Chi":
| Bước | tc1 |
tc2 |
diem1 |
diem2 |
Tử số | Mẫu | DTB |
|---|---|---|---|---|---|---|---|
| lấy giá trị | 4 | 1 | 7.0 | 9.6 | — | — | — |
| nhân trọng số | 28.0 | 9.6 | 37.6 | 5 | 7.52 |
10. Lỗi thường gặp
| Code sai | Thông báo / hiện tượng | Sửa |
|---|---|---|
tinhDTB = (d1 + d2)/2 |
Sai khi số tín chỉ khác nhau | Nhân trọng số |
class SinhVien extends Diem |
Vô nghĩa về mô hình | Dùng thuộc tính (HAS-A) |
Gán d1.cuoiKy = 15 |
cuoiKy has private access |
Dùng setter |
setSoTinChi không kiểm tra |
soTinChi = 0 → chia 0 |
Kiểm tra 1..4 |
In d1 không có toString |
Diem@1b6d3586 |
Override toString |
return (d1*3 + d2*2) / 5; với double |
Không sai nhưng cứng nhắc | Dùng tc1, tc2 |
11. Câu hỏi kiểm tra hiểu
- Vì sao
SinhVienkhông nênextends Diem? - Nếu hai học phần cùng 3 tín chỉ, công thức rút gọn thành gì?
- Vì sao constructor
Diemnên gọisetSoTinChithay vì gán trực tiếp?
12. Mở rộng
- Thêm
getXepLoai()vàoSinhVien(≥8 Giỏi, ≥7 Khá, ≥5 TB, còn lại Yếu). - Sắp xếp mảng sinh viên theo DTB giảm dần.
- In bảng điểm dạng cột (dùng
\t).
TỰ KIỂM TRA 60 GIÂY: SinhVien và
Diem là IS-A hay HAS-A? 9/8/7 với 3 tín chỉ ra
bao nhiêu? Ai kiểm tra điểm 0..10?
PHẦN 2 — MỞ RỘNG: NHIỀU HỌC PHẦN
0. Đề bài (phần "Mở rộng")
Một sinh viên có thể học nhiều học phần; mở rộng
SinhVien để lưu được điểm nhiều học phần và tính DTB.
1. Yêu cầu ẩn
- Không biết trước số học phần → dùng mảng + biến đếm
soHP. - Phải chặn thêm quá sức chứa.
- Nếu
soHP = 0→ DTB = 0, không chia 0. - Công thức:
Σ(diem_i × tc_i) / Σ(tc_i).
2. Thiết kế
SinhVienMoRong
- hoTen : String
- dsHP : Diem[]
- soHP : int
+ themHP(Diem) : boolean
+ tinhDTB() : double
3–4. Các bước chính
Bước 1 — thêm học phần có kiểm tra sức chứa:
public boolean themHP(Diem d) {
if (d == null || soHP >= dsHP.length) return false;
dsHP[soHP] = d;
soHP++;
return true;
}Bước 2 — DTB có trọng số:
public double tinhDTB() {
double tongDiem = 0;
int tongTC = 0;
for (int i = 0; i < soHP; i++) {
tongDiem += dsHP[i].tinhDiem() * dsHP[i].getSoTinChi();
tongTC += dsHP[i].getSoTinChi();
}
return (tongTC == 0) ? 0 : tongDiem / tongTC;
}5. Lời giải hoàn chỉnh
// ===== SinhVienMoRong.java =====
public class SinhVienMoRong {
private String hoTen;
private Diem[] dsHP;
private int soHP;
public SinhVienMoRong(String hoTen, int soMonToiDa) {
this.hoTen = hoTen;
this.dsHP = new Diem[soMonToiDa];
this.soHP = 0;
}
public String getHoTen() { return hoTen; }
public int getSoHP() { return soHP; }
public boolean themHP(Diem d) {
if (d == null || soHP >= dsHP.length) return false;
dsHP[soHP] = d;
soHP++;
return true;
}
public double tinhDTB() {
double tongDiem = 0;
int tongTC = 0;
for (int i = 0; i < soHP; i++) {
tongDiem += dsHP[i].tinhDiem() * dsHP[i].getSoTinChi();
tongTC += dsHP[i].getSoTinChi();
}
return (tongTC == 0) ? 0 : tongDiem / tongTC;
}
@Override
public String toString() {
double dtb = Math.round(tinhDTB() * 100) / 100.0;
String s = hoTen + " (" + soHP + " hoc phan, DTB = " + dtb + ")\n";
for (int i = 0; i < soHP; i++) {
s += " " + dsHP[i] + "\n";
}
return s;
}
}// ===== QuanLySV2.java =====
public class QuanLySV2 {
public static void main(String[] args) {
SinhVienMoRong sv = new SinhVienMoRong("Nguyen Van An", 10);
Diem d1 = new Diem("Lap trinh Java", 3);
d1.setChuyenCan(9); d1.setGiuaKy(8); d1.setCuoiKy(7);
Diem d2 = new Diem("Toan roi rac", 2);
d2.setChuyenCan(6); d2.setGiuaKy(7); d2.setCuoiKy(8);
Diem d3 = new Diem("Co so du lieu", 3);
d3.setChuyenCan(10); d3.setGiuaKy(9); d3.setCuoiKy(8);
System.out.println("Them 1: " + sv.themHP(d1));
System.out.println("Them 2: " + sv.themHP(d2));
System.out.println("Them 3: " + sv.themHP(d3));
System.out.println("Them null: " + sv.themHP(null));
System.out.println(sv);
}
}6. Cách chạy
javac Diem.java SinhVienMoRong.java QuanLySV2.java
java QuanLySV2
7. Kết quả chạy mẫu
Them 1: true
Them 2: true
Them 3: true
Them null: false
Nguyen Van An (3 hoc phan, DTB = 7.82)
Lap trinh Java (3 TC): 7.4
Toan roi rac (2 TC): 7.6
Co so du lieu (3 TC): 8.4
Kiểm tra:
(7.4×3 + 7.6×2 + 8.4×3) / 8 = (22.2 + 15.2 + 25.2) / 8 = 62.6 / 8 = 7.825.
Nhưng máy in 7.82, không phải
7.83 — đây là bài học về số thực:
| Bước | Giá trị thực trong máy |
|---|---|
tinhDiem() của 9/8/7 |
7.3999999999999995 (không phải 7.4) |
| Nhân 3 | 22.199999999999999 |
| Tổng 3 môn | 62.599999999999994 |
| Chia 8 | 7.824999999999999 |
Math.round(x*100) |
782 → in 7.82 |
Vì 0.1, 0.2, 0.7 không biểu
diễn chính xác trong hệ nhị phân, kết quả hụt một chút
so với 782.5, nên làm tròn xuống. Muốn có 7.83
đúng như toán học, phải làm tròn từng điểm trước khi
tính DTB (hoặc dùng BigDecimal — ngoài phạm vi môn học).
Đây là lý do đề thi thường tránh các giá trị rơi đúng
.5.
8. Bảng kiểm thử
| # | Ca | Kỳ vọng |
|---|---|---|
| 1 | Thêm 3 học phần | true cả 3, DTB 7.82 (xem giải thích số thực ở mục
7) |
| 2 | Thêm null |
false |
| 3 | Thêm quá sức chứa | false |
| 4 | Chưa thêm gì | DTB = 0, không lỗi |
9. Trace tinhDTB
i |
diem |
tc |
tongDiem |
tongTC |
|---|---|---|---|---|
| 0 | 7.4 | 3 | 22.2 | 3 |
| 1 | 7.6 | 2 | 37.4 | 5 |
| 2 | 8.4 | 3 | 62.6 | 8 |
| kết thúc | 62.6 | 8 → 7.825 |
10. Lỗi thường gặp
| Code sai | Hiện tượng | Sửa |
|---|---|---|
dsHP = new Diem[10] rồi
dsHP[i].set... |
NullPointerException |
new Diem(...) trước |
return tongDiem / soHP |
Sai trọng số | Chia tongTC |
Không kiểm tra soHP >= length |
ArrayIndexOutOfBoundsException |
Kiểm tra |
themHP không tăng soHP |
Luôn ghi đè ô 0 | soHP++ |
11. Câu hỏi kiểm tra hiểu
- Vì sao phải có cả
dsHPvàsoHP, không dùngdsHP.length? - Nếu đề cho "tối đa 5 học phần", nên kiểm tra ở đâu?
- Công thức DTB có cần sắp xếp mảng không? Vì sao không?
12. Mở rộng
xoaHP(String ten),timHP(String ten).- Thêm
hocBong()nếu DTB ≥ 8 và không môn nào < 5. - Đổi
Diem[]thành mảng động (tự tăng kích thước khi đầy) — không dùngArrayList.
PHẦN 3 (Ở NHÀ) —
DiemToaDo VÀ HCN
0. Đề bài
Lớp Diem: x, y (số thực);
constructor; khoangCach(Diem p); toString()
dạng (x, y). Lớp HCN: d1,
d2 là góc trên-trái và dưới-phải; constructor;
chuVi(), dienTich(); toString()
dạng [(x1, y1), (x2, y2)]. Chương trình: mảng 5 hình chữ
nhật, in kèm chu vi/diện tích, sắp xếp theo diện tích tăng dần.
1. Yêu cầu ẩn
- Hai điểm có thể nhập "ngược" (d2 nằm trên-trái) → phải dùng trị tuyệt đối khi tính cạnh.
toStringphải đúng định dạng(x, y)và[(x1, y1), (x2, y2)].- Sắp xếp theo diện tích → cần so sánh hai hình;
không so sánh object bằng
>. - Trùng diện tích → giữ thứ tự (sắp xếp ổn định) hoặc không quan trọng, nhưng phải nói rõ.
2. Input → Output
| Vào | Kiểu | Ra |
|---|---|---|
x, y |
double |
điểm |
d1, d2 |
Diem |
chuVi, dienTich |
3. Thiết kế
DiemToaDo HCN
- x, y : double - d1, d2 : DiemToaDo
+ DiemToaDo(x, y) + HCN(d1, d2)
+ khoangCach(Diem) + chieuDai() : double
+ toString() + chieuRong() : double
+ chuVi(), dienTich()
+ toString()
HCN có hai điểm (HAS-A). Thêm
chieuDai/chieuRong là phương thức phụ trợ
private/public để tránh lặp công thức ở
chuVi và dienTich.
4. Code từng bước
Bước 1 — DiemToaDo + khoảng cách.
public double khoangCach(DiemToaDo p) {
double dx = this.x - p.x;
double dy = this.y - p.y;
return Math.sqrt(dx * dx + dy * dy);
}
@Override
public String toString() { return "(" + x + ", " + y + ")"; }Bước 2 — cạnh của HCN (dùng trị tuyệt đối).
public double chieuDai() { return Math.abs(d2.getX() - d1.getX()); }
public double chieuRong() { return Math.abs(d2.getY() - d1.getY()); }Bước 3 — chu vi, diện tích.
public double chuVi() { return 2 * (chieuDai() + chieuRong()); }
public double dienTich() { return chieuDai() * chieuRong(); }Bước 4 — sắp xếp theo diện tích (bubble sort với
dienTich()).
5. Lời giải hoàn chỉnh
// ===== DiemToaDo.java =====
public class DiemToaDo {
private double x, y;
public DiemToaDo(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() { return x; }
public double getY() { return y; }
public double khoangCach(DiemToaDo p) {
double dx = this.x - p.x;
double dy = this.y - p.y;
return Math.sqrt(dx * dx + dy * dy);
}
@Override
public String toString() { return "(" + x + ", " + y + ")"; }
}// ===== HCN.java =====
public class HCN {
private DiemToaDo d1; // goc tren trai
private DiemToaDo d2; // goc duoi phai
public HCN(DiemToaDo d1, DiemToaDo d2) {
this.d1 = d1;
this.d2 = d2;
}
public DiemToaDo getD1() { return d1; }
public DiemToaDo getD2() { return d2; }
public double chieuDai() { return Math.abs(d2.getX() - d1.getX()); }
public double chieuRong() { return Math.abs(d2.getY() - d1.getY()); }
public double chuVi() { return 2 * (chieuDai() + chieuRong()); }
public double dienTich() { return chieuDai() * chieuRong(); }
@Override
public String toString() {
return "[" + d1 + ", " + d2 + "]";
}
}// ===== QuanLyHCN.java =====
public class QuanLyHCN {
public static void main(String[] args) {
HCN[] ds = new HCN[5];
ds[0] = new HCN(new DiemToaDo(0, 4), new DiemToaDo(3, 0));
ds[1] = new HCN(new DiemToaDo(0, 3), new DiemToaDo(2, 0));
ds[2] = new HCN(new DiemToaDo(1, 5), new DiemToaDo(6, 1));
ds[3] = new HCN(new DiemToaDo(0, 2), new DiemToaDo(2, 0));
ds[4] = new HCN(new DiemToaDo(0, 6), new DiemToaDo(1, 0));
System.out.println("Danh sach ban dau:");
for (int i = 0; i < ds.length; i++) {
System.out.println(ds[i] + " chu vi = " + ds[i].chuVi()
+ ", dien tich = " + ds[i].dienTich());
}
// sap xep theo dien tich tang dan
for (int i = 0; i < ds.length - 1; i++) {
for (int j = 0; j < ds.length - 1 - i; j++) {
if (ds[j].dienTich() > ds[j + 1].dienTich()) {
HCN tmp = ds[j];
ds[j] = ds[j + 1];
ds[j + 1] = tmp;
}
}
}
System.out.println("Sau khi sap xep theo dien tich:");
for (int i = 0; i < ds.length; i++) {
System.out.println(ds[i] + " dien tich = " + ds[i].dienTich());
}
}
}6. Cách chạy
javac DiemToaDo.java HCN.java QuanLyHCN.java
java QuanLyHCN
7. Kết quả chạy mẫu
Danh sach ban dau:
[(0.0, 4.0), (3.0, 0.0)] chu vi = 14.0, dien tich = 12.0
[(0.0, 3.0), (2.0, 0.0)] chu vi = 10.0, dien tich = 6.0
[(1.0, 5.0), (6.0, 1.0)] chu vi = 18.0, dien tich = 20.0
[(0.0, 2.0), (2.0, 0.0)] chu vi = 8.0, dien tich = 4.0
[(0.0, 6.0), (1.0, 0.0)] chu vi = 14.0, dien tich = 6.0
Sau khi sap xep theo dien tich:
[(0.0, 2.0), (2.0, 0.0)] dien tich = 4.0
[(0.0, 3.0), (2.0, 0.0)] dien tich = 6.0
[(0.0, 6.0), (1.0, 0.0)] dien tich = 6.0
[(0.0, 4.0), (3.0, 0.0)] dien tich = 12.0
[(1.0, 5.0), (6.0, 1.0)] dien tich = 20.0
Kiểm tra tay: H1 3×4 = 12, chu vi
2(3+4) = 14 ✓. H3 5×4 = 20, chu vi
2(5+4) = 18 ✓.
8. Bảng kiểm thử
| # | Ca | Kỳ vọng |
|---|---|---|
| 1 | (0,4)-(3,0) |
diện tích 12, chu vi 14 |
| 2 | (3,0)-(0,4) (đảo ngược) |
vẫn 12 / 14 |
| 3 | Hai điểm trùng nhau | diện tích 0, chu vi 0 |
| 4 | khoangCach((0,0),(3,4)) |
5.0 |
| 5 | Sắp xếp 5 hình | tăng dần theo diện tích |
9. Trace khoangCach
d1(0,0), p(3,4): dx = -3,
dy = -4, dx² + dy² = 9 + 16 = 25,
√25 = 5.0.
10. Lỗi thường gặp
| Code sai | Hiện tượng | Sửa |
|---|---|---|
(d2.x - d1.x) * (d2.y - d1.y) cho chu vi |
Sai công thức | 2*(dai+rong) |
Không dùng Math.abs |
Cạnh âm → diện tích âm | Trị tuyệt đối |
ds[j] > ds[j+1] |
bad operand types for binary operator '>' |
So dienTich() |
toString trả x + "," + y |
Sai định dạng đề | "(" + x + ", " + y + ")" |
Dùng == để so sánh điểm |
So địa chỉ | So x, y |
11. Câu hỏi kiểm tra hiểu
- Vì sao dùng
Math.absmà vẫn đúng khi người dùng nhập hai góc ngược? - Nếu đề yêu cầu sắp xếp theo chu vi thì đổi đúng một chỗ nào?
- Vì sao không nên để
maintự tínhdienTichthay vì gọids[i].dienTich()?
12. Mở rộng
- Thêm
boolean giaoNhau(HCN h)(kiểm tra chồng lấn). HCNcóphongTo(double k)trả về hình mới.- Sắp xếp theo diện tích giảm dần, trùng thì theo chu vi tăng.