Tài liệu môn ngôn ngữ lập trình C/C++

Các yêu cầu: – Hoàn thành tất cả các hàm của class Matrix – Bổ sung toán tử gán, và cộng ma trận – Xây dựng class Graphic mô tả đồ thị có hướng không trọng số kế thừa từ Matrix và có thể sử dụng trong đoạn biểu thức

pdf137 trang | Chia sẻ: nguyenlam99 | Lượt xem: 1040 | Lượt tải: 0download
Bạn đang xem trước 20 trang tài liệu Tài liệu môn ngôn ngữ lập trình C/C++, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
NGÔN NGỮ LẬP TRÌNH C/C++ Vũ Song Tùng 1 NỘI DUNG Đặc điểm của C/C++ Các thành phần cơ bản Biểu thức và toán tử Hàm, mảng và con trỏ Kiểu dữ liệu trừu tượng Các cấu trúc dữ liệu cơ bản 2 3 5 22 45 77 123 I. Đặc điểm của C/C++ 3 • Ngôn ngữ lập trình hàm • Linh hoạt trong việc sử dụng các kiểu biến • Truy cập trực tiếp bộ nhớ thông qua các con trỏ • Định nghĩa các kiểu biến mới bằng các struct • Có thể chia nhỏ chương trình thành nhiều mô-đun I. Đặc điểm của C/C++ 4 • Kế thừa các đặc điểm của C • Đa hình bằng kỹ thuật xếp chồng (overload) • Hướng đối tượng bằng các lớp (class) • Sử dụng lại các mã bằng kỹ thuật kế thừa (inheritance) II. Các thành phần cơ bản Bộ ký tự Chú thích Định danh Hằng Biến Vào/ra 5 II. Các thành phần cơ bản 6 • Chữ cái thường : a – z • Chữ cái hoa : A – Z • Chữ số : 0 – 9 • Phần lớn các dấu (trừ @ và $) Ví dụ #include void main() { int Arr[] = { 1, 2, 3, 4 }; for (int i = 0; i < 4; i++) std::cout << Arr[i] << '\t'; } II. Các thành phần cơ bản 7 • Dùng để mô tả một hàm hay một đoạn chương trình // Hàm tính x^n // x - số thực, n - số nguyên dương double power(double x, int n) { /* double g = 1; for (int i = 0; i < n; i++) g *= x; return g; */ if (n == 0) return 1; // x^0 = 1 return x * power(x, n - 1); } Mô tả hàm Có thể dùng để bỏ tạm thời một đoạn chương trình Làm rõ nghĩa II. Các thành phần cơ bản 8 • Tên được đặt cho các hàm, các biến, các kiểu dữ liệu v.v • Các quy tắc định danh – Chỉ được dùng các chữ cái, chữ số hoặc dấu gạch nối – Ký tự đầu tiên không là chữ số – Không được phép trùng từ khóa Chú ý. Ngôn ngữ C/C++ phân biệt chữ cái hoa và chữ cái thường Ví dụ void _foo() // đúng quy cách { int so nguyen; // sai vì có chứa dấu cách int soNguyen; // đúng quy cách } II. Các thành phần cơ bản 9 • Các giá trị cụ thể trong chương trình • Có thể là số nguyên, số thực, ký tự hoặc xâu ký tự Ví dụ 5 // số nguyên kiểu int 05 // số nguyên biểu diễn trong hệ 8 0x5 // số nguyên biểu diễn trong hệ 16 5u // U hoặc u – số nguyên kiểu unsigned 5l // L hoặc l – số nguyên kiểu long 5.0 // số nguyên kiểu double '5' // ký tự có giá trị số (mã ASCII) bằng 53 'A' // ký tự có giá trị số (mã ASCII) bằng 65 "5" // xâu ký tự gồm ký tự '5' và ký tự NULL II. Các thành phần cơ bản 10 Bảng 2.1. Các ký tự đặc biệt Ký tự Mô tả \t TAB \n ENTER \’ Nháy đơn \” Nháy kép \\ \ \0 Ký tự NULL (giá trị bằng 0) II. Các thành phần cơ bản 11 • Là một vùng trong bộ nhớ RAM dùng để lưu trữ tạm thời các giá trị được xác định bằng một tên biến • Phân loại • Biến đơn • Biến mảng • Biến con trỏ II. Các thành phần cơ bản 12 • Cần khai báo biến trước khi sử dụng Ví dụ int a, b = 1; // Khai báo biến đơn double A[10]; // Khai báo biến mảng int *pa = &a; // Khai báo biến con trỏ Cú pháp kiểu tên_biến; kiểu tên_biến = biểu_thức_khởi_tạo; II. Các thành phần cơ bản 13 Bảng 2.2. Các kiểu biến Kiểu Kích thước (byte) Vùng giá trị Số n gu yê n char 1 -128 127 short 2 –32,768 32,767 int 4 –2,147,483,648 2,147,483,647 unsigned 4 0 4,294,967,295 long 4 –2,147,483,648 2,147,483,647 long long 8 –9,223,372,036,854,775,808 9,223,372,036,854,775,807 Số t h ự c float 4 ±3.4E±38 double 8 ±1.7E±308 long double 8 ±1.7E±308 II. Các thành phần cơ bản 14 • Một vài chú ý Ví dụ void main() { int x = 10, y; // Các biểu thức for (int i = 0; i < 4; i++) { int x = 5; // Các biểu thức } int y; } error C2086: 'int y' : redefinition Trong một khối ,-, các tên biến phải khác nhau Cùng một tên biến có thể khai báo trong các khối ,- khác nhau II. Các thành phần cơ bản 15 • Một vài chú ý • Kích thước của các kiểu phụ thuộc vào hệ thống mà chương trình được biên dịch • Dùng toán tử sizeof(...) để lấy kích thước của một kiểu, một hằng hay một biến // Chương trình Win32 Console Application int sz; sz = sizeof(sz); // sz = 4 sz = sizeof(long long); // sz = 8 sz = sizeof("12345"); // sz = 6 II. Các thành phần cơ bản 16 • Kiểu liệt kê • Dùng để định danh cho các giá trị kiểu int enum tên_kiểu { danh sách tên }; Ví dụ enum Boolean { False, True }; // False = 0, True = 1 enum Keys { Enter = 13, Escape = 27, A = 65, B, C }; // B = 66, C = 67 II. Các thành phần cơ bản 17 Dùng các chuẩn vào/ra trong thư viện iostream để làm việc với màn hình và bàn phím – Chuẩn vào (cin) sử dụng toán tử luồng vào (>>) – Các chuẩn ra (cout, cerr) sử dụng toán tử luồng ra (<<) Ví dụ double a, b, c; cout << "Nhap a, b, c: "; cin >> a >> b >> c; // Dùng dấu cách, TAB hoặc ENTER để phân biệt các luồng if (a != 0) { cout << "delta = " << b*b - 4*a*c << '\n'; // Các biểu thức } else cerr << "a phai khac 0.\n"; II. Các thành phần cơ bản 18 Yêu cầu bài toán • Nhập các hệ số a, b, c từ bàn phím • Nếu a ≠ 0 thì – Tính  – In kết quả ra màn hình với các trường hợp •  > 0  X1 = , X2 = •  = 0  X1 = X2 = •  < 0  Vo nghiem. II. Các thành phần cơ bản 19 PhuongTrinhBac2.cpp #include // thư viện vào/ra using namespace std; // nơi khai báo các thành phần chuẩn void main() { double a, b, c; cout > a >> b >> c; if (a != 0) { // Đoạn biểu thức giải và biện luận phương trình // } else cerr << "He so a phai khac 0."; cout << endl; // in ký tự xuống dòng system("pause"); // tạm dừng màn hình } II. Các thành phần cơ bản 20 PhuongTrinhBac2.cpp // Giải và biện luận phương trình double d = b*b - 4*a*c; if (d >= 0) { if (d > 0) { cout << "X1 = " << (-b - sqrt(d)) / (2 * a) << ", X2 = " << (b - sqrt(d))/(2 * a); } else cout << "X1 = X2 = " << -b / (2 * a); } // if (d >= 0) else cout << "Vo nghiem."; II. Các thành phần cơ bản 21 • Tạo project PhuongTrinhBac2 trên Visual Studio .NET và kiểm tra với các hệ số: – a = 1, b = 2, c = 1 – a = 1, b = 2, c = 3 – a = 1, b = 3, c = 2 • Tối ưu đoạn mã giải phương trình bậc 2 Gợi ý. Giảm số lượng các biểu thức 2 * a và sqrt(d) III. Biểu thức và toán tử Biểu thức Các toán tử đơn Các toán tử có cấu trúc 22 Ví dụ III. Biểu thức và toán tử 23 • Tập hợp của các toán hạng và toán tử • Kết thúc bằng dấu chấm phảy • Có thể rỗng (-b – sqrt(d)) / (2 * a)  Các toán tử: () - / *  Các toán hạng:  Biến: a, b, d  Hằng: 2  Hàm: sqrt III. Biểu thức và toán tử 24 Bảng 3.1. Phân loại các toán tử đơn Nhóm Các toán tử Ghi chú Gán = Số học + - * / % Có thể kết hợp với = Tăng/Giảm ++ -- So sánh == != > = <= Cho giá trị 0 hoặc 1 Kiểm tra ?: Logic && || ! Cho giá trị 0 hoặc 1 Xử lý bit & | ~ ^ > Có thể kết hợp với = Con trỏ & * new delete Truy cập thành viên :: . -> Các loại khác {} () [] , Thứ tự ưu tiên các toán tử tham khảo tại III. Biểu thức và toán tử 25 • Toán tử gán: a = 5; // gán 5 vào a a = b = c = 5; // tương đương: c = 5; b = c; a = b; a = b + (c = 5); // tương đương: c = 5; a = b + c; Cú pháp lvalue = rvalue lvalue – tên_biến, rvalue – một biểu thức Ví dụ Ví dụ III. Biểu thức và toán tử 26 • Các toán tử số học a = 1 / 5; // a = 0 a = 1.0 / 5; // a = 0.2 a = (double)1 / 5; // a = 0.2 a = 11 % 3; // a = 2 // Kết hợp với toán tử gán a += b; // tương đương: a = a + b; a *= b + 1; // tương đương: a = a * (b + 1); + Cộng / Chia - Trừ hoặc đổi dấu % Chia dư * Nhân Ví dụ III. Biểu thức và toán tử 27 • Các toán tử tăng/giảm ++a; // tương đương: a = a + 1; a++; // tương đương: a = a + 1; a = b++; // tương đương: a = b; b = b + 1; a = ++b; // tương đương: b = b + 1; a = b; ++ Tăng 1 -- Giảm 1 III. Biểu thức và toán tử 28 • Các toán tử so sánh 5 == 3 // cho giá trị 0 5 != 3 // cho giá trị 1 5 > 3 // cho giá trị 1 5 < 3 // cho giá trị 0 5 >= 3 // cho giá trị 1 5 <= 3 // cho giá trị 0 != Khác == Bằng > Lớn hơn >= Lớn hơn hoặc bằng < Nhỏ hơn <= Nhỏ hơn hoặc bằng III. Biểu thức và toán tử 29 • Toán tử kiểm tra: Biểu thức logic? Biểu thức 1: Biểu thức 2 Ví dụ 5 == 3? 5: 3 // cho giá trị 3 5 != 3? 5: 3 // cho giá trị 5 a > b? a: b // cho giá trị lớn nhất của a và b a < 0? –a: a // cho giá trị tuyệt đối của a III. Biểu thức và toán tử 30 • Các toán tử logic Ví dụ !(a == b) // tương đương: a != b x >= a && x <= b // kiểm tra x trong khoảng [a, b] x b // kiểm tra x ngoài khoảng [a, b] && Và || Hoặc ! Phủ định III. Biểu thức và toán tử 31 • Các toán tử logic – Các giá trị khác 0 được coi là 1 – Trong biểu thức A && B, nếu A = 0 thì không cần xác định B – Trong biểu thức A || B, nếu A = 1 thì không cần xác định B !!5 // cho giá trị 1 x >= a && x <= b // kiểm tra x trong khoảng [a, b] x b // kiểm tra x ngoài khoảng [a, b] Ví dụ III. Biểu thức và toán tử 32 • Các toán tử xử lý bit Ví dụ 5 & 0xFE // cho giá trị 4 5 | 2 // cho giá trị 7 5 ^ 4 // cho giá trị 1 ~5 // cho giá trị 0xFFFFFFFA 5 << 1 // cho giá trị 10 5 >> 1 // cho giá trị 2 & AND ~ NOT | OR << SHL (dịch trái) ^ XOR >> SHR (dịch phải) III. Biểu thức và toán tử 33 Bảng 3.2. Một vài phương án sử dụng • Các toán tử xử lý bit Biểu thức Mô tả a &= 0xFE Xóa bit a0 (a thuộc kiểu 1 byte) (a & (1 << n)) Kiểm tra bit an (a & 1) == 0 Kiểm tra tính chia hết cho 2 của a a |= 1 Lập bit a0 a |= (1 << n) Đặt bit an = 1 a ^= 1 Đảo bit a0 a <<= n Nhân a với 2n a >>= 2 Chia a cho 2n III. Biểu thức và toán tử 34 • Toán tử dấu phảy: Dùng để phân biệt hai hay nhiều biểu thức void _foo(int x, int y) // các tham số của hàm { int A[] = { 1, 2, 3, 4 };// các biểu thức khởi tạo mảng int a, b; // các biểu thức khai báo biến a = (b = 3, b + 2); // tương đương: b = 3; a = b+2; _foo(a, b); // các biểu thức truyền cho hàm } III. Biểu thức và toán tử 35 • Toán tử điều kiện: if if (biểu thức logic) khối biểu thức // tìm trị tuyệt đối của x a = x; if (a < 0) a = -x; Ví dụ III. Biểu thức và toán tử 36 • Toán tử điều kiện: if else if (biểu thức logic) khối biểu thức 1 else khối biểu thức 2 // tìm giá trị nhỏ nhất của a và b if (a < b) min = a; else min = b; Ví dụ III. Biểu thức và toán tử 37 • Toán tử lặp: while while (biểu thức logic) khối biểu thức // tìm ước số chung lớn nhất của a và b while (b != 0) { int r = a % b; a = b; b = r; } uscln = a; Ví dụ III. Biểu thức và toán tử 38 • Toán tử lặp: do while do khối biểu thức while (biểu thức logic); // Ví dụ III. Biểu thức và toán tử 39 • Toán tử lặp: for for (bt khởi tạo; bt logic; bt biến đổi) khối biểu thức // tìm N! int gt = 1; for (int i = 2; i <= N; i++) gt *= i; Ví dụ III. Biểu thức và toán tử 40 • Toán tử lựa chọn: switch switch (biểu thức) { case giá_trị_1: các biểu thức #1 break; ... case giá_trị_n: các biểu thức #n break; default: các biểu thức #khác } #k – khi (biểu thức) có giá trị = giá_trị_k #khác – khi giá trị của (biểu thức) khác các giá trị đã liệt kê III. Biểu thức và toán tử 41 • Toán tử lựa chọn: switch // tìm số ngày của tháng month trong năm year switch (month) { case 2: days = (year % 4) == 0? 29: 28; break; case 4: case 6: case 9: case 11: days = 30; break; default: days = 31; } III. Biểu thức và toán tử 42 • Toán tử điều khiển: break và continue • break – đưa con trỏ chương trình ra khỏi các vòng lặp và khối switch • continue – đưa con trỏ chương trình về đầu các vòng lặp // tìm tổng các giá trị chẵn và lẻ // của các số nguyên dương nhập vào từ bàn phím int odd = 0, even = 0, input; while (1) { // vòng lặp vô cùng cin >> input; if (input < 0) continue; if (input == 0) break; if (input & 1) even += input; else odd += input; } Ví dụ III. Biểu thức và toán tử 43 • Viết chương trình in ra màn hình các giá trị từ 1 đến k dưới dạng ma trận mxn với k = mxn, m và n được khởi tạo trong hàm main(). • Viết chương trình xác định dạng tam giác được cho bởi 3 cạnh a, b, c là các số thực. Yêu cầu: – Nhập 3 cạnh của tam giác – In ra màn hình kiểu của tam giác: • Tam giac thuong • Tam giac vuong • Tam giac can • Tam giac vuong can • Tam giac deu – Chương trình chỉ kết thúc khi a, b, c không tạo thành tam giác III. Biểu thức và toán tử 44 • Viết chương trình in ra màn lịch của năm nay theo mẫu của năm 2000: Thang 1 CN T2 T3 T4 T5 T6 T7 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Thang 2 CN T2 T3 T4 T5 T6 T7 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 IV. Hàm, mảng và con trỏ Mảng Con trỏ và tham chiếu Hàm 45 IV. Hàm, mảng và con trỏ 46 • Khai báo biến mảng kiểu tên_biến[kích thước]; // kích thước phải là hằng số nguyên kiểu tên_biến[kích thước] = { danh sách biểu thức }; // số biểu thức trong danh sách biểu thức phải nhỏ // hơn hoặc bằng kích thước kiểu tên_biến[] = { danh sách biểu thức }; // kích thước của mảng bằng số biểu thức trong // danh sách biểu thức IV. Hàm, mảng và con trỏ 47 • Khai báo biến mảng Ví dụ int A[2]; short B[] = { 10, 256, 1024 }; char S[100] = { 'A', 'B', 'C', 0 }; A A[0] A[1] 0x0A 0x00 0x00 0x01 0x00 0x04 B B[0] B[2] B[1] 0x41 0x42 0x43 0x00 S[0] S[99] S – S[3] IV. Hàm, mảng và con trỏ 48 • Xâu ký tự (string) • Mảng các ký tự, kết thúc bằng ký tự NULL • Biến xâu ký tự được khai báo bằng một mảng kiểu char (biểu thức khởi tạo có thể là một hằng xâu ký tự) Ví dụ // nhập và kiểm tra mật khẩu char pwd[] = "12345678"; char s[100]; cout << "Nhap mat khau: "; cin.getline(s, 100); for (int i = 0; s[i] != 0 || pwd[i] != 0; i++) { if (s[i] != pwd[i]) // khối biểu thức xử lý sai mật khẩu } IV. Hàm, mảng và con trỏ 49 • Thiết kế và cài đặt chương trình thực hiện các thao tác sau: – Khai báo một mảng chứa 1000 số nguyên – Đặt giá trị ngẫu nhiên từ 1 .. 1000 cho các phần tử của mảng (dùng hàm rand()) – Đếm số lượng số chẵn, số lẻ và số chia hết cho 8 của mảng • Viết chương trình thực hiện các thao tác sau: – Nhập giá trị cho xâu ký tự s (chứa được nhiều nhất 49 ký tự khác NULL) – In s ra màn hình với các chữ cái thường (VD. s = “123ABC”  123abc) – Đổi s thành số nguyên và gán cho biến a (VD. s = “123abc”  a = 123) IV. Hàm, mảng và con trỏ 50 • Các khái niệm • Con trỏ là một biến đặc biệt, dùng để chứa địa chỉ của một biến khác • Tham chiếu là một biến đại diện cho duy nhất một biến nào đó Kiểu con trỏ kiểu * Truy cập nội dung con trỏ *tên_biến_con_trỏ Lấy địa chỉ &tên_biến Kiểu tham chiếu kiểu & Bảng 4.1. Các toán tử của con trỏ và tham chiếu IV. Hàm, mảng và con trỏ 51 • Các khái niệm Ví dụ int a; // giả sử a nằm ở địa chỉ 0x000000A0 int b; // giả sử b nằm ở địa chỉ 0x000000B0 int *p = &a; // p trỏ vào a -> p = 0x000000A0 int &r = a; // r là tham chiếu của a r = 10; // -> a = 10 b = *p; // p đang trỏ vào a -> b = 10 p = &b; // p trỏ vào b -> p = 0x000000B0 *p = 5; // -> b = 5 IV. Hàm, mảng và con trỏ 52 • Con trỏ và mảng • Có thể coi biến mảng như một con trỏ trỏ vào phần tử đầu tiên của mảng • Nếu A là một biến mảng thì (A + i) chính là địa chỉ của A[i] Ví dụ double A[10], *p = A; // 3 đoạn mã tương đương for (int i = 0; i < 10; i++) *(A + i) = 0; // A[i] = 0; for (int i = 0; i < 10; i++) *(p + i) = 0; for (int i = 0; i < 10; i++, p++) *p = 0; IV. Hàm, mảng và con trỏ 53 • Cấp phát bộ nhớ động • Cấp bộ nhớ cho một biến theo nhu cầu cụ thể của chương trình • Biến được cấp bộ nhớ phải là con trỏ • Sử dụng toán tử new • Giải phóng bộ nhớ bằng toán tử delete new kiểu new kiểu[kích_thước] delete tên_biến; delete []tên_biến; IV. Hàm, mảng và con trỏ 54 • Cấp phát bộ nhớ động Ví dụ int *p; p = new int; // cấp vùng nhớ 4 byte cho p // . . . delete p; p = new int[10]; // cấp vùng nhớ 40 byte cho p // . . . delete []p; p = new int[5]; // cấp vùng nhớ 20 byte cho p // . . . delete []p; IV. Hàm, mảng và con trỏ 55 • Thiết kế và cài đặt chương trình thực hiện các thao tác sau: – Khai báo một mảng chứa n số nguyên với n được nhập từ bàn phím – Đặt giá trị ngẫu nhiên từ 1 .. 1000 cho các phần tử của mảng (dùng hàm rand()) – Đếm số lượng số chẵn, số lẻ và số chia hết cho 8 của mảng • Debug đoạn biểu thức sau: char s[100] = "1234567890"; short *p = (short *)s; *(p += 2) = 0x41; cout << s; • Viết chương trình thực hiện các thao tác sau: – Nhập giá trị cho xâu ký tự s (chứa được nhiều nhất 49 ký tự khác NULL) – In s ra màn hình với các chữ cái thường (VD. s = “123ABC”  123abc) – Đổi s thành số nguyên và gán cho biến s (VD. s = “123abc”  a = 123) Yêu cầu: Duyệt các ký tự của s bằng con trỏ IV. Hàm, mảng và con trỏ 56 • Cấu trúc của hàm kiểu tên_hàm(danh sách tham số) { các biểu thức } Vi dụ int factorial(int n) { ... } double power(double x, int n) { ... } void main() { ... } IV. Hàm, mảng và con trỏ 57 • prototype của hàm kiểu tên_hàm(danh sách kiểu); Vi dụ int factorial(int ); double power(double, int ); IV. Hàm, mảng và con trỏ 58 Bảng 4.2. Quy tắc tham số Tham số Khai báo Tham trị kiểu tên Mảng kiểu tên*+ Con trỏ kiểu * tên Tham chiếu kiểu & tên Chú ý: • Dùng tham số con trỏ thay cho mảng trong prototype của hàm • VD. int sum(int *, int); • Có thể dùng từ khóa const để cấm thay đổi giá trị các tham số trong hàm • VD. int max(const int, const int); IV. Hàm, mảng và con trỏ 59 • Tham số mặc định • Được đặt sẵn giá trị • Khai báo ở cuối danh sách tham số • Chỉ cần truyền đối số khi giá trị của đối số khác giá trị mặc định Ví dụ double power(double x, int N = 2) { ... } a = power(3); // N = 2 a = power(3, 4); // N = 4 IV. Hàm, mảng và con trỏ 60 • Toán tử return return; // thoát khỏi hàm // dùng cho các hàm kiểu void Vi dụ void main() { // các biểu thức if (a == 0) return; // các biểu thức } IV. Hàm, mảng và con trỏ 61 • Toán tử return return (biểu thức); // thoát khỏi hàm // dùng cho các hàm khác kiểu void // trả về cho hàm giá trị của biểu thức Vi dụ // hàm tính giá trị lớn nhất của a và b int max(int a, int b) { if (a > b) // return a; // return (a > b? a: b); return b; // } IV. Hàm, mảng và con trỏ 62 • Gọi hàm tên_hàm(danh sách đối số) // tên_hàm phải được khai báo trước khi gọi // danh sách đối số phải phù hợp với danh sách tham số // về số lượng và kiểu Vi dụ void main() { int f = Factorial(5); double p = power(2.5, 3); } IV. Hàm, mảng và con trỏ 63 Bảng 4.2. Quy tắc truyền đối số Đối số / Tham số Tham trị Mảng Con trỏ Tham chiếu Hằng giá trị - - - Biến đơn tên - &tên tên Tham chiếu tên - &tên tên Con trỏ *tên tên tên *tên Mảng - tên tên - IV. Hàm, mảng và con trỏ 64 • Quy tắc truyền đối số // hàm tính tổng N phần tử của mảng A int sum(int A[], int N) { int s = 0; for (int i = 0; i < N; i++) s += A[i]; return s; } void main() { int arr[] = { 1, 2, 3, 4 }; int s = sum(arr, 4); } IV. Hàm, mảng và con trỏ 65 • Quy tắc truyền đối số void change1(int a) { a++; } void change2(int *p) { (*p)++; } void change3(int &r) { r++; } void change4(const int &r) { r++; } // báo lỗi void main() { int x = 10; change1(x); // x không thay đổi change2(&x); // x = 11 change3(x); // x = 12 } IV. Hàm, mảng và con trỏ 66 • Các mô hình định nghĩa hàm // 1.cpp void foo(int a) { // không thể gọi goo } void goo(int a, int b) { // có thể gọi foo } // 2.cpp // prototype của foo và goo extern void foo(int); extern void goo(int, int); // 1.cpp // prototype của foo và goo extern void foo(int); extern void goo(int, int); IV. Hàm, mảng và con trỏ 67 • Các mô hình định nghĩa hàm // 1.cpp // prototype của foo và goo void foo(int); void goo(int, int); void foo(int a) { // có thể gọi goo } void goo(int a, int b) { // có thể gọi foo } // 2.cpp // prototype của foo và goo extern void foo(int); extern void goo(int, int); // 3.cpp // prototype của foo và goo extern void foo(int); extern void goo(int, int); IV. Hàm, mảng và con trỏ 68 • Các mô hình định nghĩa hàm // 1.cpp #include "1.h" void foo(int a) { // có thể gọi goo } void goo(int a, int b) { // có thể gọi foo } #include "1.h" // có thể gọi tất cả // các hàm khai báo // trong 1.h // 1.h #pragma once void foo(int); void goo(int, int); IV. Hàm, mảng và con trỏ 69 • Hàm inline • Chương trình dịch thay các biểu thức của hàm inline vào biểu thức gọi hàm • Không nên chứa các vòng lặp Ví dụ inline double modul(double a, double b) { return sqrt(a * a + b * b); } void main() { cout << modul(3, 4); // cout << sqrt(3* 3 + 4 * 4) } IV. Hàm, mảng và con trỏ 70 • Con trỏ hàm Ví dụ int foo(int n) { if (n < 2) return 1; return n * foo(n – 1); } int goo(int a) { return a * a; } int get(int x, int (*f)(int)) { return f(x); } void main() { cout << get(5, &foo) << ' ' << get(4, &goo); } IV. Hàm, mảng và con trỏ 71 • Hàm trả về tham chiếu Ví dụ int & max(int &a, int &b) { return (a > b? a: b); } void main() { int x = 5, y = 10; cout << max(x, y); max(x, y) = 7; cout << x << ' ' << y; } IV. Hàm, mảng và con trỏ 72 • Các hàm xếp chồng (overload) • Các hàm cùng tên • Phân biệt bằng kiểu hoặc danh sách tham số double power(double x) { return x * x; } double power(double x, int N) { if (N == 0) return 1; if (N < 0) return 1/power(x, -N); return x * power(x, N – 1); } double power(double x, double y) { return exp(y * log(x)); } Ví dụ IV. Hàm, mảng và con trỏ 73 • Các hàm xếp chồng (overload) • Chương trình dịch sẽ tự gọi hàm phù hợp dựa vào các đối số truyền cho hàm double a; a = power(2); // gọi hàm: double power(double) a = power(2, 3); // gọi hàm: double power(double, int) a = power(2, 3.0); // gọi hàm: double power(double, double) IV. Hàm, mảng và con trỏ 74 • Hàm mẫu • Dùng để sinh ra các hàm có cấu trúc giống nhau, chỉ phân biệt về kiểu của các tham số Ví dụ template _T abs(_T x) { return (x < 0? –x: x); } void main() { cout << abs(-1) // hàm sinh: int abs(int x) {...} << abs(2.0); // hàm sinh: double abs(double x) {...} } IV. Hàm, mảng và con trỏ 75 • Cài đặt hàm giải phương trình bậc 2 sau: 𝐟𝐮𝐧𝐜𝐭𝐢𝐨𝐧 FindRoot 𝑎, 𝑏, 𝑐 ∶ ℝ; 𝐯𝐚𝐫 𝑥1, 𝑥2 ∶ ℝ ∶ ℕ 𝑑 ≔ 𝑏2 − 4𝑎𝑐 𝐢𝐟 𝑑 < 0 𝐭𝐡𝐞𝐧 𝐫𝐞𝐭𝐮𝐫𝐧 0 𝐢𝐟 𝑑 = 0 𝐭𝐡𝐞𝐧 𝑥1 ≔ 𝑥2 ≔ − 𝑏 2𝑎 ; 𝐫𝐞𝐭𝐮𝐫𝐧 1 𝑥1 ≔ (−𝑏 − √𝑑)/2𝑎; 𝑥2 ≔ (−𝑏 + √𝑑)/2𝑎 𝐫𝐞𝐭𝐮𝐫𝐧 2 • Thiết kế và cài đặt hàm trả về xâu ký tự theo chuẩn họ tên từ xâu đầu vào. v u H A I m i n h \0 V u H a i M i n h \0 IV. Hàm, mảng và con trỏ 76 • Cài đặt hàm sau: 𝐟𝐮𝐧𝐜𝐭𝐢𝐨𝐧 IsSorted 𝑎 ∶ 𝐀𝐫𝐫𝐚𝐲 1. . 𝑛 𝐨𝐟 ℕ; 𝑡 ∶ *0, 1+ ∶ 0, 1 𝐟𝐨𝐫 𝑖 ≔ 1 𝐭𝐨 𝑛 − 1 𝐝𝐨 𝐢𝐟 𝑡 = 1 ∧ 𝑎 𝑖 > 𝑎 𝑖 + 1 𝐭𝐡𝐞𝐧 𝐫𝐞𝐭𝐮𝐫𝐧 0 𝐢𝐟 𝑡 = 0 ∧ 𝑎 𝑖 < 𝑎 𝑖 + 1 𝐭𝐡𝐞𝐧 𝐫𝐞𝐭𝐮𝐫𝐧 0 𝐫𝐞𝐭𝐮𝐫𝐧 1 • Cài đặt các hàm sắp xếp và tìm kiếm • Viết chương trình so sánh các thuật toán sắp xếp với các mảng 100, 1000, 10000 và 100000 phần tử V. Kiểu dữ liệu trừu tượng Các khái niệm Xây dựng ADT Các toán tử Kế thừa 77 V. Kiểu dữ liệu trừu tượng 78 • Kiểu dữ liệu trừu tượng (ADT) – kiểu được định nghĩa để mô tả cho một sự vật Các tính chất • Đóng gói – các biến và các hàm được khai báo trong một khối, cho phép che dấu các thành viên • Kế thừa – ADT (dẫn xuất) được xây dựng trên nền một ADT khác (cơ sở), có thể sử dụng lại các thành phần của ADT cơ sở • Đối tượng – một biến thuộc một ADT V. Kiểu dữ liệu trừu tượng 79 • Ví dụ: • Một hình chữ nhật (Rectangle) được xác định bởi: – tọa độ góc trên bên trái: x1, y1 – tọa độ góc dưới bên phải: x2, y2 – tính diện tích: Area = (y2 – y1) * (x2 – x1) • Một hình ô van (Elipse) nội tiếp trong hình chữ nhật: – tính diện tích: Area = Rectagle::Area *  / 4 V. Kiểu dữ liệu trừu tượng 80 • Ví dụ (struct): struct Rectangle { double x1, y1; double x2, y2; double Area() { return (y2 - y1) * (x2 - x1); } }; struct Elipse : public Rectangle { double Area() { return Rectangle::Area() * 3.14 / 4; } }; V. Kiểu dữ liệu trừu tượng 81 • Ví dụ (class): class Rectangle { public: double x1, y1; double x2, y2; double Area() { return (y2 - y1) * (x2 - x1); } }; class Elipse : public Rectangle { public: double Area() { return s = Rectangle::Area() * 3.14 / 4; } }; V. Kiểu dữ liệu trừu tượng 82 • Ví dụ (các đối tượng): void main() { Rectangle r = { 1, 1, 6, 3 }; Elipse e; e.x1 = 12; e.y1 = 2; e.x2 = 17; e.y2 = 7; cout << r.Area() << ' ' << e.Area(); } V. Kiểu dữ liệu trừu tượng 83 • Các vùng truy cập protected public private V. Kiểu dữ liệu trừu tượng 84 • Cấu trúc của ADT class tên_ADT { private|protected|public: // các biến thành viên (các thuộc tính) private|protected|public: // các hàm tạo public: // hàm hủy private|protected|public: // các hàm thành viên khác (các phương thức) public: // các toán tử thành viên // các hàm và các toán tử friend }; V. Kiểu dữ liệu trừu tượng 85 • Cấu trúc của ADT • Các hàm đơn giản (không chứa các vòng lặp hoặc rất ngắn) có thể định nghĩa inline class tên_ADT { kiểu tên_hàm(danh sách tham số) { // các biểu thức } }; V. Kiểu dữ liệu trừu tượng 86 • Cấu trúc của ADT • Các hàm phức tạp nên định nghĩa ngoài khối khai báo ADT class tên_ADT { kiểu tên_hàm(danh sách tham số); }; kiểu tên_ADT::tên_hàm(danh sách tham số) { // các biểu thức } V. Kiểu dữ liệu trừu tượng 87 • Hàm tạo và hàm hủy Hàm tạo (constructor) • Dùng để thiết lập giá trị cho các biến hoặc cấp phát bộ nhớ cho các mảng động • Được gọi trong các biểu thức khai báo đối tượng hoặc cấp phát bộ nhớ Hàm hủy (destructor) • Dùng để giải phóng bộ nhớ đã cấp phát • Được gọi khi kết thúc khối khai báo đối tượng hoặc trong biểu thức giải phóng bộ nhớ V. Kiểu dữ liệu trừu tượng 88 • Hàm tạo và hàm hủy class tên_ADT { public: tên_ADT(); // hàm tạo mặc định tên_ADT(danh sách tham số); // hàm tạo thiết lập tên_ADT(const tên_kiểu &); // hàm tạo copy ~tên_ADT(); // hàm hủy }; V. Kiểu dữ liệu trừu tượng 89 • Định nghĩa hàm tạo (inline) class tên_ADT { public: tên_ADT(danh sách tham số) : tên_biến(biểu thức) , ... { // các biểu thức } }; V. Kiểu dữ liệu trừu tượng 90 • Ví dụ (class Time) class Time { long ticks; public: Time() { ticks = 0; } Time(long value) : ticks(value) { } Time(const Time & t) : ticks(t.ticks) { } ~Time() { } public: long Seconds() { return ticks / 1000; } long Minutes() { return Seconds() / 60; } long Hours() { return Seconds() / 3600; } }; V. Kiểu dữ liệu trừu tượng 91 • Ví dụ (class Time) void main() { Time *p; Time t1; // gọi Time() Time t2(1000); // gọi Time(long) Time t3 = t2; // gọi Time(const Time &) p = new Time(100); // gọi Time(long) cout << t2.Seconds() << endl; cout Seconds() << endl; delete p; // gọi ~Time() của *p } // gọi ~Time() của t3, t2 và t1 V. Kiểu dữ liệu trừu tượng 92 • Ví dụ (class String) – Các biến thành viên và các hàm static class String { char *data; // Vùng dữ liệu chứa các ký tự int len; // Số ký tự public: // Lấy độ dài xâu src static int GetLength(const char * src); // copy xâu src vào dst static void Copy(char * dst, const char * src); V. Kiểu dữ liệu trừu tượng 93 • Ví dụ (class String) – Các hàm private private: // Hàm tạo đối lượng chứa được n ký tự String(int n) { createData(n); } // copy xâu src vào data void copyData(const char * src) { Copy(data, src); } // Tạo vùng dữ liệu chứa n ký tự void createData(int n) { len = n; data = new char[n + 1]; data[n] = 0; } V. Kiểu dữ liệu trừu tượng 94 • Ví dụ (class String) – Các hàm tạo và hàm hủy public: String() { createData(0); } String(const char * src) { createData(GetLength(src)); copyData(src); } String(const String & src) { createData(src.len); copyData(src.data); } ~String() { delete[] data; } V. Kiểu dữ liệu trừu tượng 95 • Ví dụ (class String) – Các hàm public public: // Lấy số ký tự int Length() { return len; } // So sánh với đối tượng src int Compare(const String & src) const { return Compare(src.data); } // So sánh với xâu src int Compare(const char * src) const; V. Kiểu dữ liệu trừu tượng 96 • Ví dụ (class String) – Các toán tử public: String operator=(const char * src); String operator=(String & src); // Các toán tử khác }; // class String V. Kiểu dữ liệu trừu tượng 97 • Ví dụ (class String) – Định nghĩa các hàm int String::GetLength(const char * src) { register int i = 0; while (src[i]) ++i; return i; } void String::Copy(char *dst, const char * src) { for (register int i = 0; src[i]; i++) dst[i] = src[i]; } V. Kiểu dữ liệu trừu tượng 98 • Ví dụ (class String) – Định nghĩa các hàm int String::Compare(const char *src) const { for (int i = 0; i <= len; i++) { if (data[i] != src[i]) return (data[i] > src[i]? 1: -1); } return 0; } V. Kiểu dữ liệu trừu tượng 99 • Toán tử gán { Time t1, t2; String s1, s2; t1 = t2; s1 = s2; } t1.ticks = t2.ticks s1.len = s2.len s1.data = s2.data delete[] s2.data delete[] s1.data sinh ra lỗi vì s1.data đã bị xóa V. Kiểu dữ liệu trừu tượng 100 • Toán tử gán // Bổ sung toán tử gán cho String String& operator=(const String & right) { delete [] data; // xóa vùng dữ liệu cũ createData(right.len); // tạo vùng dữ liệu mới copyData(right.data); // copy dữ liệu từ src return *this; // trả về bản thân đối tượng } V. Kiểu dữ liệu trừu tượng 101 • Các toán tử số học // Bổ sung toán tử số học cho Time Time operator+(const Time right) { return Time(ticks + right.ticks); } // Bổ sung toán tử số học cho String String operator+(const String & right) { String s(len + right.len); copy(s.data, data); copy(s.data + len, right.data); return s; } (const Time right) (const String & right) Có gì khác nhau ? V. Kiểu dữ liệu trừu tượng 102 • Các toán tử kết hợp // Bổ sung toán tử kết hợp cho Time Time & operator+=(const Time right) { ticks += right.ticks; return *this; } // Bổ sung toán tử kết hợp cho String String operator+=(const String & right) { String s(len + right.len); copy(s.data, data); copy(s.data + len, right.data); len = s.len; char *p = data; data = s.data; s.data = p; return *this; } V. Kiểu dữ liệu trừu tượng 103 • Các toán tử so sánh // Bổ sung toán tử so sánh cho Time int operator==(const Time right) const { return (ticks == right.ticks); } // Bổ sung toán tử so sánh cho String int operator==(const String & right) const { return (Compare(right.data) == 0); } V. Kiểu dữ liệu trừu tượng 104 • Toán tử chỉ số // Bổ sung toán tử chỉ số cho String char & operator[](int index) { return data[index]; } V. Kiểu dữ liệu trừu tượng 105 • Toán tử hàm kiểu operator()(danh sách tham số) { ... } Ví dụ  Lấy giá trị của hàm theo một tập các đối số  Truy cập phần tử của mảng n chiều V. Kiểu dữ liệu trừu tượng 106 • Các toán tử tăng/giảm // Bổ sung toán tử ++ cho Time // Trường hợp toán tử ở bên phải Time & operator++() { ticks++; return *this; } // Trường hợp toán tử ở bên trái friend Time & operator++(Time & right) { right.ticks++; return right; } V. Kiểu dữ liệu trừu tượng 107 • Các toán tử luồng vào/ra // Bổ sung toán tử luồng ra cho Time friend ostream & operator<<(ostream & left, Time & right) { left << right.Hours() << ':' << right.Minutes() % 60 << ':' << right.Seconds() % 60 << '.' << right.ticks % 1000; return left; } // Bổ sung toán tử luồng ra cho String friend ostream & operator<<(ostream & left, Time & right) { return left << right.data; } V. Kiểu dữ liệu trừu tượng 108 • Các toán tử ép kiểu // Bổ sung toán tử ép sang kiểu long cho Time operator long() { return ticks; } // Bổ sung toán tử ép sang kiểu xâu ký tự cho String operator char*() { return data; } V. Kiểu dữ liệu trừu tượng 109 • Xây dựng class PhanSo mô tả kiểu phân số gồm các thành phần sau: – Hai biến a, b chứa tử số và mẫu số – Các hàm tạo – Các toán tử cộng, trừ, nhân, chia và kết hợp – Toán tử luồng ra VD. PhanSo a(2, 4); cout << a + 1;  3/2 • Xây dựng class Complex mô tả kiểu số phức gồm các thành phần sau: – Hai biến r, i chứa phần thực và phần ảo – Các hàm tạo – Các toán tử cộng, trừ, nhân, chia và kết hợp – Toán tử hàm để lấy mô-đun – Toán tử luồng ra VD. Complex z(1, 3); cout << z + 1;  (2, 3i) V. Kiểu dữ liệu trừu tượng 110 • Mô hình class ADT_cơ_sở { protected|public: virtual void foo() { ... } }; class ADT_dẫn_xuất : public|protected|private ADT_cơ_sở { protected|public: void foo() { // phần mở rộng ADT_cơ_sở::foo(); // phần mở rộng } }; ADT_dẫn_xuất : public ADT_cơ_sở V. Kiểu dữ liệu trừu tượng 111 • Các vùng truy cập ADT_cơ_sở protected public private V. Kiểu dữ liệu trừu tượng 112 • Ví dụ về sự kế thừa class B { protected: int x; public: B(int a = 0) : x(a) { } virtual void Print() { cout << x; } void Inc() { x++; } }; class D : public B { int x; public: D(int a, int b) : x(a), B(b) { } void Print() { cout << x << ", "; B::Print(); } }; V. Kiểu dữ liệu trừu tượng 113 • Ví dụ về sự kế thừa void main() { B b(5); D d(1, 2); d.Inc(); B *p = &b; p->Print(); // gọi B::Print() -> 5 p = &d; p->Print(); // gọi D::Print() -> 1, 3 } V. Kiểu dữ liệu trừu tượng 114 • Lớp cơ sở trừu tượng class ADT_cơ_sở { ... virtual void foo() = 0; }; class ADT_dẫn_xuất : public|protected|private ADT_cơ_sở { ... void foo() { // ... } }; V. Kiểu dữ liệu trừu tượng 115 • Lớp cơ sở trừu tượng class Shape { String _name; public: Shape(const char *name) : _name(name) { } void Print() { cout << _name << ": Area = " << Area() << endl; } virtual double Area() = 0; }; V. Kiểu dữ liệu trừu tượng 116 • Kế thừa từ lớp cơ sở trừu tượng class Rectangle : public Shape { int _w, _h; public: Rectangle(int a, int b) : Shape("Rectangle"), _w(a), _h(b) { } double Area() { return _w * _h; } }; V. Kiểu dữ liệu trừu tượng 117 • Kế thừa lớp cơ sở trừu tượng class Triangle : public Shape { int _a, _b, _c; public: Triangle(int a, int b, int c) : Shape("Triangle"), _a(a), _b(b), _c(c) { } double Area() { double s = (_a + _b + _c) / 2; return sqrt(s * (s - _a) * (s - _b) * (s - _c)); } }; V. Kiểu dữ liệu trừu tượng 118 • Ví dụ void main() { Shape *s[2]; s[0] = new Rectangle(2, 5); s[1] = new Triangle(3, 4, 5); for (int i = 0; i < 2; i++) { s[i]->Print(); delete s[i]; } } Rectangle: Area = 10 Triangle: Area = 12 VI. Các cấu trúc dữ liệu cơ bản 119 • ADT mẫu template class Shape { _T edge[n]; // các cạnh public: _T Bound(); }; template _T Shape::Bound() { int c = 0; for (int i = 0; i < n; i++) c += edge[i]; return c; } void main() { Shape tamGiac; // tạo ra class Shape có 3 cạnh kiểu int Shape tuGiac;// tạo ra class Shape có 4 cạnh kiểu double } V. Kiểu dữ liệu trừu tượng 120 • class Matrix mô tả một ma trận được cho dưới đây template class Matrix { _T **data; int rows, cols; // số hàng và số cột void createData(); // tạo vùng dữ liệu từ rows và cols void createData(int m, int n); // tạo vùng dữ liệu m hàng, n cột void deleteData(); // xóa dữ liệu public: Matrix() : data(0) { } Matrix(int m, int n = 0); // tạo ma trận mxn hoặc mxm Matrix(int m, int n, const _T*); // tạo ma trận mxn kiểu ưu tiên // hàng từ mảng 1 chiều Matrix(const Matrix& M); ~Matrix() { deleteData(); } _T& operator()(int i, int j) { return data[i][j]; } }; V. Kiểu dữ liệu trừu tượng 121 • Định nghĩa các hàm của Matrix template void Matrix::createData() { data = new _T *[rows]; for (int i = 0; i < rows; i++) data[i] = new _T[cols]; } template void Matrix::deleteData() { if (data == 0) return; for (int i = 0; i < rows; i++) delete []data[i]; delete data; } V. Kiểu dữ liệu trừu tượng 122 • Các yêu cầu: – Hoàn thành tất cả các hàm của class Matrix – Bổ sung toán tử gán, và cộng ma trận – Xây dựng class Graphic mô tả đồ thị có hướng không trọng số kế thừa từ Matrix và có thể sử dụng trong đoạn biểu thức sau: int M[] = { 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0 }; Graphic g(5, M); g.DFT(2); // in ra màn hình chỉ số các đỉnh // theo chiều sâu bắt đầu từ đỉnh 2 VI. Các cấu trúc dữ liệu cơ bản Array, BoundStack và BoundQueue LinkedList Binary Search Tree 123 Link đến file code đầy đủ: https://docs.google.com/open?id=0B4vBa0QnLWSraGRyVkJKaFUwekE VI. Các cấu trúc dữ liệu cơ bản 124 template class Array { protected: T *data; int size; public: Array(); Array(int length); Array(const Array& a); ~Array(); public: void CopyFrom(T *); int Size(); public: T& operator[](int index); Array& operator=(const Array& a); }; VI. Các cấu trúc dữ liệu cơ bản 125 template class BoundStack : protected Array { int top; public: BoundStack(); BoundStack(int size); public: void Push(T value); T Pop(); T Top(); int IsEmpty(); int IsFull(); int Count(); T operator[](int index); }; VI. Các cấu trúc dữ liệu cơ bản 126 template class BoundQueue : protected Array { int front, rear; int count; void Inc(int &i); public: BoundQueue(); BoundQueue(int size); public: void Enqueue(T value); T Dequeue(); int IsEmpty(); int IsFull(); int Count(); T operator[](int index); }; VI. Các cấu trúc dữ liệu cơ bản 127 • Ứng dụng stack trong QuickSort template class Sort { class Segment { public: int Lb, Ub; Segment() { } Segment(int l, int r) : Lb(l), Ub(r) { } void Swap(T &a, T &b) { T t = a; a = b; b = t; } int DoPart(Array &); // Phân đoạn Array // Sắp xếp Array trong đoạn [Lb, Ub] bằng InsertSort void DoSort(Array &); }; // Segment public: static void DoSort(Array &); }; VI. Các cấu trúc dữ liệu cơ bản 128 • Ứng dụng stack trong QuickSort template void Sort::DoSort(Array &a) { int n0 = 10, len = a.Size(); BoundStack s(len/n0 + 1); s.Push(Segment(0, len - 1)); while (!s.IsEmpty()) { Segment b = s.Pop(); if (b.Ub - b.Lb + 1 > n0) { int j = b.DoPart(a); if (b.Lb < j - 1) s.Push(Part(b.Lb, j - 1)); if (b.Ub > j + 1) s.Push(Part(j + 1, b.Ub)); } else b.DoSort(a); } } VI. Các cấu trúc dữ liệu cơ bản 129 • Sử dụng class Sort #include "stdafx.h" #include "ds.h" #include using namespace std; int main() { int v[] = { 7, 5, 4, 8, 9, 1, 3, 2, 0, 6 }; Array a(10); a.CopyFrom(v); Sort::DoSort(a); for (int i = 0; i < a.Size(); i++) cout << a[i] << ' '; } VI. Các cấu trúc dữ liệu cơ bản 130 • class LinkedList template class LinkedList { protected: // Đoạn định nghĩa các lớp con // baseList h; int n; public: LinkedList() : n(0) { } ~LinkedList() { h.makeEmpty(); } int IsEmpty() { return n == 0; } int Count() { return n; } _Ti PopBegin(); _Ti PopEnd(); void RemoveAll() { h.makeEmpty(); n = 0; } void PushBegin(const _Ti& i); void PushEnd(const _Ti& i) }; VI. Các cấu trúc dữ liệu cơ bản 131 • Các lớp con class baseList { public: baseList *next, *prev; baseList() { next = prev = this; } void insertAfter(const _Ti& info); void remove(); void makeEmpty(); }; class infoList : public baseList { public: _Ti info; infoList(const _Ti& i) : info(i) { } }; VI. Các cấu trúc dữ liệu cơ bản 132 • Ứng dụng – đổi cơ số đếm std::string IntToBin(int x) { std::string s; LinkedList stack; do { char c = (char)((x & 1) + 48); x >>= 1; stack.PushBegin(c); } while (x); while (!stack.IsEmpty()) s += stack.PopBegin(); return s; } VI. Các cấu trúc dữ liệu cơ bản 133 • class cơ sở template class baseBST { public: baseBST() { } virtual baseBST * insert(const _Ti& ) = 0; virtual baseBST * contents(const _Ti& ) { return 0 ; } virtual baseBST * remove(const _Ti& ) { return this; } virtual baseBST * getSuccessor() { return 0; } virtual void makeEmpty() { } virtual _Ti * Info() { return 0; } }; template int _compare(const _Ti& a, const _Ti& b) { return (a b); } VI. Các cấu trúc dữ liệu cơ bản 134 • class BST template class BST { // Đoạn định nghĩa các class con // nullBST nullBST; baseBST * root; public: BST() { root = (baseBST *)&nullBST; } ~BST() { root->makeEmpty(); } void Insert(const _Ti& info) { root = root->insert(info); } void Delete(const _Ti& i) { root = root->remove(i); } bool Contents(const _Ti& i) { return root->contents(i); } }; VI. Các cấu trúc dữ liệu cơ bản 135 • Định nghĩa các class con class nullBST : baseBST { public: baseBST * insert(const _Ti& i) { return new infoBST(i, this); } }; class infoBST : baseBST { _Ti info; baseBST *left, *right; public: infoBST(const _Ti& i, baseBST *nullBST) : info(i) { left = right = nullBST; } void makeEmpty(); baseBST * insert(const _Ti& ); baseBST * contents(const _Ti& ); baseBST * remove(const _Ti& ); baseBST * getSuccessor(); }; VI. Các cấu trúc dữ liệu cơ bản 136 • Ứng dụng – kiểm tra khai báo biến #include "ds.h" #include using namespace std; class VarDef { public: string name; int line; VarDef() { } VarDef(const char* s, int l) : name(s), line(l) { } static int compare(const VarDef& a, const VarDef& b) { return a.name.compare(b.name); } }; VI. Các cấu trúc dữ liệu cơ bản 137 • Ứng dụng – kiểm tra khai báo biến void main() { char vars[][100] = { "x", "y", "a", "b", "x", "k", "i", "k", "m", "n" }; BST bst; BoundQueue e(10); for (int i = 0; i < 10; i++) { VarDef v(vars[i], i + 1); if (!bst.Contents(v)) bst.Insert(v); else e.Enqueue(v); } for (int i = 0; i < e.Count(); i++) { VarDef v(e[i]); cout << "redefinition variable " << v.name.data() << " in line " << v.line << endl; } }

Các file đính kèm theo tài liệu này:

  • pdfngon_ngu_lap_trinh_cc_vu_song_tung_6068.pdf
Tài liệu liên quan