1. Trang chủ
  2. » Luận Văn - Báo Cáo

BÁO cáo bài tập NHÓM PHÂN TÍCH THIẾT kế GIẢI THUẬT đề tài phân tích độ phức tạp của giải thuật sắp xếp quick sort

16 12 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Phân Tích Độ Phức Tạp Của Giải Thuật Sắp Xếp Quick Sort
Tác giả Trần Kim Phước, Nguyễn Viết Phú, Lê Thành Trung
Người hướng dẫn Trần Anh Tuấn
Trường học Trường Đại Học Giao Thông Vận Tải
Chuyên ngành Công Nghệ Thông Tin
Thể loại báo cáo
Năm xuất bản 2021
Thành phố TP. Hồ Chí Minh
Định dạng
Số trang 16
Dung lượng 171,33 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Bài toán sắp xếp là chúng ta sẽ sắp xếp lại các phần tử của một danh sách theo chiều tăng hoặc giảm dần theo một tiêu chí nào đó của phần tử trong danh sách.Ví dụ như bạn sắp xếp danh sá

Trang 1

TRƯỜNG ĐẠI HỌC GIAO THÔNG VẬN TẢI TP HỒ CHÍ MINH

KHOA CÔNG NGHỆ THÔNG TIN

BÁO CÁO BÀI TẬP NHÓM PHÂN TÍCH THIẾT KẾ GIẢI THUẬT

Đề tài: Phân tích độ phức tạp của giải thuật sắp xếp Quick sort

Chuyên ngành: CÔNG NGHỆ THÔNG TIN

Giảng viên hướng dẫn : Trần Anh Tuấn Môn học: Phân tích thiết kế giải thuật

Trang 2

2 NGUYỄN VIẾT PHÚ MSSV: 1951120121

3 LÊ THÀNH TRUNG MSSV: 1951120157

MỤC LỤC:

1 Quick sort là gì?

2 Thuật toán phân đoạn (partition)

3 Ý tưởng thuật toán

4 Cách chọn phần tử làm pivot

5 Phương pháp phân hoạch

6 Giải thuật Quick sort

III Minh họa chương trình và phân tích độ phức tạp của thuật toán 4

Trang 3

I Tổng quan về đề tài

Bài toán sắp xếp chắc chắn không còn xa lạ gì với mỗi chúng ta, nó là một trong những bài toán được bắt gặp nhiều nhất trong thực tế Ví dụ như sắp xếp danh sách lớp học, sắp xếp quyển sách, sắp xếp tiền… Vậy thì bài toán sắp xếp là gì? Bài toán sắp xếp là chúng ta sẽ sắp xếp lại các phần tử của một danh sách theo chiều tăng hoặc giảm dần theo một tiêu chí nào đó của phần tử trong danh sách.Ví dụ như bạn sắp xếp danh sách lớp học theo điểm trung bình từ cao đến thấp, sắp những quyển sách theo kích cỡ từ nhỏ đến lớn, sắp xếp những tờ tiền theo mệnh giá từ thấp đến cao… Mục đích của việc sắp xếp chính là giúp ta có cái nhìn tổng quan hơn về những dữ liệu mà ta có, dễ dàng tìm kiếm những phần tử đứng nhất về một tiêu chí nào đó Trong lập trình, sắp xếp không chỉ đơn giản là để tìm một hoặc nhiều phần tử đứng đầu về một tiêu chí nào đó hay để có cái nhìn tổng quan

về dữ liệu, sắp xếp còn làm cơ sở cho các giải thuật nâng cao với hiệu suất cao hơn Có rất nhiều thuật toán sắp xếp được sử dụng như: Merge sort, Selection sort, Quick sort, Bubble sort, Trong khuôn khổ đề tài được giao, nhóm chúng em xin được nghiên cứu và trình bày về giải thuật sắp xếp Quick sort, một thuật toán có khà năng sắp xếp với tốc độ cao hơn hẳn so với các thuật toán Insertion sort, Selection sort hay Bubble sort.

Trang 4

II Cơ sở lý thuyết:

1 Quick sort là gì?

Sắp xếp nhanh (Quick sort) hay sắp xếp phân đoạn (Partition) là là thuật toán sắp xếp dựa trên kỹ thuật chia để trị, cụ thể ý tưởng là: chọn một điểm làm chốt (gọi là pivot), sắp xếp mọi phần tử bên trái chốt đều nhỏ hơn chốt và mọi phần tử bên phải đều lớn hơn chốt, sau khi xong ta được 2 dãy con bên trái và bên phải, áp dụng tương tự cách sắp xếp này cho 2 dãy con vừa tìm được cho đến khi dãy con chỉ còn

