Upload
anonymous-fbmmb1nwt
View
10
Download
0
Embed Size (px)
DESCRIPTION
cấu trúc dữ liệu
Citation preview
� Tìm kiếm� Tuần tự
� Nhị phân
� Sắp xếp� Bubble sort
� Selection sort
� Insert sort
� Quick sort
Nội dung
Tìm kiếm3
� Tìm kiếm: duyệt một danh sách và lấy ra phần tử thoả tiêu chuẩn cho trước.
� Là thao tác phổ biến trên máy tính:� Tìm mẫu tin trong cơ sở dữ liệu
� Tìm kiếm thông tin trên Internet…
� Khảo sát việc tìm kiếm trên mảng/danh sách.
Tìm kiếmGiải thuật
4
� Input:� Mảng A gồm n phần tử� Giá trị x cần tìm
� Trả về:� Vị trí phần tử x trong A hoặc –1 nếu x không xuất hiện
� Thao tác cơ bản:� So sánh
Tìm kiếm tuần tựGiải thuật
5
� Giải thuật:� Lần lượt so sánh x với các phần tử của mảng A cho đến khi
gặp được phần tử cần tìm, hoặc hết mảng.
� Ví dụ: A = {1, 25, 6, 5, 2, 37, 40}, x = 6
1 25 6 5 2 37 40
x = 6
x = 6
Dừng
1 25 6 5 2 37 40
1 25 6 5 2 37 40
x = 6
Tìm kiếm tuần tựĐánh giá
6
� Đánh giá (thao tác so sánh):� Tốt nhất: O(1)
� Xấu nhất: O(n)
� Trung bình: � Giả sử dữ liệu phân bố đều, xác suất bắt gặp x tại mỗi vị trí đều như nhau.
� Mỗi vòng lặp thực hiện 2 thao tác so sánh. Tại sao?
� Số thao tác = 2*(1 + 2 + … + n) = n + 1
� Độ phức tạp: O(n)
Hiếm khi xảy ra. Tại sao?
Tìm kiếm tuần tựPhần tử lính canh
7
� Mỗi vòng lặp cần 2 thao tác so sánh:� Kiểm tra hết mảng
� Kiểm tra phần tử hiện tại có bằng x
� Phần tử lính canh: đặt giá trị x vào cuối mảng ⇒không cần kiểm tra điều kiện hết mảng.
� Ví dụ: A = {1, 25, 5, 2, 37}, x = 6
� Trả về: n nếu không tìm thấy
1 25 5 2 37 6
Tìm kiếm nhị phân8
� Khi mảng gồm các phần tử được sắp, tận dụng điềukiện này để giảm số thao tác.
� Ý tưởng:� Xét phần tử giữa A[m]
� Nếu A[m] = x, trả về m
� Nếu A[m] > x, tìm trong các phần tử bên trái của m
� Nếu A[m] < x, tìm trong các phần tử bên phải của m
Tìm kiếm nhị phânVí dụ minh hoạ
9
� A = {2, 3, 6, 7, 10, 16, 18}, x = 16
2 3 6 7 10 16 18
[0] [1] [2] [3] [4] [5] [6]
[4] [5] [6]
2 3 6 7 10 16 18
10
Tìm kiếm nhị phânChương trình
int BinarySearch(int a[], int n, int x)
{
int l = 0, r = n-1;
while (l <= r) {
int m = (l + r)/2;
if (a[m]==x) return m; // tìm thấy
else if (x < a[m]) r = m – 1;
else l = m + 1;
}
return –1; // không tìm thấy
}
Tìm kiếm nhị phânBài tập
11
� Thực hiện việc tìm kiếm đối với các bài tập sau:� A = {1, 2, 6, 26, 28, 37, 40}, x = 40
� A = {1, 2, 6, 26, 28, 37, 40}, x = -7
Tìm kiếm nhị phânĐánh giá
12
� Mỗi lần lặp, chiều dài mảng con phải xét được giảm ½ so với mảng trước đó.
� Mảng ban đầu được chia tối đa k lần với k =
log2n.
� Tối đa k vòng lặp được thực hiện trong đó mỗi vòng lặp thực hiện 1-2 phép so sánh.
� Độ phức tạp: O(log2n)
� Mảng cần được sắp xếp trước!!!
Sắp xếp13
� Sắp xếp: tổ chức các phần tử trong một danh sách theo thứ tự.
� Là bài toán phổ biến trên máy tính.
� Nhiều giải thuật sắp xếp đã ra đời.
� Khảo sát và đánh giá hiệu quả một số giải thuật sắp xếp thông dụng dựa trên mảng.
Sắp xếpGiải thuật
14
� Input:� Mảng A gồm n phần tử.
� Output:� Một hoán vị của A sao cho: A0 ≤ A1 ≤ … ≤ An-1 (sắp
xếp tăng dần).
� Thao tác cơ bản:� So sánh
� Hoán vị (đổi vị trí hai phần tử)
Sắp xếpCác giải thuật
15
� Các phương pháp sắp xếp thông dụng:� Bubble Sort
� Selection Sort
� Insertion Sort
� Quick Sort
� Merge Sort
� Shell Sort
� Heap Sort
� Radix Sort
Bubble sort16
� Giải thuật:� Xuất phát từ cuối (đầu) dãy, đổi chỗ các cặp phần tử kế
cận để đưa phần tử nhỏ hơn về vị trí đúng đầu dãy
hiện hành.
� Sau đó không xét đến nó ở bước kế tiếp.
� Lần xử lý thứ i sẽ có vị trí đầu dãy là i.
� Lặp lại cho đến khi không còn cặp phần tử nào để xét.
� Ví dụ: sắp xếp dãy A: 15 2 8 7 3 6 9 17
Bubble sortVí dụ
17
15 2 8 7 3 6 9 17
15 2 8 3 7 6 9 17
15 2 3 8 7 6 9 17
2 15 3 8 7 6 9 17
2 15 3 8 6 7 9 17
2 15 3 6 8 7 9 17
2 3 15 6 8 7 9 17
2 3 15 6 7 8 9 17
i = 0
i = 0
i = 0
i = 1
i = 1
i = 1
i = 2
i = 2
j = 4
j = 3
j = 1
j = 5
j = 4
j = 2
j = 5
j = 3
Bubble sortVí dụ (tt)
18
2 3 6 15 7 8 9 17
2 3 6 7 15 8 9 17
2 3 6 7 8 15 9 17
2 3 6 7 8 9 15 17
2 3 6 7 8 9 15 17
j = 4
j = 5
j = 6
j = 7
i = 3
i = 4
i = 5
i = 6
Bubble sortChương trình
19
void BubbleSort(int a[], int n){
for(int i=0; i<n-1 ; i++){
for(int j = n-1; j>i; j--){
if(a[j]<a[j-1])//nếu sai vị trí thì đổi chỗ
HoanVi(a[j],a[j-1]);
}
}
}
Bubble sortBài tập
20
� Mô tả tình trạng dãy A sau mỗi bước chạy với thuật toán Bubble sort.
A = {2, 9, 5, 12, 20, 15, -8, 10}
Bubble sortĐánh giá
21
� Các giải thuật sắp xếp thường có độ phức tạp tương tự nhau.
� Cần một đánh giá chi tiết:� Các trường hợp: xấu nhất, tốt nhất, trung bình
� Các thao tác:� So sánh
� Gán (quan trọng hơn vì tốn nhiều chi phí hơn). Lưu ý: mỗi thao tác gán vị tốn 3 phép gán
Bubble sortChương trình
22
void BubbleSort(int a[], int n){
for(int i=0; i<n-1 ; i++){
for(int j = n-1; j>i; j--){
if(a[j]<a[j-1])
HoanVi(a[j],a[j-1]);
}
}
} Số lần vòng jthực hiện?Số lần vòng i
thực hiện?
Bubble sortĐánh giá
23
� Số phép so sánh: không phụ thuộc vào tình trạng dãy số ban đầu.
� Số lượng phép gán: tùy vào kết quả so sánh� Tốt nhất: 0
� Xấu nhất:
2
0
( 1)( 1)
2
n
i
n nn i
−
=
−− − =∑
2
0
3 ( 1)3( 1)
2
n
i
n nn i
−
=
−− − =∑
Shaker sort Cải tiến Bubble sort
24
� Nhận xét: Bubble sort có các khuyết điểm:� Không nhận diện được tình trạng dãy đã có thứ tự hay
không có thứ tự từng phần.
� Trong khi phần tử nhỏ được đưa về vị trí đúng rất nhanh, thì các phần tử lớn lại được đưa về vị trí đúng rất chậm.
Giải thuật Shaker sort cải tiến các khuyết điểm này.
Shaker sort Cải tiến Bubble sort
25
� Cải tiến:� Duyệt mảng theo 2 lượt từ 2 phía khác nhau:
� Lượt đi: đẩy phần tử nhỏ về đầu mảng
� Lượt về: đẩy phần tử lớn về cuối mảng.
� Ghi nhận lại những đoạn đã sắp.
Shaker sortVí dụ minh hoạ
26
15 2 8 7 3 6 9 17
15 2 8 3 7 6 9 17
15 2 3 8 7 6 9 17
2 15 3 8 7 6 9 17
2 3 15 8 7 6 9 17
2 3 8 15 7 6 9 17
2 3 8 7 15 6 9 17
k=1
r =7
r =7
l = 0
l = 1
Shaker sortVí dụ minh hoạ
27
2 3 8 7 6 15 9 17
2 3 8 7 6 9 15 17 k=5
2 3 8 7 6 9 15 17
2 3 8 6 7 9 15 17
2 3 6 8 7 9 15 17 k=3
2 3 6 7 8 9 15 17
r =5
r =5
l = 1
l = 3
Shaker sortChương trình
28
l=0; r=n-1; k=n-1; //khởi gán các giá trị
//k là vị trí xảy ra hoán vị sau cùng
while(l<r)
{
j=r; // đẩy phần tử nhỏ về đầu
while(j>l)
{ if(a[j]<a[j-1])
{
HoanVi(a[j], a[j-1]);
k=j; //lưu lại vị trí xảy ra hoán vị
}
j--;
}
l=k; //loại các phần tử đã có thứ tự ở đầu dãy
Shaker sortChương trình (tt)
29
j=l; //đẩy phần tử lớn về cuối
while(j<r)
{ if(a[j]>a[j+1])
{
HoanVi(a[j], a[j+1]);
k=j; //lưu lại vị trí xảy ra hoán vị
}
j++;
}
r=k; //loại các phần tử đã có thứ tự ở cuối dãy
}
Selection Sort30
� Mô phỏng cách sắp xếp tự nhiên nhất trong thực tế� Chọn phần tử nhỏ nhất và đưa về vị trí đúng là đầu dãy
hiện hành.
� Sau đó xem dãy hiện hành chỉ còn n-1 phần tử.
� Lặp lại cho đến khi dãy hiện hành chỉ còn 1 phần tử.
Selection SortGiải thuật
31
� Các bước của giải thuật:1. i = 0.
2. Tìm a[min] nhỏ nhất trong dãy từ a[i] đến a[n-1]
3. Hoán vị a[min] và a[i]
4. Nếu i ≤ n thì tăng i và lặp lại bước 2
Ngược lại: Dừng thuật toán
Selection SortVí dụ
32
15 2 8 7 3 6 9 17
2 15 8 7 3 6 9 17
2 3 8 7 15 6 9 17
2 3 6 7 15 8 9 17
2 3 6 7 15 8 9 17
2 3 6 7 8 15 9 17
2 3 6 7 8 9 15 17
2 3 6 7 8 9 15 17
i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
Selection SortChương trình
33
void SelectionSort(int a[], int n){
int min; //chỉ số của phần tử nhỏ nhất
for(int i=0; i<n-1; i++)
{
min = i;
for(int j = i+1; j<n; j++)
{
if(a[j] < a[min])
min = j; //ghi nhận lại vị trí
}
HoanVi(a[min], a[i]);
}
}
Selection SortĐánh giá
34
void SelectionSort(int a[], int n){
int min;
for(int i=0; i<n-1; i++)
{
min = i;
for(int j = i+1; j<n; j++)
{
if(a[j] < a[min])
min = j;
}
HoanVi(a[min], a[i]);
}
}
Cho biết sốphép gán?
Nhận xét số phép so sánh trong vòng for
Selection SortĐánh giá
35
� Số phép so sánh: � Tại lượt i bao giờ cũng cần (n-i-1) số lần so sánh
� Không phụ thuộc vào tình trạng dãy số ban đầu
� Số phép gán:� Tốt nhất:
� Xấu nhất:
Số phép so sánh = ∑−
=
−=−−
1
0 2
)1()1(
n
i
nnin
1
0
4 4n
i
n−
=
=∑
∑−
=
+=−−+
1
0 2
)7()14(
n
i
nnin
Insertion Sort36
� Cách xếp các quân bài dùng thuật toán Insertion Sort:
� Tay trái là dãy các quân bài đã có thứ tự, khi cầm 1 quân bài mới lên thì tìm vị trí đúng của nó và chèn vào.
� Cách tìm: lần lượt so sánh quân bài mới với các quân bài trong dãy ban đầu.
Insertion SortGiải thuật
37
� Giải thuật: � Xem dãy a0, a1, …, an-1 có i phần tử đầu tiên a0, a1, …,
ai-1 đã có thứ tự.
� Tìm cách chèn phần tử ai vào vị trí thích hợp để dãy a0, a1, …, ai có thứ tự.
� Cho dãy ban đầu a0, a1, …, an-1, có thể xem như đoạn gồm 1 phần tử a0 đã được sắp.
� Thêm vào a1 sẽ có a0, a1 được sắp, tiếp tục thêm a2, a3
cho đến khi thêm an-1
Insertion SortVí dụ
38
15 2 8 7 3 6 9 17
2 15 8 7 3 6 9 17
2 8 15 7 3 6 9 17
2 7 8 15 3 6 9 17
2 3 7 8 15 6 9 17
2 3 6 7 8 15 9 17
2 3 6 7 8 9 15 17
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
Insertion SortGiải thuật
39
� Các bước của giải thuật:1. Xuất phát từ i = 1.
2. Tìm vị trí pos thích hợp trong đoạn a[0] đến a[i-1] để chèn a[i].
3. Dời chỗ các phần tử từ a[pos] đến a[i-1] sang 1 vị trí để chèn a[i].
4. a[pos] = a[i]
5. Tăng i.5.1 Nếu i ≤ n: lặp lại bước 2
5.2 Ngược lại: dừng
Insertion SortChương trình
40
void InsertionSort(int a[], int n)
{
for(int i=1; i<n; i++) //đoạn a[0] đã được sắp
{
int x = a[i], pos = i-1;
while(pos>=0 && a[pos] > x) //tìm pos
{
a[pos+1]=a[pos]; //dời về sau 1 vị trí
pos--;
}
a[pos+1] = x;
}
}
Insertion SortBài tập
41
� Cho biết các giá trị i, pos tương ứng khi dùng thuật toán Insertion Sort để sắp xếp mảng A giảm dần.
A = {2, 9, 5, 12, 20, 15, -8, 10}
Insertion SortNhận xét
42
� Nhận xét:� Đoạn a[0] đến a[i-1] luôn luôn được sắp:
� Việc tìm vị trí chèn có thể dùng giải thuật tìm kiếm nhị phân.
� Nếu dùng giải thuật tìm kiếm nhị phân thì vẫn phải trả giá cho thao tác dời các phần tử sau x.
� Sinh viên tự cài đặt.
Insertion SortĐánh giá
43
void InsertionSort(int a[], int n)
{
for(int i=1; i<n; i++)
{
int x = a[i], pos = i-1;
while(pos>=0 && a[pos] > x)
{
a[pos+1]=a[pos];
pos--;
}
a[pos+1] = x;
}
}
Số lần lặp i
Số lần lặp pos
Insertion SortĐánh giá
44
� So sánh:� Tốt nhất:
� Xấu nhất:
� Gán:� Tốt nhất:
� Xấu nhất:
1
1
2 2 ( 1)n
i
n−
=
= −∑
1
1
3 3( 1)n
i
n−
=
= −∑
1
1
2 ( 1)n
i
i n n−
=
= −∑
1
1
( 1)(3 ) 3( 1)
2
n
i
n ni n
−
=
−+ = − +∑
Quick sort45
� Các giải thuật Bubble sort, Selection sort, Insertion sort:� Dễ hiểu, dễ cài đặt
� Hiệu quả thấp: O(n2)
� Các giải thuật sắp xếp dựa trên so sánh: độ phức tạp ≥ n × log2n.
� Quick sort (C. A. R. Hoare, 1962) có thể đạt được độ phức tạp trên.
Quick SortÝ tưởng
46
� Dựa trên việc phân hoạch dãy ban đầu thành 2 phần:� Dãy con 1: a0, a1, …, ai có giá trị nhỏ hơn x
� Dãy con 2: aj, …, an-1 có giá trị lớn hơn x.
Dãy ban đầu được phân thành 3 phần:
� Phần 2 đã có thứ tự
� Phần 1, 3: cần sắp thứ tự, tiến hành phân hoạch từng dãycon theo cách phân hoạch dãy ban đầu (chia để trị)
ak<x ak = x ak>xk = 0 …i k = i+1 … j k = j+1, … n-1
Quick SortGiải thuật
47
� Giải thuật phân hoạch thành 2 dãy con:1. Chọn phần tử a[k] trong dãy làm giá trị mốc, 0 ≤ k ≤ r-1
x=a[k], i = 0, j = r-1.Thường chọn phần tử ở giữa dãy: k = (l+r)/2
2. Phát hiện và hiệu chỉnh cặp phần tử a[i], a[j] sai vị trí2.1 Trong khi (a[i] < x), tăng i.2.2 Trong khi (a[j] >x), giảm j.2.3 Nếu i<=j thì hoán vị a[i], a[j], tăng i, giảm j
3. Nếu i<j: lặp lại bước 2Ngược lại: dừng.
Quick SortVí dụ
48
Phân hoạch dãy ban đầu: l = 0, r = 7, x = a[3]
Phân hoạch đoạn l = 0, r = 3, x = a[1]
Phân hoạch đoạn l = 1, r = 3, x = a[2]
15 2 8 7 3 6 9 17
6 2 3 7 8 15 9 17i = 3, j = 3
i=0, j = 5; i = 2, j = 4
6 2 3 7 8 15 9 17
2 6 3 7 8 15 9 17i=1, j = 0
i=0, j = 1
2 6 3 7 8 15 9 17
2 3 6 7 8 15 9 17i=2, j = 1
i=1, j = 2
Quick SortVí dụ
49
Phân hoạch đoạn l = 2, r = 3, x = a[2]
Phân hoạch đoạn l = 3, r = 7, x = a[5]
Phân hoạch đoạn l = 3, r = 5, x = a[4]
Phân hoạch đoạn l = 6, r = 7, x = a[6]
2 3 6 7 8 15 9 17
2 3 6 7 8 15 9 17i=5, j = 6
i=6, j = 5
2 3 6 7 8 9 15 17i=5, j = 3
2 3 6 7 8 9 15 17
i=3, j = 1
Quick SortChương trình
50
void QuickSort(int a[], int l, int r)
{
i = l; j = r; x = a[(l+r)/2];
do {
while (a[i] < x) i++;
while (a[j] > x) j--;
if (i <= j){
HoanVi(a[i], a[j]);
i++; j--;
}
} while (i < j);
if (l < j)
QuickSort(a, l, j);
if (i < r)
QuickSort(a, i, r);
}
Quick SortBài tập
51
� Chạy tay thuật toán Quick Sort để sắp xếp mảng A trong 2 trường hợp tăng dần và giảm dần.
A = {2, 9, 5, 12, 20, 15, -8, 10}