CHƢƠNG 2 TÌM KiẾM VÀ SẮP XẾP NỘI

1

Nội dung

 Các giải thuật tìm kiếm nội

1. Tìm kiếm tuyến tính

2. Tìm kiếm nhị phân

 Các giải thuật sắp xếp nội

1. Đổi chỗ trực tiếp – Interchange Sort

2. Chọn trực tiếp – Selection Sort

3. Nổi bọt – Bubble Sort

2

Nội dung 4. Chèn trực tiếp – Insertion Sort

5. Shell Sort

6. Heap Sort

7. Quick Sort

3

Nhu cầu tìm kiếm và sắp xếp

 Thao tác tìm kiếm đƣợc sử dụng nhiều nhất

trong các hệ lƣu trữ và quản lý dữ liệu.

 Do dữ liệu lớn nên tìm ra giải thuật tìm kiếm nhanh chóng là mối quan tâm hàng đầu. Để đạt đƣợc điều này dữ liệu phải đƣợc tổ chức theo một thứ tự nào đó thì việc tìm kiếm sẽ nhanh chóng và hiệu quả hơn, vì vậy nhu cầu sắp xếp dữ liệu cũng đƣợc lƣu ý.

 Tóm lại, bên cạnh những giải thuật tìm kiếm thì các giải thuật sắp xếp dữ liệu không thể thiếu trong hệ quản lý thông tin trên máy tính.

4

Các giải thuật tìm kiếm

 Có 2 giải thuật thƣờng đƣợc áp dụng: Tìm tuyến

tính và tìm nhị phân.

 Để đơn giản cho việc minh họa, ta đặc tả nhƣ sau:

a1

a2

a3

a4

a5

an-1

aN

◦ Tập dữ liệu đƣợc lƣu trữ là dãy số a1, a2, ... ,aN. ◦ Giả sử chọn cấu trúc dữ liệu mảng để lƣu trữ dãy số này trong bộ nhớ chính, có khai báo: int a[N];

◦ Khoá cần tìm là x, đƣợc khai báo nhƣ sau: int x;

5

5

Tìm kiếm tuyến tính

 Ý tưởng

Tiến hành so sánh x lần lƣợt với phần tử thứ nhất, thứ hai, ... của mảng a cho đến khi gặp đƣợc phần tử có khóa cần tìm, hoặc đã tìm hết mảng mà không thấy x.

Minh họa tìm x =10

10

7

5

12

41

32

13

15

3

9

10 10

Chƣa Đã tìm hết thấy tại mảng vị trí 5

1

2

3

4

5

6

7

9

10

8

Minh họa tìm x =25

25

Đã hết mảng

Chƣa hết mảng

7

5

12

41

10

32

13

15

3

9

1

2

3

4

5

6

7

9

10

8

6

Giải thuật Bước 1: i = 1;

// bắt đầu từ phần tử đầu tiên của dãy

Bước 2: So sánh a[i] với x, có 2 khả năng : ◦ a[i] = x : Tìm thấy. Dừng ◦ a[i] != x : Sang Bước 3. Bước 3: ◦ i = i+1; // xét tiếp phần tử kế trong mảng ◦ Nếu i >N: Hết mảng, không tìm thấy. Dừng

Ngược lại: Lặp lại Bước 2.

7

Cài đặt

