52
TÌM KIM & SP XP Bài ging Cu trúc dliu và Gii thut 1

Bai 2-Search Sort

Embed Size (px)

DESCRIPTION

cấu trúc dữ liệu

Citation preview

TÌM KIẾM & SẮP XẾP

Bài giảng Cấu trúc dữ liệu và Giải thuật

1

� 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}

Quick SortĐánh giá

52

� Đánh giá giải thuật:� Hiệu quả phụ thuộc vào việc chọn giá trị mốc

� Tốt nhất là phần tử median.

� Nếu phần tử mốc là cực đại hay cực tiểu thì việc phân hoạch không đồng đều.

� Tốt nhất: O(n*log2n)

� Trung bình: O(n*log2n)

� Xấu nhất: O(n2)