1 phần tử

Phần tử được chọn làm chốt rất quan trọng, nó quyết định thời gian thực thi của thuật toán Phần tử được chọn làm chốt tối ưu nhất là phần tử trung vị, phần tử này làm cho số phần tử nhỏ hơn trong dãy bằng hoặc sấp xỉ số phần tử lớn hơn trong dãy Tuy nhiên, việc tìm phần tử này rất tốn kém, phải có thuật toán tìm riêng, từ đó

NHẬN XÉT CỦA GIÁO VIÊN:

Trang 5

làm giảm hiệu suất của thuật toán tìm kiếm nhanh, do đó, để đơn giản, người ta thường sử dụng phần tử chính giữa làm chốt.

2 Thuật toán phân đoạn (Partition)

Đặt pivot là phần tử cuối cùng của dãy số Arr Chúng ta bắt đầu từ phần tử trái nhất của dãy số có chỉ số là left, và phần tử phải nhất của dãy số có chỉ số là right

-1 (bỏ qua phần tử pivot) Khi nào left < right mà arr[left] > pivot và arr[right] < pivot thì đổi chỗ hai phần tử left và right Sau cùng, ta đổi chỗ hai phần tử left và pivot cho nhau Khi đó, phần tử left đã đứng đúng vị trí và chia dãy số làm đôi (bên trái và bên phải).

3 Ý tưởng thuật toán

● Chọn một giá trị khóa v làm chốt (pivot).

● Phân hoạch dãy A[0]…A[n-1] thành hai mảng con “bên trái” và “bên phải”

Mảng con “bên trái” bao gồm các phần tử có khóa nhỏ hơn chốt, mảng con

“bên phải” bao gồm các phần tử có khóa lớn hơn oặc bằng chốt.

● Sắp xếp mảng con “bên trái” và mảng con “bên phải”.

● Sau khi đã sắp xếp được mảng con “bên trái” và mảng con “bên phải” thì

mảng đã cho sẽ được sắp xếp bởi vì tất cả các khóa trong mảng con “bên trái” đều nhỏ hơn các khóa trong mảng con “bên phải”.

● Việc sắp xếp các mảng con “bên trái” và “bên phải” cũng được tiến hành

bằng phương pháp nói trên

● Một mảng chỉ gồm một phần tử hoặc gồm nhiều phần tử có khóa bằng nhau

thì dã có thứ tự.

4 Cách chọn phần tử làm pivot

● Chọn giá trị khóa lớn nhất trong hai phần tử có khóa khác nhau đầu tiên kể

từ trái qua.

● Nếu mảng chỉ gồm một phần tử hay gồm nhiều phần tử có khóa bằng nhau

thì không có chốt.

● Chọn phần tử bên trái ngoài cùng (phần tử đầu tiên của mảng)

● Chọn phần tử bên phải ngoài cùng (phần tử cuối cùng của mảng)

● Ngẫu nhiên một phần tử (sử dụng hàm random mà ngôn ngữ lập trình cung

cấp)

● Phần tử chính giữa của mảng.

5 Phương pháp phân hoạch

NHẬN XÉT CỦA GIÁO VIÊN:

Trang 6

● Để phân hoạch mảng, ta dùng hai “con nháy” L và R trong đó L từ bên trái

và R từ bên phải

● Ta cho L chạy sang phải cho tới khi gặp phần tử có khóa lớn hơn hoặc bằng chốt.

● Cho R chạy sang trái cho tới khi gặp phần tử có khóa nhỏ hơn chốt.

● Tại chỗ dừng của L và R nếu L < R thì hoán vị A[L], A[R].

● Lặp lại quá trình dịch sang phải, sang trái của hai “con nháy” L và R cho đến khi L > R.

● Khi đó L sẽ là điểm phân hoạch, cụ thể là A[L] là phần tử đầu tiên của mảng con “bên phải”.

6 Giải thuật Quick sort

● Để sắp xếp mảng A[i]…A[j] ta làm các bước sau:

− Xác định chốt trong mảng A[i]…A[j].

− Phân hoạch mảng A[i]…A[j] đã cho thành hai mảng con A[i]…A[k-1] và A[k]…A[j].

− Sắp xếp mảng A[i]…A[k-1] bằng đệ quy.

− Sắp xếp mảng A[k]…A[j] bằng đệ quy.

● Đệ quy sẽ dừng khi không còn tìm thấy chốt.

Trang 7

III Minh họa chương trình và phân tích độ phức tạp của thuật toán

1 Minh họa chương trình

- Hàm phân hoạch