int LinearSearch(int a[], int N, int x) {

int i=0; while ((i

i++; if(i==N)

return -1;// tìm hết mảng nhưng không có x

else

return i;// a[i] là phần tử có khoá x

}

8

Cải tiến thuật toán tìm kiếm tuyến tính

Cải tiến (dùng phần tử lính canh) giúp giảm

bớt một phép so sánh

 Minh họa tìm x =10

10

12

41

10 10

32

13

15

3

7

5

9

10

3

4

5

6

7

9

10

1

2

8

 Minh họa tìm x = 25

25

7

5

12

41

10

32

13

15

3

9

25 25 11

1

2

3

4

5

6

7

9

10

8

9

Cài đặt int LinearSearch2(int a[],int N,int x) {

// mảng gồm N phần tử từ a[0]..a[N-1]

int i=0; a[N] = x; // thêm phần tử thứ N+1 while (a[i]!=x )

i++; if (i==N)

return -1; // tìm hết mảng nhưng không có x

return i;

// tìm thấy x tại vị trí i

else

}

10

Ðánh Giá Thuật Toán Tìm Tuyến Tính

Css

Trƣờng hợp

1

Tốt nhất

Xấu nhất

N

Trung bình

(N+1) / 2

 Độ phức tạp O(N)

11

Tìm kiếm nhị phân

 Đƣợc áp dụng trên dãy đã có thứ tự.  Ý tưởng: .

 Giả xử ta xét mảng có thứ tự tăng, khi ấy ta có

ai-1

 Nếu X>ai thì X chỉ có thể xuất hiện trong đoạn [ai+1, an-1]  Nếu X

 Ý tƣởng của giải thuật là tại mỗi bƣớc ta so sánh X với

phần tử đứng giữa trong dãy tìm kiếm hiện hành, dựa vào kết quả so sánh này mà ta quyết định giới hạn dãy tìm kiếm ở nữa dƣới hay nữa trên của dãy tìm kiếm hiện hành.

12

Minh họa tìm x = 41 x

x

x

14 14 14 14

16 16 16 16

19 19 19 19

41 41 41 41

46 46 46 46

63 63 63 63

22 22 22 22

51 51 51 51

71 71 71 71

3 3 3 3

2 2 2 2

3 3 3 3

4 4 4 4

6 6 6 6

7 7 7 7

9 9 9 9

5 5 5 5

8 8 8 8

10 10 10 10

1 1 1 1

Tìm thấy x tại vị trí 6

m

m

r

l

m

13

Minh họa tìm x = 45 x

x

x

x

14 14 14 14 14

16 16 16 16 16

19 19 19 19 19

3 3 3 3 3

22 22 22 22 22

41 41 41 41 41

51 51 51 51 51

63 63 63 63 63

71 71 71 71 71

46 46 46 46 46

2 2 2 2 2

3 3 3 3 3

4 4 4 4 4

1 1 1 1 1

5 5 5 5 5

6 6 6 6 6

8 8 8 8 8

9 9 9 9 9

10 10 10 10 10

7 7 7 7 7

l

m

m

r

l > r: Kết thúc: Không tìm thấy

m

m

14

Giải thuật Bƣớc 1: left = 1; right = N;

// tìm kiếm trên tất cả

các phần tử

Bƣớc 2:

// lấy mốc so sánh

mid = (left+right)/2; So sánh a[mid] với x, có 3 khả năng : a[mid] = x: Tìm thấy. Dừng a[mid] > x:

//tìm tiếp x trong dãy con aleft .. amid -1

right =mid - 1;

a[mid] < x:

//tìm tiếp x trong dãy con amid +1 .. aright

left = mid + 1;

Bƣớc 3:

//còn phần tử chƣa xét tìm

Nếu left <= right tiếp.

//Ðã xét hết tất cả các phần

15

Lặp lại Bƣớc 2. Ngƣợc lại: Dừng tử.

Cài đặt int BinarySearch(int a[],int N,int x ) {

int left =0; right = N-1; int mid; do{

mid = (left + right)/2; if (x == a[mid])

return mid;//Thấy x tại mid

else if (x < a[mid])

right = mid -1; else left = mid +1;

}while (left <= right); return -1; // Tìm hết dãy mà không có x

}

16

Ðánh Giá Thuật Toán Tìm Nhị Phân

Css

Trƣờng hợp

1

Tốt nhất

Xấu nhất

log2N

Trung bình

log2N / 2

 Độ phức tạp O(log2N)

17

Bài toán sắp xếp  Cho danh sách có n phần tử a0, a1, a2…, an-1.  Sắp xếp là quá trình xử lý các phần tử trong danh sách để đặt chúng theo một thứ tự thỏa mãn một số tiêu chuẩn nào đó dựa trên thông tin lƣu tại mỗi phần tử, nhƣ:

 Sắp xếp danh sách lớp học tăng theo điểm trung

bình.

 Sắp xếp danh sách sinh viên tăng theo tên.

 …

 Để đơn giản trong việc trình bày giải thuật ta dùng

18

mảng 1 chiều a để lƣu danh sách trên trong bộ nhớ chính.

Bài toán sắp xếp  a: là dãy các phần tử dữ liệu  Để sắp xếp dãy a theo thứ tự (giả sử theo thứ tự tăng), ta tiến hành triệt tiêu tất cả các nghịch thế trong a.  Nghịch thế:

a[0], a[1] là cặp nghịch thế

• Cho dãy có n phần tử a0, a1,…,an-1 • Nếu iaj 4 3 34

8

19

 Đánh giá độ phức tạp của giải thuật, ta tính Css: Số lƣợng phép so sánh cần thực hiện CHV: Số lƣợng phép hoán vị cần thực hiện

Các thuật toán sắp xếp

1. Đổi chỗ trực tiếp – Interchange Sort 2. Chọn trực tiếp – Selection Sort 3. Nổi bọt – Bubble Sort 4. Shaker Sort 5. Chèn trực tiếp – Insertion Sort 6. Chèn nhị phân – Binary Insertion Sort 7. Shell Sort 8. Heap Sort 9. Quick Sort

20

Đổi Chỗ Trực Tiếp–Interchange Sort

 Ý tưởng: Xuất phát từ đầu dãy, tìm tất

các các nghịch thế chứa phần tử này,

triệt tiêu chúng bằng cách đổi chỗ 2

phần tử trong cặp nghịch thế. Lặp lại xử

lý trên với phần tử kế trong dãy.

21

// bắt đầu từ đầu dãy

Đổi Chỗ Trực Tiếp–Interchange Sort  Bƣớc 1: i = 0;  Bƣớc 2: j = i+1; //tìm các nghịch thế với a[i]  Bƣớc 3:

Trong khi j < N thực hiện

Nếu a[j]

j = j+1;

 Bƣớc 4: i = i+1;

22

Nếu i < N-1: Lặp lại Bƣớc 2. Ngƣợc lại: Dừng.

Đổi Chỗ Trực Tiếp–Interchange Sort

 Cho dãy số a: 8

12

2

5

1

6

4

15

i=0

j=1

j=4

i=0

23

Đổi Chỗ Trực Tiếp–Interchange Sort

i=1

j=2

i=1

j=3

i=1

j=4

24

Đổi Chỗ Trực Tiếp–Interchange Sort

i=2

j=3

i=2

j=4

i=2

j=6

25

Đổi Chỗ Trực Tiếp–Interchange Sort

i=3

j=4

i=3

j=5

j=6

i=3 26

Đổi Chỗ Trực Tiếp–Interchange Sort

i=4

j=5

j=6

i=4

i=5

j=6

27

Đổi Chỗ Trực Tiếp–Interchange Sort

j=7

i=6

28

Cài Đặt Đổi Chỗ Trực Tiếp

void InterchangeSort(int a[], int N ) {

i, j;

int for (i = 0 ; i

for (j =i+1; j < N ; j++)

if(a[j ]< a[i]) // Thỏa 1 cặp nghịch thế

Swap(a[i], a[j]);

}

29

Minh Họa – Đổi Chỗ Trực Tiếp

j

2 8 1 12 1 6 4 15 5

1 2 4 5 6 7 3

0 i

30

Minh Họa – Đổi Chỗ Trực Tiếp

j

2 12 1 2 6 4 15 5 8

0

2 1 4 5 6 7 3

0 i

31

Minh Họa – Đổi Chỗ Trực Tiếp

j

0

1 4 12 2 5 6 4 15 8

0 2 4 5 6 7 3

1 i

32

Minh Họa – Đổi Chỗ Trực Tiếp

j

0

1 2 4 8 6 5 15 5 12

0 1 4 5 6 7 3

2 i

33

Minh Họa – Đổi Chỗ Trực Tiếp

j

0

4 8 1 2 5 12 6 6 15

0 1 2 4 5 6 7

3 i

34

Minh Họa – Đổi Chỗ Trực Tiếp

j

0

8 6 12 8 15 4 5 1 2

0 1 2 3 5 6 7

4 i

35

Minh Họa – Đổi Chỗ Trực Tiếp

j

0

6 8 12 12 15 4 5 1 2

0 1 2 3 4 6 7

5 i

36

Minh Họa – Đổi Chỗ Trực Tiếp

1

2

3

5

6

7

8

4

1 2 4 6 8 12 15 5

37

Độ phức tạp thuật toán Đổi chỗ trực tiếp

38

Chọn Trực Tiếp – Selection Sort

 Ý tưởng:

 Chọn phần tử nhỏ nhất trong N phần tử trong

dãy hiện hành ban đầu.

 Đƣa phần tử này về vị trí đầu dãy hiện hành

 Xem dãy hiện hành chỉ còn N-1 phần tử của

dãy hiện hành ban đầu

 Bắt đầu từ vị trí thứ 2;

 Lặp lại quá trình trên cho dãy hiện hành... đến khi dãy hiện hành chỉ còn 1 phần tử

39

Chọn Trực Tiếp – Selection Sort

 Bƣớc 1:

i = 0;

 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]

 Bƣớc 3 : Đổi chỗ a[min] và a[i]

 Bƣớc 4 : Nếu i < N-1 thì

i = i+1; Lặp lại Bƣớc 2;

Ngƣợc lại: Dừng.

40

Chọn Trực Tiếp – Selection Sort

 Cho dãy số a: 8

12 2

5

1

6

4

15

41

Chọn Trực Tiếp – Selection Sort

i=0

i=1

42

Chọn Trực Tiếp – Selection Sort

i=2

i=3

i=4

43

Chọn Trực Tiếp – Selection Sort

i=5

i=6

44

Cài Đặt Thuật Toán Chọn Trực Tiếp

void SelectionSort(int a[],int n ) {

int min,i,j; // chỉ số phần tử nhỏ nhất trong dãy hiện hành for (i=0; i

min = i; for(j = i+1; j

min = j; // lưu vtrí phần tử hiện nhỏ nhất

Swap(a[min],a[i]);

}

45

}

Minh Họa Thuật Toán Chọn Trực Tiếp

min

Vị trí nhỏ nhất(0,7) Swap(a[0], a[4])

12 2 8 1 6 4 15 5

1 2 4 5 6 7 3

0 i

46

Minh Họa Thuật Toán Chọn Trực Tiếp

min

Vị trí nhỏ nhất(1,7) Swap(a[1], a[1])

2 8 1 12 6 4 15 5

1 2 4 5 6 7 3

0 i

47

Minh Họa Thuật Toán Chọn Trực Tiếp

min

Vị trí nhỏ nhất(2,7) Swap(a[2], a[6])

8 1 2 12 6 4 15 5

2 0 4 5 6 7 3

1 i

48

Minh Họa Thuật Toán Chọn Trực Tiếp

min

Vị trí nhỏ nhất(3, 7) Swap(a[3], a[3])

1 2 4 12 6 8 15 5

0

1

4

5

6

7

3

2 i

49

Minh Họa Thuật Toán Chọn Trực Tiếp

min

Vị trí nhỏ nhất(4, 7) Swap(a[4], a[5])

1 2 4 6 8 15 12 5

0 1 2 5 6 7 4 3

i

50

Minh Họa Thuật Toán Chọn Trực Tiếp

min

Vị trí nhỏ nhất(5,7) Swap(a[5], a[6])

1 2 4 12 6 8 15 5

0 1 2 5 6 7 3

4 i

51

Minh Họa Thuật Toán Chọn Trực Tiếp

min

Vị trí nhỏ nhất(6, 7)

1 2 4 12 12 15 15 6 8 5

0 1 2 6 7 4 3

5 i

52

Độ phức tạp thuật toán Chọn trực tiếp

 Ðánh giá giải thuật

53

Nổi Bọt – Bubble Sort

 Ý tưởng:

 Xuất phát từ cuối dãy, đổi chỗ các cặp phần tử kế cận để đƣa phần tử nhỏ hơn trong cặp phần tử đó về vị trí đúng đầu dãy hiện hành, sau đó sẽ không xét đến nó ở bƣớc tiếp theo, do vậy ở lần xử lý thứ i sẽ 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.

54

Nổi Bọt – Bubble Sort

// lần xử lý đầu tiên

 Bƣớc 1 : i = 0;  Bƣớc 2 : j = N-1;//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]

j = j-1;

// lần xử lý kế tiếp

 Bƣớc 3 : i = i+1;

Doicho(a[j],a[j-1]);

Nếu i =N: Hết dãy. Dừng Ngƣợc lại : Lặp lại Bƣớc 2.

55

Nổi Bọt – Bubble Sort

 Cho dãy số a: 12 8

2

5

1

6

4

15

i=0

j=6

i=0

i=4

56

Nổi Bọt – Bubble Sort

i=0

j=3

j=2

i=0

i=0

j=1

57

Nổi Bọt – Bubble Sort

i=1

j=5

i=1

j=4

i=1

j=3 58

Nổi Bọt – Bubble Sort

i=2

j=5

j=4

i=2

i=3 59

j=6

Nổi Bọt – Bubble Sort

i=3

j=5

i=4

j=6

i=5

60

Cài Đặt Thuật Toán Nổi Bọt

void BubbleSort(int a[],int n) {

i, j;

int for (i = 0 ; i

for (j =n-1; j >i ; j --)

if(a[j]< a[j-1])// nếu sai vị trí thì đổi chỗ Swap(a[j], a[j-1]);

}

61

Minh Họa Thuật Toán Nổi Bọt

j

2 8 1 6 4 15 5 12 1

1

2

4

5

6

7

3

0 i

62

Minh Họa Thuật Toán Nổi Bọt

j

2 12 2 1 5 4 6 15 8

1 2 4 5 6 7 3

0 i

63

Minh Họa Thuật Toán Nổi Bọt

j

1 2 4 12 8 5 6 15 4

0

2

4

5

6

7

3

1 i

64

Minh Họa Thuật Toán Nổi Bọt

j

1 2 8 5 6 4 15 12 5

0 1 3 4 5 6 7

2 i

65

Minh Họa Thuật Toán Nổi Bọt

j

1 2 4 8 6 15 5 12 6

0

1

2

4

5

6

7

3 i

66

Minh Họa Thuật Toán Nổi Bọt

j

1 2 4 8 12 8 6 15 5

0 1 2 5 6 7 3

4 i

67

Minh Họa Thuật Toán Nổi Bọt

1

2

3

5

7

j 8

6

4

1 2 4 6 12 12 15 15 8 5

i

68

Độ Phức Tạp Của Thuật Toán Nổi Bọt

69

ShakerSort

 Trong mỗi lần sắp xếp, 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 xếp nhằm

tiết kiệm các phép so sánh thừa.

70

ShakerSort

 Bƣớc 1: l=0; r=n-1; //Đoạn l->r là đoạn cần đƣợc sắp xếp

k=n;

//ghi nhận vị trí k xảy ra hoán vị sau cùng

// để làm cơ sơ thu hẹp đoạn l->r

 Bƣớc 2:

Bƣớc 2a:

//đẩy phần tử nhỏ về đầu mảng

j=r; Trong khi j>l

nếu a[j]

l=k;

//loại phần tử đã có thứ tự ở đầu dãy

Bƣớc 2b: j=l

Trong khi j

nếu a[j]>a[j+1] thì {Doicho(a[j],a[j+1]); k=j;} j++;

r=k;

//loại phần tử đã có thứ tự ở cuối dãy

 Bƣớc 3: Nếu l

71

Ngƣợc lại: dừng

Cài đặt thuật toán ShakerSort

void ShakeSort(int a[],int n) {

int int

i, j; left, right, k; left = 0; right = n-1; k = n-1;

while (left < right) {

if (a[j]< a[j-1]) {Swap(a[j], a[j-1]);k =j;}

for (j = right; j > left; j --)

left = k; for (j = left; j < right; j ++) if (a[j]> a[j+1]) {Swap(a[j], a[j-1]);k = j; }

right = k;

}

72

}

Chèn Trực Tiếp – Insertion Sort

 Giả sử có một dãy a0 , a1 ,... ,an-1 trong đó 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 của đoạn đã đƣợc sắp để có dãy mới a0 , a1,... ,ai trở nên có thứ tự. Vị trí này chính là vị trí giữa hai phần tử ak-1 và ak thỏa ak-1 < ai < ak (1≤k≤i).

73

Chèn Trực Tiếp – Insertion Sort

 Bƣớc 1: i = 1;

 Bƣớc 2: x = a[i]; Tìm vị trí pos thích hợp trong đoạn a[1]

//giả sử có đoạn a[1] đã đƣợc sắp

 Bƣớc 3: Dời chỗ các phần tử từ a[pos] đến a[i-1]

đến a[i-1] để chèn a[i] vào

 Bƣớc 4: a[pos] = x; //có đoạn a[1]..a[i] đã đƣợc sắp

 Bƣớc 5: i = i+1;

sang phải 1 vị trí để dành chổ cho a[i]

Ngƣợc lại : Dừng

Nếu i < n : Lặp lại Bƣớc 2

74

Chèn Trực Tiếp – Insertion Sort Cho dãy số : 12

4

1

6

2

8

5

15

i=1

i=2

75

Chèn Trực Tiếp – Insertion Sort

i=3

i=4

i=5

76

Chèn Trực Tiếp – Insertion Sort

i=6

i=7

77

Cài Đặt Thuật Toán Chèn Trực Tiếp

void InsertionSort(int d, int n )

{

x = a[i]; pos = i-1; // tìm vị trí chèn x while((pos >= 0)&&(a[pos] > x)) {//kết hợp dời chỗ các phần tử sẽ đứng sau x trong dãy

mới

int pos, i; int x;//lƣu giá trị a[i] tránh bị ghi đè khi dời chỗ các phần tử. for(i=1 ; i

a[pos+1] = a[pos]; pos--;

} a[pos+1] = x; // chèn x vào dãy

}

78

}

Minh Họa Thuật Toán Insertion Sort

12 2 8 1 6 4 15 5

0 1 2 4 5 6 7 3

79

Minh Họa Thuật Toán Insertion Sort

Insert a[1] into (0,0)

pos

1 6 4 15 2 12 8 2 5

4

5

6

7

0

2

1

3

x

i

80

Minh Họa Thuật Toán Insertion Sort

pos

Insert a[2] into (0, 1)

1 6 4 15 8 12 2 8 5

4

5

6

7

1

0

2

3

x

i

81

Minh Họa Thuật Toán Insertion Sort

pos

Insert a[3] into (0, 2)

2 5 8 1 6 4 15 12 5

0

1

4

5

6

7

2

3

x

i

82

Minh Họa Thuật Toán Insertion Sort

pos

Insert a[4] into (0, 3)

5 8 1 6 4 15 12 2 1

0 1 2 4 5 6 7

x

3 i

83

Minh Họa Thuật Toán Insertion Sort

pos

Insert a[5] into (0, 4)

1 2 5 6 4 15 12 6 8

0

1

2

5

6

7

3

4 i

x

84

Minh Họa Thuật Toán Insertion Sort

pos

Insert a[6] into (0, 5)

1 2 4 5 8 4 15 12 6

0 1 2 4 6 7 3

x

5 i

85

Minh Họa Thuật Toán Insertion Sort

pos

Insert a[8] into (0, 6)

1 2 4 6 8 15 15 12 5

0

1

2

4

5

7

3

6 i

x

86

Minh Họa Thuật Toán Insertion Sort

pos

1 2 4 8 12 15 6 5

0 1 2 5 6 7 4 3

87

Độ Phức Tạp Thuật Toán Insertion Sort

88

Shell Sort

 Cải tiến của phƣơng pháp chèn trực tiếp  Ý tƣởng:

 Phân hoạch dãy thành các dãy con  Sắp xếp các dãy con theo phƣơng pháp chèn

trực tiếp

 Dùng phƣơng pháp chèn trực tiếp sắp xếp lại cả

dãy.

89

Shell Sort

 Phân chia dãy ban đầu thành những dãy con gồm các

 Dãy ban đầu : a1, a2, ..., an đƣợc xem nhƣ sự xen kẽ của

phần tử ở cách nhau h vị trí

 Dãy con thứ nhất : a1 ah+1 a2h+1 ...

 Dãy con thứ hai : a2 ah+2 a2h+2 ...

 ....

 Dãy con thứ h : ah a2h a3h ...

các dãy con sau :

90

Shell Sort

 Tiến hành sắp xếp các phần tử trong cùng dãy con sẽ làm

cho các phần tử đƣợc đƣa về vị trí đúng tƣơng đối

 Giảm khoảng cách h để tạo thành các dãy con mới

 Dừng khi h=1

91

Shell Sort

 Giả sử quyết định sắp xếp k bƣớc, các khoảng cách

chọn phải thỏa điều kiện :

 hi = (hi-1 - 1)/3 và hk = 1, k = log3n-1

Ví dụ :127, 40, 13, 4, 1

 hi = (hi-1 - 1)/2 và hk = 1, k = log2n-1

Ví dụ : 15, 7, 3, 1

hi > hi+1 và hk = 1

92

Shell Sort

 h có dạng 3i+1: 364, 121, 40, 13, 4, 1

 Dãy fibonaci: 34, 21, 13, 8, 5, 3, 2, 1

 h là dãy các số nguyên tố giảm dần đến 1: 13, 11, 7, 5, 3,

1.

93

Shell Sort

 Bƣớc 1: Chọn k khoảng cách h[1], h[2], ..., h[k];

i = 1;

 Bƣớc 2: Phân chia dãy ban đầu thành các dãy con cách nhau h[i] khoảng cách.

 Bƣớc 3

Sắp xếp từng dãy con bằng phƣơng pháp chèn trực tiếp;

: i = i+1;

Nếu i > k : Dừng Ngƣợc lại : Lặp lại Bƣớc 2.

94

Shell Sort

 Cho dãy số a: 2 8

12

5

1

6

4

15

 Giả sử chọn các khoảng cách là 5, 3, 1

95

Shell Sort

 h = 5 : xem dãy ban đầu nhƣ các dãy con

 h = 3 : (sau khi đã sắp xếp các dãy con ở

bƣớc trƣớc)

96

Shell Sort

 h = 1 : (sau khi đã sắp xếp các dãy con ở bƣớc

trƣớc

97

Shell Sort

98

Shell Sort

void ShellSort(int a[],int n, int h[], int k) {

step,i,j, x,len;

int for (step = 0 ; step

len = h[step]; for (i = len; i

x = a[i]; j = i-len; // a[j] đứng kề trƣớc a[i] trong cùng dãy con while ((x=0)// sắp xếp dãy con chứa x { // bằng phƣơng pháp chèn trực tiếp

a[j+len] = a[j]; j = j - len;

} a[j+len] = x;

}

}

99

}

Minh Họa Thuật Toán Shell Sort

h = (5, 3, 1); k = 3

len = 5

joint curr

2 8 6 1 4 15 5 12

0 1 2 5 4 6 7 3

100

Minh Họa Thuật Toán Shell Sort

h = (5, 3, 1); k = 3

len = 5;

6 2 8 1 12 4 15 5

0 1 2 4 5 6 7 3

101

Minh Họa Thuật Toán Shell Sort

h = (5, 3, 1); k = 3

len = 3

joint curr

2 15 1 12 4 8 5 6

0 1 2 4 5 6 7 3

102

Minh Họa Thuật Toán Shell Sort

h = (5, 3, 1); k = 3

len = 3

joint curr joint

5 1 12 2 15 4 8 6

0 1 2 4 5 6 7 3

103

Minh Họa Thuật Toán Shell Sort

h = (5, 3, 1); k = 3

len = 3

4 1 12 2 15 6 8 5

0 1 2 4 5 6 7 3

104

Minh Họa Thuật Toán Shell Sort

h = (5, 3, 1); k = 3

len = 1

curr joint

joint joint

4 1 12 5 2 15 6 8

0 1 2 3 4 5 6 7

105

Minh Họa Thuật Toán Shell Sort

h = (5, 3, 1); k = 3

len = 1

curr joint

joint joint joint joint joint joint joint

1 4 5 12 2 15 6 8

0 1 2 3 4 5 6 7

106

Minh Họa Thuật Toán Shell Sort

1 2 4 6 8 12 15 5

0 1 2 4 5 6 7 3

107

Thuật Toán Sắp Xếp Heap Sort  Heap Sort tận dụng đƣợc các phép so sánh ở bƣớc i-1 mà thuật toán sắp xếp chọn trực tiếp không tận dụng đƣợc

 Để làm đƣợc điều này Heap sort thao tác

dựa trên cây.

108

Thuật Toán Sắp Xếp Heap Sort

 Cho dãy số : 12 2 8 5 1 6 4 15

0 1 2 3 4 5 6 7

a[0]

a[2]

a[1]

12

a[4]

a[5]

a[6]

2 8

a[3]

a[7]

1 6 4 5

15

109

Thuật toán sắp xếp Heap Sort

 Ở cây trên, phần tử ở mức i chính là phần tử lớn

trong cặp phần tử ở mức i +1, do đó phần tử ở nút gốc là phần tử lớn nhất.

 Nếu loại bỏ gốc ra khỏi cây, thì việc cập nhật cây

chỉ xảy ra trên những nhánh liên quan đến phần tử mới loại bỏ, còn các nhánh khác thì bảo toàn.

 Bƣớc kế tiếp có thể sử dụng lại kết quả so sánh của

bƣớc hiện tại.

 Vì thế độ phức tạp của thuật toán O(nlog2n)

110

Các Bƣớc Thuật Toán

 Giai đoạn 1 : Hiệu chỉnh dãy số ban đầu thành

heap

 Giai đoạn 2: Sắp xếp dãy số dựa trên heap:

◦ Bƣớc 1:Đƣa phần tử lớn nhất về vị trí đúng ở cuối

dãy:

r = n-1; Swap (a1 , ar );

◦ Bƣớc 2: Loại bỏ phần tử lớn nhất ra khỏi heap: r =

r-1;

Hiệu chỉnh phần còn lại của dãy từ a1 , a2 ...

ar thành một heap.

◦ Bƣớc 3:

111

Nếu r>1 (heap còn phần tử ): Lặp lại Bƣớc 2 Ngƣợc lại : Dừng

Minh Họa Thuật Toán

 Heap: Là một dãy các phần tử al, al+1 ,... , ar

thoả các quan hệ với mọi i  [l, r]: ◦ ai  a2i+1 ◦ ai  a2i+2 // (ai , a2i+1), (ai , a2i+2 ) là các cặp phần tử liên đới

 Cho dãy số : 12 2 8 5 1 6 4 15 Giai đoạn 1: Hiệu chỉnh dãy ban đầu thành Heap

12 2 8 5 1 6 4 15

Pt liên đới

l=3

0 1 2 3 4 5 6 7

112

Minh Họa Thuật Toán

8

15

1

6

4

5

12

2

l=2

Pt liên đới

2 3 4 5 6 7 0 1

8 15 1 6 4 5 12 2

l=1

Pt liên đới

2 3 4 5 6 7 0 1

113

Minh Họa Thuật Toán

12

8

15

6

4

5

1

2

Lan truyền việc điều chỉnh

l=1

0 2 1 5 6 7 4 3

12 8 15 6 4 2 1 5

l=0

Pt liên đới

0 2 1 5 6 7 4 3

114

Minh Họa Thuật Toán 6

12 8 5 1 15 4 2

1 2 3 4 6 7

0 5 Giai đoạn 2: Sắp xếp dãy số dựa trên Heap

15 12 8 5 1 6 4 2

0 1 2 3 4 5 6 7

2 12 8 5 1 6 4 15

r=6

0 1 2 3 4 5 6 7

115

Minh Họa Thuật Toán

Hiệu chỉnh Heap

8 5 1 6 4 15 2 12

2

3

4

5

6

7

0

1

l=2

Pt liên đới

8 5 1 6 4 15 2 12

l=1

Pt liên đới

2 3 4 5 6 7 0 1

116

Minh Họa Thuật Toán

12 8 5 1 6 4 15 2

l=0

Pt liên đới

1 2 3 4 5 6 7 0

2 8 5 1 6 4 15 12

l=2

1 2 3 4 5 6 7 0

117

Minh Họa Thuật Toán

Lan truyền việc điều chỉnh

2

8

12

5

1

6

4

15

l=2

1 2 0 3 4 5 6 7

5

8

12

2

1

6

4

15

l=2

1 2 0 3 4 5 6 7

118

Minh Họa Thuật Toán

12 5 8 2 1 6 4 15

0 1 2 3 4 5 6 7

4 5 8 2 1 6 12 15

Thực hiện với r= 5,4,3,2 ta đƣợc

0 1 2 3 4 5 6 7

1 2 4 5 6 8 12 15

0 1 2 4 5 6 7 3 119

Cài Đặt Thuật Toán

 Hiệu chỉnh al, al+1,..,ar thành Heap

void shift(int a[],int l,int r) {

int x,i,j; i=l; j=2*i+1; x=a[i]; while(j<=r) if(j

120

Cài Đặt Thuật Toán

j++; //luu chi so cua phan tu nho nhat trong hai phan tu if(a[j]<=x) return; else {

a[i]=a[j]; a[j]=x; i=j; j=2*i+1; x=a[i];

}

}

}

