Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 8Tìm kiếm tuyến tính Cải tiến cài đặt: dùng phương pháp “lính canh” Đặt thêm một phần tử cĩ giá trị x vào cuối mảng Bảo đảm luơn tìm thấy x t
Trang 1Chương I :
Trang 2Các giải thuật
Tìm kiếm tuyến tính
Tìm kiếm nhị phân
Trang 3Tìm kiếm tuyến tính
Trang 4Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 4
Tìm kiếm tuyến tính
Bước 1: i = Vị trí đầu;
Bước 2: Nếu a[i] = x : Tìm thấy Dừng, vị trí xuất hiện:
i
Bước 3 : i = Vị trí kế(i);// xét tiếp phần tử kế trong mảng
Bước 4: Nếu i >Vị trí cuối: //Hết mảng
Khơng tìm thấy Dừng
Ngược lại: Lặp lại Bước 2
Trang 6Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 6
Trang 7Tìm kiếm tuyến tính
int LinearSearch ( int a[], int n, int x)
{
int i=0;
while (i<n && a[i]!=x) i++;
if (i<n) return i; // a[i] là phần tử có khoá x
return -1; // tìm hết mảng nhưng không có x
Trang 8Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 8
Tìm kiếm tuyến tính
Cải tiến cài đặt: dùng phương pháp “lính canh”
Đặt thêm một phần tử cĩ giá trị x vào cuối mảng
Bảo đảm luơn tìm thấy x trong mảng
Sau đĩ dựa vào vị trí tìm thấy để kết luận
Trang 9a[n] = x; // thêm lính canh vào cuối dãy
while( a[i]!=x) i++;
if (i<n) return i; // a[i] là phần tử có khoá x
Trang 10Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 10
Tìm kiếm tuyến tính
Đánh giá giải thuật:
Vậy giải thuật tìm tuần tự cĩ độ phức tạp tính tốn cấp
n: T(n) = O(n)
Trang 11Tìm kiếm tuyến tính
Nhận xét:
Giải thuật tìm tuyến tính không phụ thuộc vào thứ tự của các phần tử trong danh sách, do vậy đây là phương pháp tổng quát nhất để tìm kiếm trên một danh sách bất kỳ
Một thuật toán có thể được cài đặt theo nhiều cách khác nhau, kỹ thuật cài đặt ảnh hưởng đến tốc độ thực hiện của thuật toán
Trang 12Tìm kiếm nhị phân
Trang 13Tìm kiếm nhị phân
Đối với những dãy đã có thứ tự (giả sử thứ tự tăng ), các phần
tử trong dãy có quan hệ
a[i-1] a[i] a[i+1]
Nếu x > a[i] thì x chỉ có thể xuất hiện trong đoạn [a[i+1] ,a[N]] của dãy
Nếu x < a[i] thì x chỉ có thể xuất hiện trong đoạn [a[0] ,a[i-1]] của dãy
Trang 14Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 14
Tìm kiếm nhị phân
Ý tưởng của giải thuật là tại mỗi bước tiến hành so sánh
x với phần tử nằm ở ở vị trí giữa của dãy tìm kiếm hiện hành, dựa vào kết quả so sánh này để quyết định giới hạn dãy tìm kiếm ở ở bước kế tiếp là nửa trên hay nửa dưới của dãy tìm kiếm hiện hành
Trang 15Tìm kiếm nhị phân
Bước 1: left = VTĐ; right = VTC;
Bước 2: Trong khi left right lặp: //đoạn tìm kiếm chưa rỗng
Bước 21: mid = (left+right)/2; // lấy mốc so sánh Bước 22: Nếu a [ mid ] = x : // Tìm thấy
Dừng, vị trí xuất hiện: mid Bước 23: Nếu a[mid] > x: //tìm x trong dãy con aleft amid -1 right = mid - 1;
Ngược lại //tìm x trong dãy con amid +1 aright
Trang 16Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 16
Trang 17Tìm kiếm nhị phân
int BinarySearch ( int a[], int n, int x )
{
int left =0, right = n-1, mid;
Trang 18Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 18
Tìm kiếm nhị phân
Đánh giá giải thuật:
Giải thuật tìm nhị phân cĩ độ phức tạp tính tốn cấp logn:
T(n) = O(log 2 n)
Trang 19Tìm kiếm nhị phân
Nhận xét:
Giải thuật tìm nhị phân dựa vào quan hệ giá trị của các phần tử mảng để định hướng trong quá trình tìm kiếm, do vậy chỉ áp dụng được cho những dãy đã có thứ tự
Giải thuật tìm nhị phân tiết kiệm thời gian hơn rất nhiều so với giải thuật tìm tuần tự do
(n) = O(log n) < Ttuần (n) = O(n)
Trang 20Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 20
Cần cân nhắc nhu cầu thực tế để chọn một trong hai giải thuật tìm kiếm trên sao cho cĩ lợi nhất
Trang 21Các giải thuật
Trang 22Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 22
Định nghĩa bài tốn sắp xếp
Sắp xếp là quá trình xử lý một danh sách các phần tử
(hoặc các mẫu tin) để đặt chúng theo một thứ tự thỏa mãn một tiêu chuẩn nào đĩ dựa trên nội dung thơng tin lưu giữ tại mỗi phần tử
Trang 23Khái niệm nghịch thế
Khái niệm nghịch thế:
Xét một mảng các số a[0], a[1], … a[n-1]
Nếu có i<j và a[i] > a[j], thì ta gọi đó là một nghịch thế
Mảng chưa sắp xếp sẽ có nghịch thế
Mảng đã có thứ tự sẽ không chứa nghịch thế
a[0] a[1] … a[n -1]
Trang 24Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 24
Trang 26Phương pháp
Trang 27Interchange Sort – Ý tưởng
Nhận xét: Để sắp xếp một dãy số, ta có thể xét các
nghịch thế có trong dãy và làm triệt tiêu dần chúng đi
Ý tưởng chính:
Xuất phát từ đầu dãy, tìm tất cả nghịch thế chứa phần
tử này, triệt tiêu chúng bằng cách đổi chỗ phần tử này với phần tử tương ứng trong cặp nghịch thế
Lặp lại xử lý trên với các phần tử tiếp theo trong dãy
Trang 28Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 28
//input: dãy (a, n)
//output: dãy (a, n) đã được sắp xếp
Bước 1 : i = 1; // bắt đầu từ đầu dãy
Bước 2 : j = i+1; //tìm các cặp phần tử a[j] < a[i], j>i
Bước 3 : Trong khi j n thực hiện
Nếu a[j]<a[i]: a[i]a[j];
j = j+1;
Bước 4 : i = i+1;
Nếu i < n: Lặp lại Bước 2
Ngược lại: Dừng
Trang 29Interchange Sort – Ví dụ
5
1 2
Trang 30Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 30
Interchange Sort – Ví dụ
1 2
5 1
Trang 32Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 32
Trang 34Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 34
Interchange Sort - Cài đặt
void InterchangeSort ( int a[], int n)
Trang 35Interchange Sort
Đánh giá giải thuật
Số lượng các phép so sánh xảy ra không phụ thuộc vào
tình trạng của dãy số ban đầu
Số lượng phép hoán vị thực hiện tùy thuộc vào kết quả so
sánh
Trang 36Phương pháp
Selection sort
Trang 37Selection sort – Ý tưởng
Nhận xét: Mảng có thứ tự thì a[i]=min(a[i], a[i+1], …,
Trang 38Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 38
//input: dãy (a, n)
//output: dãy (a, n) đã được sắp xếp
Bước 1 : i = Vị trí đầu;
Bước 2 : Tìm phần tử a[min] nhỏ nhất trong dãy hiện hành
từ a[i] đến a[n-1]
Bước 3 : Nếu min i: Hốn vị a[min] và a[i]
Bước 4 : Nếu i chưa là Vị trí cuối
i = Vị trí kế(i);
Lặp lại Bước 2 Ngược lại: Dừng //n phần tử đã nằm đúng vị trí
Trang 39Selection sort – Ví dụ
5
1 2
Trang 40Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 40
Trang 42Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 42
Trang 44Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 44
Trang 46Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 46
Selection sort
void SelectionSort ( int a[], int n ) {
int min; // chỉ số phần tử nhỏ nhất trong dãy hiện hành
for ( int i=0; i<n-1 ; i++) {
} }
Trang 47Selection sort – Đánh giá giải thuật
Ởû lượt thứ i, cần (n-i) lần so sánh để xác định phần tử
nhỏ nhất hiện hành
Số lượng phép so sánh không phụ thuộc vào tình trạng
của dãy số ban đầu
Trong mọi trường hợp, số lần so sánh là:
1)
n(n i)
(n
1
Trang 48Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 48
Số lần hốn vị (một hốn vị bằng 3 phép gán) phụ thuộc vào tình trạng ban đầu của dãy số
Selection sort – Đánh giá giải thuật
Trang 49Phương pháp
Insertion Sort
Trang 50Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 50
Insertion Sort – Ý tưởng
trở nên cĩ thứ tự
Vị trí này chính là pos thỏa :
a[pos-1] a[i ]< a[pos] (1 posi ).
Trang 51Chi tiết hơn:
Dãy ban đầu a[0] , a[1] , , a[n-1] , xem như đã có đoạn gồm một phần tử a[0] đã được sắp
Thêm a[1] vào đoạn a[0] sẽ có đoạn a[0] a[1] được sắp
Thêm a[2] vào đoạn a[0] a[1] để có đoạn a[0] a[1] a[2]
Trang 52Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 52
Insertion Sort – Thuật tốn
//input: dãy (a, n)
//output: dãy (a, n) đã được sắp xếp
Bước 1: i = 2; // giả sử cĩ đoạn a[0] đã được sắp
Bước 2: x = a[i]; Tìm vị trí pos thích hợp trong đoạn a[0]
Trang 53Insertion Sort – Ví dụ
5
1 2
1
Trang 54Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 54
5
1 2
Trang 551 2
5 2
Trang 56Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 56
2
5 2
Trang 575 8 1
2
5 2
Trang 58Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 58
2
5 1
Trang 592 5 6 8 1
2
5 1
Trang 60Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 60
Trang 62Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 62
Insertion Sort – Cài đặt
void InsertionSort ( int a[], int n )
} }
Trang 63Insertion Sort – Nhận xét
Khi tìm vị trí thích hợp để chèn a[i] vào đoạn a[0] đến
a[i-1], do đoạn đã được sắp có thể sử dụng giải thuật tìm nhị phân để thực hiện việc tìm vị trí pos giải thuật sắp xếp chèn nhị phân Binary Insertion Sort
Lưu ý: Chèn nhị phân chỉ làm giảm số lần so sánh, không làm giảm số lần dời chỗ
Ngoài ra, có thể cải tiến giải thuật chèn trực tiếp với phần
tử cầm canh để giảm điều kiện kiểm tra khi xác định vị trí pos
Trang 64Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 64
Insertion Sort – Đánh giá giải thuật
Các phép so sánh xảy ra trong mỗi vịng lặp tìm vị trí thích hợp pos Mỗi lần xác định vị trí pos đang xét khơng thích hợp dời chỗ phần tử a[pos-1] đến vị trí pos
Giải thuật thực hiện tất cả N-1 vịng lặp tìm pos, do số lượng phép so sánh và dời chỗ này phụ thuộc vào tình trạng của dãy số ban đầu, nên chỉ cĩ thể ước lược trong từng trường hợp như sau:
Trang 65Phương pháp
Bubble sort
Trang 66Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 66
Ý tưởng chính:
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ỏ (lớn) hơn trong cặp phần tử
đĩ về vị trí đúng đầu (cuối) dãy hiện hành, sau đĩ sẽ khơng xét đến nĩ ở bước tiếp theo,
Ở lần xử lý thứ i cĩ vị trí đầu dãy là i
Lặp lại xử lý trên cho đến khi khơng cịn cặp phần tử nào để xét
Trang 67Bubble sort – Thuật toán
//input: dãy (a, n)
//output: dãy (a, n) đã được sắp xếp
Bước 1 : i = Vị trí đầu;
Bước 2 : j = Vị trí cuối;//Duyệt từ cuối dãy ngược về vị trí i
Trong khi (j > i) thực hiện:
Nếu a[j]<a[j-1]: a[j]a[j-1];//xét cặp phần tử kế cận
j = Vị trí trước(j);
Bước 3 : i = Vị trí kế(i); // lần xử lý kế tiếp
Trang 68Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 68
Bubble Sort – Ví dụ
5
1 2
Trang 69Bubble Sort – Ví dụ
1 2
5 1
Trang 70Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 70
Trang 72Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 72
Trang 74Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 74
2
Trang 75Bubble sort - Cài đặt
void BubbleSort ( int a[], int n)
Trang 76Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 76
Bubble sort - Đánh giá giải thuật
Số lượng các phép so sánh xảy ra khơng phụ thuộc vào
tình trạng của dãy số ban đầu
Số lượng phép hốn vị thực hiện tùy thuộc vào kết quả so
sánh
Trang 77Bubble sort - Đánh giá giải thuật
Trang 78Sắp xếp dựa trên phân hoạch
Quick sort
Trang 79Quick sort – Ý tưởng
Một vài hạn chế của thuật toán ĐổiĐổi chỗ trực tiếp:
Mỗi lần đổi chổ chỉ thay đổi 1 cặp phần tử trong nghịch thế; các trường hợp như: : ii < j < k và ai > aj > ak (*) chỉ cần thực hiện 1 lần đổi chổ (ai, ak): thuật toán không làm được
Độ phức tạp của thuật toán O(N2) khi N đủ lớn thuật toán sẽ rất chậm
Ý tưởng: phân chia dãy thành các đoạn con tận dụng được các phép đổi chỗ dạng (*) và làm giảm độ dài dãy khi
Trang 80Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 80
Quick sort – Ý tưởng
Giải thuật QuickSort sắp xếp dãy a[0], a[1] , a[n-1] dựa trên việc phân hoạch dãy ban đầu thành 3 phần :
Phần 1: Gồm các phần tử cĩ giá trị khơng lớn hơn x
Phần 2: Gồm các phần tử cĩ giá trị bằng x
Phần 3: Gồm các phần tử cĩ giá trị khơng bé hơn x
với x là giá trị của một phần tử tùy ý trong dãy ban đầu
Sau khi thực hiện phân hoạch, dãy ban đầu được phân thành 3 đoạn:
1 a[k] ≤ ≤ x , với k = 1 j
2 a[k ] = x , với k = j+1 i-1
3 a[k ] x , với k = i n-1
Trang 81 Đoạn thứ 2 đã có thứ tự
Nếu các đoạn 1 và 3 chỉ có 1 phần tử thì chúng cũng đã
có thứ tự, khi đó dãy con ban đầu đã được sắp
Ngược lại, nếu các đoạn 1 và 3 có nhiều hơn 1 phần tử
thì dãy con ban đầu chỉ có thứ tự khi các đoạn 1, 3 được sắp
Để sắp xếp các đoạn 1 và 3, ta lần lượt tiến hành việc
Quick sort – Ý tưởng
Trang 82Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 82
Quick sort – Giải thuật
//input: dãy con (a, left, right)
//output: dãy con (a, left, right) được sắp tăng dần
Bước 1: Nếu leftleft = right //dãy cĩ ít hơn 2 phần tử
Bước 3: 3: SắpSắp xếp đoạn 1: a[left] a[j]
Bước 4: 4: SắpSắp xếp đoạn 3: a[i] a[right]
Trang 83Quick sort – Phân hoạch dãy
//input: dãy con a[left], …, a[right]
x = a[p];
a[i], a[j] vi phạm điều kiện
Trang 84Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 84
Quick sort – Ví dụ
5
1 2
Không lớn hơn x
Phân hoạch dãy
Trang 86Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 86
Trang 88Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 88
Sắp xếp đoạn 3
Trang 90Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 90
Quick sort – Cài đặt
{
x = a[(left+right)/2]; // chọn phần tử giữa làm giá trị mốc
}
Trang 91Quick sort – Đánh giá giải thuật
Nhận xét:
Về nguyên tắc, có thể chọn giá trị mốc x là một phần tử tùy
ý trong dãy, nhưng để đơn giản, phần tử có vị trí giữa thường được chọn, khi đó p = (l +r)/ 2
Giá trị mốc x được chọn sẽ có tác động đến hiệu quả thực hiện thuật toán vì nó quyết định số lần phân hoạch
Số lần phân hoạch sẽ ít nhất nếu ta chọn được x là phần
tử trung vị (median), nhiều nhất nếu x là cực trị của dãy
Tuy nhiên do chi phí xác định phần tử median quá cao
Trang 92Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 92
Hiệu quả phụ thuộc vào việc chọn giá trị mốc:
Trường hợp tốt nhất: mỗi lần phân hoạch đều chọn phần tử median làm mốc, khi đĩ dãy được phân chia thành 2 phần bằng nhau và cần log2(n) lần phân hoạch thì sắp xếp xong
Nếu mỗi lần phân hoạch chọn phần tử cĩ giá trị cực đại (hay cực tiểu) là mốc dãy sẽ bị phân chia thành 2 phần khơng đều: một phần chỉ cĩ 1 phần tử, phần cịn lại gồm (n-1) phần tử, do vậy cần phân hoạch n lần mới sắp xếp xong
Trang 93Quick sort – Đánh giá giải thuật
Trường hợp
Độ phức tạpTốt nhất O(NlogN)Trung bình O(NlogN)
Trang 94Cấu trúc Dữ liệu - Tìm kiếm và Sắp xếp 94
Hiệu quả phụ thuộc vào việc chọn giá trị mốc:
Trường hợp tốt nhất: mỗi lần phân hoạch đều chọn phần tử median làm mốc, khi đĩ dãy được phân chia thành 2 phần bằng nhau và cần log2(n) lần phân hoạch thì sắp xếp xong
Nếu mỗi lần phân hoạch chọn phần tử cĩ giá trị cực đại (hay cực tiểu) là mốc dãy sẽ bị phân chia thành 2 phần khơng đều: một phần chỉ cĩ 1 phần tử, phần cịn lại gồm (n-1) phần tử, do vậy cần phân hoạch n lần mới sắp xếp xong
Trang 95Quick sort – Đánh giá giải thuật
Trường hợp
Độ phức tạpTốt nhất O(NlogN)Trung bình O(NlogN)