int   partition  ( int   arr [],  int   low ,  int   high ) {

     int   pivot  =  arr [ high ];    

     int    = ( low  -  1 );  

       for  ( int    =  low ;  j  <=  high -  1 ;  j ++)     {

         if  ( arr [ ] <=  pivot )         {

       i ++;    

       swap (& arr [ ], & arr [ ]);

        }     }      swap (& arr [  +  1 ], & arr [ high ]);

     return  ( i  +  1 );

}

- Hàm Quick sort void   quickSort ( int   arr [],  int   low ,  int   high ) {

     if  ( low  <  high )     {

         int   pi  =  partition ( arr ,  low ,  high );

         quickSort ( arr ,  low ,  pi  -  1 );

         quickSort ( arr ,  pi  +  1 ,  high );

    } }

- Toàn bộ source code chương trình

#include  <iostream>

using   namespace   std ;

void   swap ( int*   ,  int*   ) {

     int    = * a

    * a  = * b

    * b  =  t }

int   partition  ( int   arr [],  int   low ,  int   high ) {

Trang 8

     int   pivot  =  arr [ high ];    

     int    = ( low  -  1 );  

       for  ( int    =  low ;  j  <=  high -  1 ;  j ++)     {

         if  ( arr [ ] <=  pivot )         {

       i ++;    

       swap (& arr [ ], & arr [ ]);

        }     }      swap (& arr [  +  1 ], & arr [ high ]);

     return  ( i  +  1 );

}  

void   quickSort ( int   arr [],  int   low ,  int   high ) {

     if  ( low  <  high )     {

         int   pi  =  partition ( arr ,  low ,  high );

         quickSort ( arr ,  low ,  pi  -  1 );

         quickSort ( arr ,  pi  +  1 ,  high );

    } }  

/* Function to print an array */