121

Cài Đặt Thuật Toán  Hiệu chỉnh a0,..an-1Thành Heap void CreateHeap(int a[],int n) {

int l; l=n/2-1; while(l>=0) {

shift(a,l,n-1); l=l-1;

}

122

}

Cài Đặt Thuật Toán  Hàm HeapSort

void HeapSort(int a[],int n) {

int r; CreateHeap(a,n); r=n-1; while(r>0) {

Swap(a[0],a[r]);//a[0] la nút gốc r--; if(r>0)

shift(a,0,r);

}

}

123

Quick Sort

 Ý tƣởng:

 Giải thuật QuickSort sắp xếp dãy a1, a2 ..., aN dựa trên

• Phần 1: Gồm các phần tử có giá trị bé 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ị lớn hơn x

việc phân hoạch dãy ban đầu thành 3 phần :

với x là giá trị của một phần tử tùy ý trong dãy ban đầu.

124

Quick Sort

 Sau khi thực hiện phân hoạch, dãy ban đầu đƣợc phân

thành 3 đoạn:

• 2. ak = x , với k = j+1 .. i-1

• 1. ak ≤ x , với k = 1 .. j

 Đoạn thứ 2 đã có thứ tự.

 Nếu các đoạn 1 và 3 chỉ có 1 phần tử : đã có thứ tự

