Bài giảng Ngôn ngữ lập trình C/C++ - Vũ Song Tùng
Tóm tắt Bài giảng Ngôn ngữ lập trình C/C++ - Vũ Song Tùng: ...n 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...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...ệ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ử...
á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;
}
}
File đính kèm:
bai_giang_ngon_ngu_lap_trinh_cc_vu_song_tung.pdf