void   printArray ( int   arr [],  int   size ) {

     int   ;      for  ( i 0 ;  i  <  size ;  i ++)          printf ( "%d " ,  arr [ ]);

     printf ( \n " );

}  

int   main () {

     int   ;      cout   <<   "Nhap so phan tu: "  ;      cin   >>   ;

     int   [ ];

     cout   <<   "Nhap vao gia tri moi phan tu cua mang: "   <<   endl ;      for  ( int   = ; < ; ++)

    {          cout   << "a[" <<   << "]"   <<   " = " ;          cin   >>   [ ];

    }      quickSort ( ,  0 ,  n 1 );

     cout   <<   "Mang sau khi duoc sap xep: "   <<   endl ;      printArray ( ,  n );

     system ( "pause" );

     return   ; }

Trang 9

2 Đánh giá độ phức tạp của thuật toán

- Trường hợp xấu nhất

Trong trường hợp xấu nhất, phân hoạch bị lệch Nghĩa là mảng có n phần tử phân hoạch thành hai mảng con Mảng con “bên trái” gồm n-1 phần tử và mảng con bên phải chỉ gồm 1 phần tử.

void   quickSort ( int   arr [],  int   low ,  int   high ) {

     if  ( low  <  high )     {

         int   pi  =  partition ( arr ,  low ,  high );

         quickSort ( arr ,  low ,  pi  -  1 );

         quickSort ( arr ,  pi  +  1 ,  high );

    } }

T(n) = T(n-1) + T(1) + n

= T(n-1) + n + 1

= T(n-2) + (n-1) + n + 2

= T(n-3) + (n-2) + (n-1) + n +3

= T(1) +(2 + 3+ 4 +…+ n) + n - 1

= 1 + 2 + 3 +…+ n + n - 1 = n(n+1) 2 + n – 1 🡺 O(n 2 )

- Trường hợp tốt nhất Trong trường hợp tốt nhất khi ta chọn được chốt sao cho hai mảng con có kích thước bằng nhau và bằng n/2 Khi đó ta có độ phức tạp của thuật toán như sau

quickSort ( int   arr [],  int   low ,  int   high ) {

     if  ( low  <  high )

Trang 10

    {          int   pi  =  partition ( arr ,  low ,  high );

         quickSort ( arr ,  low ,  pi  -  1 );

         quickSort ( arr ,  pi  +  1 ,  high );

    } }

T(n) = 2T( n 2 ) + n

= 2[2T( 2 n 2) + n 2 ] + n

= 2 2 [2T( 2 n 3 ) + 2 n 2] + 2n

= 2 3 [2T( 2 n 4 ) + 2 n 3] + 3n

= 2 k T( 2 n k ) + kn

= 2 k T(1) + kn = n.1 + n.logn 🡺O(n.logn)

Trang 11

IV Kết luận

Quick Sort là một thuật toán sắp xếp hiệu quả dựa trên việc phân chia mảng dữ liệu thành các nhóm phần tử nhỏ hơn Giải thuật sắp xếp nhanh chia mảng thành hai phần bằng cách so sánh từng phần tử của mảng với một phần tử được gọi là phần

tử chốt Một mảng bao gồm các phần tử nhỏ hơn hoặc bằng phần tử chốt và một mảng gồm các phần tử lớn hơn phần tử chốt.

Quá trình phân chia này diễn ra cho đến khi độ dài của các mảng con đều bằng 1 Với phương pháp đệ quy ta có thể sắp xếp nhanh các mảng con sau khi kết thúc chương trình ta được một mảng đã sắp xếp hoàn chỉnh Giải thuật sắp xếp nhanh tỏ

ra khá hiệu quả với các tập dữ liệu lớn khi mà độ phức tạp là O(nlogn).

Trang 12

V Câu hỏi củng cố

1 Khi nào thì độ phức tạp của thuật toán là lớn nhất và khi nào là nhỏ nhất?

Trả lời: Độ phức tạp của thuật toán là lớn nhất khi mảng bị phân hoạch lệch Nghĩa là sau khi phân hoạch mảng đã cho gồm n phần tử sẽ được chia thành hai mảng con Mảng con bên trái gồm n-1 phần tử và mảng con bên phải chỉ có một phần tử duy nhất Khi đó độ phức tạp của thuật toán sẽ là O(n 2 ) Độ phức tạp của thuật toán là nhỏ nhất khi ta chọn được chốt sao cho hai mảng con có kích thước bằng nhau và bằng n/2 Khi đó độ phức tạp của thuật toán là O(n.logn).

2 Cho mảng sau:

Hãy nêu cách chọn pivot sao cho khi sắp xếp mảng trên ta được độ phức tạp của thuật toán là nhỏ nhất.

Trả lời:

Đầu tiên, ta chọn 4 là pivot Khi đó mảng sẽ được chia thành hai mảng con Mảng con bên trái gồm các phần tử nhỏ hơn 4

Và mảng con bên phải sẽ gồm các phần tử lớn hơn 4

Ở mảng con bên trái, ta chọn 2 là pivot Khi đó mảng sẽ được sắp xếp thành

Ở mảng con bên phải, ta chọn 6 là pivot Khi đó mảng sẽ được sắp xếp thành

Kết thúc thuật toán, mảng đã cho được sắp xếp theo đúng thứ tự với độ phức tạp là O(n.logn)

Trang 13

3 Dùng giải thuật Quick Sort để sắp xếp mảng sau theo đúng thứ tự tăng dần.

Trong ví dụ ta luôn chọn phần tử pivot là phần tử đứng giữa danh sách

Do ngẫu nhiên, phần tử chốt a[4]=7 là phần tử lớn nhất trong dãy, ta tìm từ trái sang phải không có phần tử nào lớn hơn phần tử chốt, do đó ta đổi phần

tử chốt với phần tử cuối cùng, danh sách được chia thành hai danh sách con

là a[1 6] và a[7 7]

Việc phân chia tiếp tục với danh sách con a[1 6] Phần tử pivot được chọn

là a[4]=1 Từ trái sang phải tìm được phần tử đầu tiên lớn hơn a[4]=1 là a[1]=2, từ phải sang phần tử đầu tiên <=1 là chính a[4] Đổi chố hai phần tử này

Đi tiếp sang phải ta được a[2]>1 ở phía ngược lại đi tiếp sang trái tìm được phần tử nhỏ hơn hoặc bằng chốt là chính a[1]=1nhưng lúc này hai đường đã chạm nhau nên ta không đổi nữa Do vậy a[1 6] được phân chia thành hai danh sách con a[1 1] và a[2 6].

Tiếp tục phân chia a[2 6] với phần tử chốt {\displaystyle a[4]= 2 ta được

Tiếp tục phân chia a[3 6] với phần tử chốt a[5]=4 ta được

Tiếp tục phân chia a[3 4] với phần tử chốt a[4]=4 và a[5 6] với phần tử chốt a[6]=5 ta được

Trang 14

VI Tài liệu tham khảo

https://nguyenvanhieu.vn/thuat-toan-sap-xep-quick-sort/#thuat-toan-phan-doan

fbclid=IwAR0pBWN3sUaoGkzOh6PRwi-d7BDnLfc5EZrKfo2iWoNtaJUHwxHK5EIAfhQ

Trang 15

7.

Ngày đăng: 23/12/2023, 22:44

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm

w