• 3. ak  x , với k = i..N

 khi đó dãy con ban đầu đã đƣợc sắp.

125

Quick Sort

 Đoạn thứ 2 đã có thứ tự.

 Nếu các đoạn 1 và 3 có nhiều hơn 1 phần tử thì dãy 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 phân hoạch từng dãy con theo cùng phƣơng pháp phân hoạch dãy ban đầu vừa trình bày …

126

Giải Thuật Quick Sort

 Bƣớc 1: Nếu left ≥ right //dãy có ít hơn 2 phần tử

Kết thúc;

//dãy đã đƣợc sắp xếp  Bƣớc 2: Phân hoạch dãy aleft … aright thành các đoạn:

aleft.. aj, aj+1.. ai-1, ai.. aright

Đoạn 1 x Đoạn 2: aj+1.. ai-1 = x Đoạn 3: ai.. aright  x  Bƣớc 3: Sắp xếp đoạn 1: aleft.. aj  Bƣớc 4: Sắp xếp đoạn 3: ai.. aright

127

Giải Thuật Quick Sort  Bƣớc 1 : Chọn tùy ý một phần tử a[k] trong dãy là

giá trị mốc ( l ≤ k ≤ r):

 Bƣớc 2 : Phát hiện và hiệu chỉnh cặp phần tử

