Phạm vi và các phép toán trên kiểu dữ liệu có cấu trúc Xét kiểu dữ liệu mới T ñược tạo từ nhưng kiểu dữ liệu ñã biết t 1 , t 2 ,…,t n, Phạm vi: Xác ñịnh bởi phạm vi của các kiểu dữ liệu
Trang 1Bài 1: Giới thiệu về cấu trúc dữ liệu và giải thuật
(Introduction to data structures and algorithms)
Lê Sỹ Vinh
Bộ môn Khoa Học Máy Tính – Khoa CNTT
ðại Học Công Nghệ - ðHQGHN
Email: vinhioi@yahoo.com
Trang 2Cấu trúc dữ liệu (data structure)
- Cấu trúc dữ liệu là gì?
Cấu trúc dữ liệu là cách tổ chức lưu giữ dữ liệu trong sao cho hiệu quả nhất
- Thế nào là hiệu quả?
1 “Chính xác”
2 Dùng ít bộ nhớ
3 Khả năng tìm kiếm/truy xuất
4 Khả năng cập nhật, thêm bớt (modification, insertion / deletion)
4 Khả năng cập nhật, thêm bớt (modification, insertion / deletion)
5 ðơn giản, dễ hiểu
- Các kiểu cấu trúc dữ liệu cơ bản
Trang 3Thuật toán (algorithm)
• Thuật toán là gì?
Thuật toán là một phương pháp bao gồm một dãy các bước tính toán ñể giải quyết một bài toán Thuật toán có thể ñược diễn tả dưới dạng ngôn ngữ tự nhiên (tiếng Việt, tiếng Anh…) hay ngôn ngữ lập trình (C++, Java…)
• Thế nào là một thuật toán tốt?
Trang 4Ví dụ 1: Sắp xếp danh sách tuyển sinh
Năm 2008, ðại học Công Nghệ có N thí sinh tham gia tuyển sinh, hãy viết
chương trình sắp xếp các thí sinh theo thứ tự giảm dần của tổng ñiểm thi ba môn
Ví dụ:
Trang 5Sắp xếp nổi bọt (bubble sort)
Ý tưởng: Lần lượt duyệt qua danh sách thí sinh, nếu hai thí sinh không ñúng
thứ tự, ñổi chỗ hai thí sinh Lặp lại quá trình trên cho ñến khi danh sách ñược sắp xếp
1 (Tuấn, 22) 1 (Thăng, 29) 1 (Thăng, 29)
1 (Tuấn, 22) 1 (Thăng, 29) 1 (Thăng, 29)
2 (Thăng , 29) 2 (Tuấn, 22) 2 (Vinh, 26)
Trang 6Sắp xếp nổi bọt (bubble sort)
Function bubbleSort (A : danh sách thí sinh) {
swapped := false;
do
swapped := false;
for each i = 1 to N – 1 do
if A[i].diem < A[i + 1] diem then {
swap (A[i], A[i+1]);
swapped := true;
}done;
while (swapped = true)
}
Trang 8Ví dụ 1’: Sắp xếp danh sách website (google search)
Google có danh sách N website Website x có một ñộ ưu tiên là f(x) Hãy sắp xếp các website trên theo ñộ ưu tiên giảm dần
Câu hỏi: Có thể dùng bubble sort không?
Trả lời: ðược, nhưng không hiệu quả
Trang 9Ví dụ 2: Danh bạ ñiện thoại
Viết một chương trình quản lý danh bạ ñiện thoại của toàn bộ thành phố Hà Nội, sao cho các thao tác sau ñược hiệu quả nhất:
1 Kiểm tra một số ñiện thoại
2 Thêm một số ñiện thoại
3 Xóa một số ñiện thoại
Trang 11Ví dụ 3: Tìm ñường ñi tốt nhất (google map)
Trang 14Ví dụ 5: Người bán hàng traveling salesman problem (TSP)
Một người bán hàng cần ñến thăm N khách hàng ở N ñịa ñiểm khác nhau Tìm
một hành trình cho người bán hàng trên sao cho:
1 Mỗi ñịa ñiểm thăm ñúng 1 lần, sau ñó quay về ñiểm xuất phát
2 Tổng chi phí ñi lại là ít nhất
Trang 15Người bán hàng
Thuật toán: Thăm ñịa ñiểm gần nhất (nearest neighbor tour)
Từ ñiểm xuất phát, lần lượt ñi thăm các ñiểm theo quy tắc: “ðến thăm ñiểm chưa ñược thăm gần với ñiểm hiện tại nhất”
Trang 16Người bán hàng
Nearest neighbor tour: 1 → 2 → 3 → X → 7 → 8 → 6 → 5 → 4 → 9 → 1ðương ñi tối ưu: 1 → 2 → 3 → 4 → 5 → 6 → 8 → 7 → X → 9 → 1
Trang 17Các ví dụ khác (10’)
Trang 185 Dễ thay ñổi và nâng cấp
5 Dễ thay ñổi và nâng cấp
“Thuật toán + Cấu trúc dữ liệu = Chương trình”
N Wirth
Trang 19– int age
– double weight
Trang 20Kiểu dữ liệu cơ bản
Kiểu dữ liệu ñược xác ñịnh bởi:
1 Phạm vi giá trị
2 Các phép toán
Ví dụ trong C++
kiểu phạm vi phép toán thường dùng
bool true / false and, or, not
char -127 -> 127 ‘<‘, ‘>’, ‘=’
int -32,767 -> 32,767 ‘<‘, ‘>’, ‘=’, ‘+’, ‘-’, ‘*’, ‘/’
float ~1E-37 -> ~1E+37 ‘<‘, ‘>’, ‘=’, ‘+’, ‘-’, ‘*’, ‘/’
double ~1.7E-308 -> ~1.7E+308 ‘<‘, ‘>’, ‘=’, ‘+’, ‘-’, ‘*’, ‘/’
Trang 21Kiểu dữ liệu có cấu trúc
Câu hỏi: Làm sao ựể biểu diễn dữ liệu về 1 ựiểm trên mặt phẳng?
đáp án: Ngôn ngữ lâp trình cung cấp cho ta những luật ựể xây dựng kiểu dữ
liệu mới T từ những kiểu dữ liệu ựã biết t 1 , t 2 ,Ầ,t n
Trang 22Kiểu dữ liệu có cấu trúc
• Xây dựng cấu trúc dữ liệu ñể biểu diễn dữ liệu của 1 ñiểm trên mặt phẳng
Trang 23Kiểu dữ liệu có cấu trúc
• Xây dựng cấu trúc dữ liệu ñể biểu diễn 1 sinh viên (5’)
Trang 24Phạm vi và các phép toán trên
kiểu dữ liệu có cấu trúc
Xét kiểu dữ liệu mới T ñược tạo từ nhưng kiểu dữ liệu ñã biết t 1 , t 2 ,…,t n,
Phạm vi: Xác ñịnh bởi phạm vi của các kiểu dữ liệu thành phần
– real: là số thực nằm trong phạm vi kiểu ‘double’
– image: là số thực nằm trong phạm vi kiểu ‘double’
Trang 25Phạm vi và các phép toán trên
kiểu dữ liệu có cấu trúc
Phép toán: Do người dùng ñịnh nghĩa
Trang 26Phạm vi và các phép toán trên
kiểu dữ liệu có cấu trúc
complexType add (complexType c1, complextType c2) {
complexType c12;
c12.real = c1.real + c2.real;
c12.image = c1.image + c2.image;
return c12;
}
complexType multiply (complexType c1, complextType c2) {
complexType c12;
c12.real = (c1.real * c2.real) – (c1.image * c2.image);
c12.image = (c1.real * c2.image) + (c1.image * c2.real);
return c12;
}
Trang 27Phạm vi và các phép toán trên
kiểu dữ liệu có cấu trúc
complexType getReal (complexType c) {
void printComplex (complexType c) {
cout << c.real << “ +i ” << c.image << “ \ n” ;
}
Trang 28Trừu tượng hóa dữ liệu
(abstraction data type)
1 ðặc tả ñối tượng dữ liệu (các thành phần dữ liệu của ñối tượng)
Ví dụ: ñối tượng số phức (complex)
– real
– image
2 ðặc tả các phép toán trên ñối tượng dữ liệu (operations)
2 ðặc tả các phép toán trên ñối tượng dữ liệu (operations)
Ví dụ: ðối tượng số phức (complex):
– createComplex (real, image)
– getReal (complexNumber)
– getImage (complexNumber)
– add (complexNumber1, complexNumber2)
– multiply (complexNumber2, complexNumber2)
– print (complexNumber)
Trang 29Trừu tượng hóa dữ liệu
Trừu tượng hóa ñối tượng sinh viên (student ) (5’)
1 ðặc tả ñối tượng dữ liệu
name, age, sex, address
2 ðặc tả các phép toán trên ñối tượng dữ liệu
2 ðặc tả các phép toán trên ñối tượng dữ liệu
createStudent (name, age, sex, address)compare (student1, student2)
getName (student)getAge (student)getSex (student)getAdd (student)
Trang 30Trừu tượng hóa dữ liệu
• studentClass
1 ðặc tả ñối tượng dữ liệu
className, numberStudent, studentArr, Address
2 ðặc tả các phép toán trên ñối tượng dữ liệu
addStudent (studentClass, student)findStudent (studentClass, student)deleteStudent (studentClass, student)getClassName (studentClass)
getNumberStudent (studentClass)getStudentArr (studentClass)
getStudentAddress (studentClass)
Trang 31Lập trình hướng ñối tượng
Object oriented programming (OOP)
• Lâp trình hướng ñối tượng giúp chúng ta cài ñặt các mô tả trừu tượng (ñối tượng dữ liệu và các phép toán) thành các ñoạn mã chương trình
• Chương trình ñược thiết kế thành từng ñoạn nhỏ, mỗi ñoạn mô tả về một ñối tượng (thuộc tính dữ liệu, các phép toán trên dữ liệu)
• Hai thuốc tính quan trọng: ñóng gói (encapsulation) và thừa kế
(inheritance)
Trang 33OOP: Tính ñóng gói
(encapsulation)
• Class: Cài ñặt một lớp ñối tượng dữ liệu trừu tượng Việc cài ñặt bao gồm
cài ñặt các thành phần dữ liệu và các phép toán trên dữ liệu
Trang 35Thiết kế chương trình: ðặc tả vấn ñề
Chính xác hóa vấn ñề cần giải quyết:
- Chúng ta ñược cho những gì?
- Chúng ta cần tìm ra cái gì?
- Mối quan hệ giữa chúng là gì?
ðặc tả vấn ñề trong khoa học máy tính:
Input: Dữ liệu vào, các rằng buộc, ñịnh dạng
Ouput: Dữ liệu ra, các rằng buộc, ñịnh dạng
Trang 36– c1 (số phức biểu diễn tổng của dãy số phức)
– c2 (số phức biểu diễn tích của dãy số phức)
– c3 (số phức có phần thực lớn nhất)
– c4 (số phức có phần ảo lớn nhất)
Trang 38Kiểu dữ liệu danh sách
Lê Sỹ Vinh
Bộ môn Khoa Học Máy Tính – Khoa CNTT
ðại Học Công Nghệ - ðHQGHN
Email: vinhioi@yahoo.com
Trang 39– Danh sách sinh viên
– Danh sách ñiện thoại
– Danh sách môn học
– Danh sách bài hát
– Danh sách công việc
Trang 402 Mô tả các phép toán trên cấu trúc danh sách
• empty (A): Kiểm tra danh sách có rỗng hay không
• length (A): Cho biết số phần tử của danh sách
• element (A, i) : Trả phần tử ở vị trí thứ i của A
Ví dụ: A =(1,3,5)
Element (A, 0) → 1 Element (A, 2) → 5
Trang 41Danh sách
• insert (A, i, x): Thêm phần tử x vào danh sách A tại vị trí i
A = (a 0 , a 1 ,…, a n ) → A = (a 0 ,a 1 ,…,a i-1 , x, a i ,…a n )
• delete (A, i): Loại phần tử ở vị trí thứ i trong danh sách A
A = (a 0 , a 1 ,…a i-1 , a i , a i+1 , a n ) → A = (a 0 ,a 1 ,…,a i-1 , a i+1 ,…a n )
Ví dụ: A = (1,3,5)
delete (A, 1) → A = (1, 5)
Trang 42Cài ñặt danh sách bằng mảng
Mảng (array)
• Tập hợp các phần tử (các biến) có cùng một kiểu
• Một phần tử cụ thể trong mảng sẽ ñược xác ñịnh và truy cập bởi một chỉ số
• Trong C/C++, các phần tử của mạng ñược ñặt cạnh nhau tạo thành một khối liên tục ðịa chỉ thấp nhất tương ứng với phần tử ñầu tiên, ñịa chỉ cao nhất tương ứng với phần tử cuối cùng
• Mảng thì có thể là một chiều hoặc nhiều chiều
Trang 44Danh sách
Tóm tắt về trừu tượng hóa cấu trúc danh sách
• Mô tả dữ liệu
• A = (a 0 , a 1 , …, a n)
• Mô tả các phép toán trên cấu trúc danh sách
• empty (A): Kiểm tra danh sách có rỗng hay không
• length (A): Cho biết số phần tử của danh sách
• element (A, i) : Trả phần tử ở vị trí thứ i của A
• insert (A, i, x): Thêm phần tử x vào danh sách A tại vị trí i
• append (A, x): Thêm x vào ñuôi danh sách A
• delete (A, i): Loại phần tử ở vị trí thứ i trong danh sách A
Các phép toán trên cấu trúc danh sách không phụ thuộc vào kiểu dữ liệu của các phần tử trong danh sách!!!
Trang 45Cài ñặt danh sách trong C++
Trang 46Các phép toán khác trên danh sách
• Tìm phần tử lớn nhất
• ðổi chỗ hai phần tử
• Sắp xếp tăng dần
Trang 47Con trỏ (pointer)
• Là ñiểm mạnh nhất, nhưng cũng nguy hiểm nhất của C/ C++
• Chứa ñịa chỉ của một tế bào nhớ trong máy tính
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ðịa chỉ ô nhớ 10 11 12 13 14 15 16 17
Trang 49Con trỏ (pointer)
Cấp phát bộ nhớ cho một ñối tượng dữ liệu
pointerVariable = new objectDataType
(xem ví dụ chương trình)
Trang 51Danh sách liên kết
-1 1 3 2
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
11 12 13 14 15 16 17 18 19 20 21 22 Mảng
Trang 52Cài ñặt danh sách liên kết
Xem chương trình
Trang 53Các phép toán khác trên danh sách liên kết
• Tìm phần tử lớn nhất
• ðổi chỗ hai phần tử
• Sắp xếp tăng dần
Trang 54Mảng và danh sách liên kết
• Truy cập phần tử
• Thêm phần tử
• Xóa phần tử
Trang 56Các vấn ñề liên quan ñến thuật toán
1 Một vấn ñề ñược giải quyết bởi nhiều thuật toán khác nhau
2 ðối với một thuật toán:
– ðộ phức tạp về không gian (dung lượng bộ nhớ sử dụng)
– ðộ phức tạp về thời gian chạy
3 ðộ phức tạp về thời gian chạy
Trang 57ðộ phức tạp thuật toán
1 Thời gian chạy 1 thuật toán phụ thuộc vào cỡ (size) của dữ liệu vào
– Tìm xem 1 ñối tượng có trong danh sách N phần tử hay không?
– Sắp xếp tăng dần dãy số gồm N số
– Bài toán người bán hàng cần thăm N ñịa ñiểm
2 Trong các dữ liệu vào cùng một cỡ (N), thời gian chạy của thuật toán cũng
2 Trong các dữ liệu vào cùng một cỡ (N), thời gian chạy của thuật toán cũng
thay ñổi
Ví dụ: Tìm xem 1 ñối tượng có trong danh sách N phần tử hay không?
– ðối tượng nằm ở ñầu danh sach
– ðối tượng nằm ở giữa danh sach
– ðối tượng nằm ở cuối danh sách
Trang 58ðộ phức tạp thuật toán
1 Thời gian chạy trong trường hợp xấu nhất (worse-case running time)
Thời gian chạy lớn nhất của thuật toán ñó trên tất cả các dữ liệu cùng cỡ
2 Thời gian chạy trung bình
Là trung bình cộng thời gian chạy trên tất cả các bộ dữ liệu cùng cỡ
3 Thời gian chạy trong trường hợp tốt nhất (best-case running time)
Thời gian chạy ít nhất của thuật toán ñó trên tất cả các dữ liệu cùng cỡ
Trang 59độ phức tạp thuật toán
đánh giá thời gian chạy thuật toán:
Ờ T(n) = số lượng phép toán sơ cấp cần phải thực hiện (phép toán số
học, phép toán logic, phép toán so sánh) Mỗi phép toán sơ cấp ựược thực hiện trong một khoảng thời gian cố ựịnh
Ờ Quan tâm ựến tốc ựộ tăng của hàm T(n)
Ờ Vắ dụ:
T(n) = 2n2 + 3n + 10
Trang 60Biểu diễn thời gian chạy bởi kí hiệu O
ðịnh nghĩa Giả sử f(n) và g(n) là các hàm thực không âm của ñối số nguyên không
âm n Ta nói “f(n) là ô lớn của g(n)” và viết là
f(n) = O( g(n) )
nếu tồn tại các hằng số dương c* và n0 sao cho f(n) <= c*g(n) với mọi n >= n0.
Trang 61Biểu diễn thời gian chạy bởi kí hiệu O
Ví dụ
Giả sử f(n) = 5n 3 + 2n 2 + 13n + 6 , ta có:
f(n) = 5n 3 + 2n 2 + 13n + 6 <= 5n 3 + 2n 3 + 13n 3 + 6n 3 = 26n 3 f(n) = O(n 3 )
Tổng quát nếu f(n) là một ña thức bậc k của n:
f(n) = akn k + ak-1n k-1 + + a1n + a0 thì f(n) = O(n k )
Trang 62Ký hiệu ô lớn Tên gọi O(1)
O(logn)
hằng logarit
Biểu diễn thời gian chạy bởi kí hiệu O
O(n) O(nlogn) O(n 2 ) O(n 3 ) O(2 n )
tuyến tính nlogn bình phương lập phương mũ
Trang 63Thời gian chạy của các lệnh
Trang 64Thời gian chạy của các lệnh
3 Lệnh lặp: for, while, do-while
0
n X
i n T
n T
Trang 65Thời gian chạy của các lệnh
4 Phân tích các hàm ñệ quy
Trang 68Ví dụ 4
Phân tích ñộ phức tạp thuật toán của tất cả các phép toán trên kiểu danh dữ liệu danh sách ñược cài ñặt bằng mảng và danh sách liên kết
Trang 69Hàng ñợi và Ngăn xếp (Queue and Stack)
Lê Sỹ Vinh
Bộ môn Khoa Học Máy Tính – Khoa CNTT
ðại Học Công Nghệ - ðHQGHN
Email: vinhioi@yahoo.com
Trang 71Hàng ñợi
Trừu tượng hóa cấu trúc hàng ñợi
1 Mô tả dữ liệu
A = (a 0 , a 1 , …, a n)trong ñó:
– a o : Phần tử ở ñầu của hàng ñợi A
– a n : Phần tử ở cuối của hàng ñợi A
– a n : Phần tử ở cuối của hàng ñợi A
Trang 72Các phép toán trên hàng ñợi
• empty (A): Kiểm tra hàng ñợi có rỗng hay không
• length (A): Cho biết số phần tử của hàng ñợi
• EnQueue (A, x): Thêm phần tử x cuối hàng ñợi
Trang 74– Lấy hàng hóa trong kho
– Tìm các cặp dấu ngoặc tương ứng
Tính chất:
Vào trước ra sau (First In Last Out: FILO)
Trang 75A = (‘Vinh’, ‘Tuấn’, ‘Ánh’) → Ánh: Phần tử ở ñỉnh ngăn xếp
2 Mô tả các phép toán trên cấu trúc ngăn xếp
• empty (A): Kiểm tra ngăn xếp có rỗng hay không
• length (A): Cho biết số phần tử của ngăn xếp
Trang 76• Pop (A): Loại phần tử ở ñỉnh ngăn xếp
• Pop (A): Loại phần tử ở ñỉnh ngăn xếp
Trang 79Bài toán sắp xếp
Input:
Danh sách các ñối tượng A = (a 0 ,…,a n )
Problem: ðổi chỗ các phần tử ñể thu ñược một danh sách mới, trong ñó các
phần tử ñược sắp xếp theo một thứ tự nào ñó
Trang 80Sắp xếp nổi bọt
Thuật toán:
Lần lượt duyệt qua danh sách, nếu hai phần tử liền kề ñứng không ñúng thứ
tự thì ñổi chỗ Lặp lại quá trình trên cho ñến khi danh sách ñược sắp xếp
Trang 81Sắp xếp hòa nhập (Merge sort)
Chia ñể trị (Divide and conquer): Chia bài toán lớn thành những bài toán nhỏ hơn Giải quyết
những bài toán nhỏ sau ñó gộp lại ñể ñược lời giải cho bài toán lớn.
Ý tưởng merge sort: ðể sắp xếp một mảng A[start…end], ta chia mảng A thành 2 mảng con A1
và A2 Sắp xếp A1 và A2, sau ñó hòa nhập chúng thành một ñể ñược mang A ñã sắp xếp.
Mô tả thuật toán:
Bước 1:
– Mid = (start + end) / 2
– Sắp xếp hai nửa mảng A[start…mid] và A[(mid + 1)…end] Việc sắp xếp hai nửa mảng
ñược thực hiện bằng cách gọi ñệ quy thủ tục sắp xếp hòa nhập
Bước 2: Hòa nhập hai nửa mảng A[start…mid] và A[(mid + 1)…end] ñể thu ñược mảng A
Trang 82Image taken from Skiena’s lecture note at Stony brook
Trang 83Sắp xếp hòa nhập (Merge sort)
void MergeSort( Item A[ ], int start, int end) {
if (start < end) {
int mid = (start + end)/2;
MergeSort ( A, start, mid );
MergeSort ( A, mid+1, end);
Merge ( A, start, mid, end);
}}
Trang 84Hòa nhập hai mảng tăng dần
Trang 85Sắp xếp hòa nhập
Thuật toán merge: Xem chương trình
ðộ phức tạp thuật toán sắp xếp hòa nhập: O(n logn)
Trang 86Ví dụ 0
Trang 87Ví dụ
Sắp tăng dãy số
1 9 8 7 6 5 4 3 2 1
2 C D A B G H I J K AB F E
Trang 88Sắp xếp nhanh (Quick sort)
Tư tưởng của Quick sort: Phân chia danh sách dữ liệu cần sắp xếp ra thành
hai phần “phần bên trái” và “phần bên phải” sao cho các phần tử ở phần bên trái nhỏ hơn hoặc bằng các phần tử ở phần bên phải Sau khi phân chia, tiếp tục thực hiện “quick sort trên hai phần dữ liệu trên
Cụ thể hơn, gọi “pivot” là phần tử trung tâm của danh sách, các phần tử nhỏ hơn hoặc bằng “pivot” thi nằm bên trái “pivot”, các phần tử lớn hơn hoặc bằng “pivot” thì nằm bên phải “pivot”