x = a[k]; i = l; j = r;

 Bƣớc 2a : Trong khi (a[i]

 Bƣớc 2b : Trong khi (a[j]>x) j--;

 Bƣớc 2c : Nếu i< j

Swap(a[i],a[j]);

 Bƣớc 3 : Nếu i < j:

a[i], a[j] nằm sai chỗ :

Lặp lại Bƣớc 2.

Ngƣợc lại: Dừng

128

Quick Sort – Ví Dụ

 Cho dãy số a: 8

12

2

5

1

6

4

15

x = a[3] = 5

Phân hoạch đoạn l =0, r = 7:

12

2

8

5

1

6

4

15

l=0

r=7

129

Quick Sort – Ví Dụ

4

2

8

5

1

6

12

15

i = 0

j = 6

l=0

r=7

4

2

8

5

1

6

12

15

i = 1

i = 2

l=0

r=7

j = 3

j = 5

j = 4

130

Quick Sort – Ví Dụ  Phân hoạch đoạn l = 0, r = 2:

4

2

1

5

8

6

12

15

l = 0

r =3

i = 0

j = 2

131

Quick Sort – Ví Dụ  Phân hoạch đoạn l =4, r = 7:

1

2

4

5

8

6

12

15

r =7

l = 4 i = 4

j = 6

j = 6

j = 7

1

2

4

5

8

12

15

6 i = 4

l = 4

r =7

132

Quick Sort – Ví Dụ

 Phân hoạch đoạn l =6, r = 7:

1

2

4

5

6

8

12

15

133

Quick Sort

void QuickSort(int a[], int left, int right) { int i, j, x;

x = a[(left+right)/2]; i = left; j = right; do {

if(i <= j)

while(a[i] < x) i++; while(a[j] > x) j--;

{

Swap(a[i],a[j]); i++ ; j--;

} while(i <= j);

}

if(left

if(i

QuickSort(a, left, j);

QuickSort(a, i, right);

}

134

Quick Sort

 Phân hoạch đọan [0,7]

i 0 1 2 4 5 6 j 7 3

5 5

12 2 8 1 6 4 15

right

X

left

135

Quick Sort

 Phân hoạch đọan [0,7]

X 5

0 i 1 2 4 j 5 6 7 3

4

2

8

1

6

12

15

5

right left

136

Quick Sort

 Phân hoạch đọan [0,2]

0

1

j 2 i 4

5

6

7

3

right

left

4 2 1 8 6 12 15 5

137

Quick Sort

 Phân hoạch đọan [0,2]

i 0

1

j 2

3

4

5

6

7

4 2 2 1 5 8 6 12 15

right

left

X

138

Quick Sort

 Phân hoạch đọan [4,7]

0 1 2 3

i 4

6 5

j 7

X

1 2 4 5 8 12 15 6 6

right left

139

Quick Sort

 Phân hoạch đọan [5,7]

0

1

2

3

j 4 i 5

6

7

right

1 2 4 5 6 8 12 15

left

140

Quick Sort

 Phân hoạch đọan [5,7]

0 1 2 3 4 i 5 6 j 7

right

1 2 4 5 6 8 12 12 15

left

141

Quick Sort

0 1 2 3 4 5 6 7

1 2 4 5 6 8 12 15

142

Độ Phức Tạp Của Quick Sort

143