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

Tổng quan về thuật toán sắp xếp

21 2,2K 16
Tài liệu đã được kiểm tra trùng lặp

Đ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 đề Tổng Quan Về Thuật Toán Sắp Xếp
Trường học Trường Đại Học Công Nghệ Thông Tin
Chuyên ngành Công Nghệ Thông Tin
Thể loại Bài Tiểu Luận
Thành phố Hà Nội
Định dạng
Số trang 21
Dung lượng 154,37 KB

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

Nội dung

Tổng quan về thuật toán sắp xếpTrước tiên để hiểu rõ về thuật toán sắp xếp mình xin nói qua về nó trước Một trong những vấn đề nền tảng của khoa học máy tính là sắp xếp một t

Trang 1

Tổng quan về thuật toán sắp xếp

Trước tiên để hiểu rõ về thuật toán sắp xếp mình xin nói qua về nó trước

Một trong những vấn đề nền tảng của khoa học máy tính là sắp xếp một tập các phần tử cho trước theo thứ tự nào đó Có rất nhiều các giải pháp cho vấn đề này, được biết đến như là các thuật toán sắp xếp (sorting algorithms) Bên cạnh các thuật toán sắp xếp đơn giản và rất rỏ ràng, như là sắp xếp nổi bọt (bubble sort) Một số khác, như phương pháp sắp xếp nhanh (quick sort) thì lại rất phức tạp nhưng đổi lại có kết quả thực thi nhanh hơn một cách đáng kể

Dưới đây là liên kết tới các mô tả, phân tích, và mã nguồn cho 7 thuật toán sắp xếp quan trọng, phổ biến nhất hiện nay

Ví dụ, O(n) có nghĩa là thuật toán có độ phức tạp tuyến tính Cụ thể hơn , nó sẽ mất thời gian gấp 10 lần cho việc xử lý trên tập dữ liệu có 100 phần tử so với tập chỉ có 10 phần tử (10 * 10 = 100) Nếu độ phức tạp là O(n2) (quadratic complexity), thì nó sẽ phải tiêu tốn thời gian gấp 100 lần để xử lý trên tập 100 phần tử so với tập dữ liệu chỉ gồm 10 phần tử.Hai nhóm thuật toán sắp xếp được phân như sau: nhóm thứ nhất có độ phức tạp là O(n2) bao gồm bubble, insertion, selection, và shell sorts; Nhóm thứ hai có độ phức tạp là O(n log n) gồm heap, merge, và quick sorts

Bên cạnh độ phức tạp của thuật toán, tốc độ của các thuật toán sắp xếp có thể được so sánh dựa vào kinh nghiệm có được từ việc thử trên các tập dữ liệu Vì tốc độ sắp xếp có thể thay đổi rất nhiều tùy theo đặc điểm của dữ liệu, nên để các kết quả thống kê chính

Trang 2

xác dựa trên kinh nghiệm đòi hỏi việc chạy các thuật toán nhiều lần trên các dữ liệu khác nhau và tính trung bình Thông thường tập dữ liệu kiểm tra được tạo ngẫu nhiên.

Trong các biểu đồ thể hiện mức độ hiệu quả của thuật toán dưới đây, đường thấp nhất là

"tốt nhất" Ghi nhớ rằng "tốt nhất" ở đây là một khái niệm không tuyệt đối vì nó còn tùy vào trường hợp sử dụng của bạn - nếu nhìn biểu đồ bạn sẽ thấy quick sort có lẽ là thuật toán nhanh nhất, nhưng nếu sử dụng nó để sắp xếp một tập 20 phần tử thì cũng giống như vác đại bác ra bắn ruồi

Đồ thị trên đã thể hiện khá rỏ, Bubble sort là giải pháp cực kì không hiệu quả, và shell sort là sự cải tiến tạo ra cuộc bứt phá hết sức ngoạn mục Chú ý rằng vào đường ngang đầu tiên của khu vực đồ thị thể hiện thời gian 100 giây- bạn sẽ thấy rằng không có thuật toán nào trong số này mà bạn muốn sử dụng cho tập dữ liệu lớn của một ứng dụng tương tác Ngay cả khi dùng shell sort, người sử dụng cũng có nguy cơ ngồi bấm móng tay nếu bạn cố gắng sắp xếp nhiều hơn 10,000 phần tử

Nhìn từ phương diện tươi sáng hơn, tất cả những thuật toán thuộc nhóm O(n2) đều đơn giản một cách không ngờ (có thể shell sort là một ngoại lệ hơi phức tạp hơn) Với những chương trình dùng kiểm tra nhanh, những mẩu thử nghiệm gấp, hay các phần mềm dành cho người sử dụng nội bộ, chúng không phải là những lựa chọn tồi nếu bạn không đặt quá nặng về hiệu năng

Trang 3

Trong trường hợp tốc độ là ưu tiên hàng đầu, những giải thuật thuộc nhóm O(n log n) nên được sử dụng Chú ý rằng thời gian trong đồ thị ngay trên đây được đo theo từng phần 10 của giây thay vì từng trăm giây như đồ thị của nhóm O(n2).

Tuy nhiên mọi thứ thì không thật sự dễ dàng với các ứng dụng thực tiễn, bạn phải đứng trước sự lựa chọn cân bằng (trade-offs) giữa các yếu tố Những thuật toán thuộc nhóm O(n log n) thì rất nhanh, nhưng tốc độ đó có được do phải trả giá cho sự phức tạp trong triển khai Trong trường hợp đệ quy, các cấu trúc dữ liệu nâng cao, mảng đa chiều - việc

sử dụng những thuật toán này sẽ tạo ra nhiều vấn đề phát sinh rất khó chịu ( nhưng mà nên nhớ thuật có độ phức tạp O(n log n) nó khó nhưng mà nó nhanh)

Post added at 01:36 PM Previous post was at 01:30 PM

-Bây giờ vào phần chính thôi

Trước hết mình nói qua về thuật heap sort

Heap sort là thuật toán chậm nhất trong số các thuật toán sắp xếp thuộc nhóm có độ phức tạp O(n log n), nhưng không giống như Merge và Quick sort nó không đòi hỏi sự đệ quy phức tạp hay nhiều mảng dữ liệu để xử lý Điều này làm cho nó trở thành một lựa chọn hấp dẫn với tập dữ liệu rất lớn hàng triệu phần tử Tuy nhiên sự lựa chọn thích hợp lúc nào cũng còn tùy thuộc vào kết cấu hạ tầng và mục tiêu của ứng dụng

Heap sort hoạt động cũng như sự gợi ý trong tên gọi - nó bắt đầu bằng việc xây dựng một heap out của tập dữ liệu, và sau đó loại phần tử lớn nhất và đặt nó vào vị trí cuối của mảng được sắp xếp Sau việc xóa phần tử lớn nhất, nó tái cấu trúc heap và di chuyển phần tử lớn nhất kế tiếp còn lại và đặt nó vào vị trí mở kế cuối của mảng được sắp xếp

Trang 4

Thao tác này được lặp lại cho tới khi không còn phần tử bên trái trong heap và mảng được sắp xếp đã đầy Cách triển khai căn bản đòi hỏi hai mảng dữ liệu - một giữ heap và một giữ những phần tử đã được sắp xếp.

Việc thực hiện tiến trình sắp xếp chỉ trong một mảng duy nhất nhằm tiết kiệm không gian của mảng thứ hai là cần thiết, giải thuật sau đây dùng một ít kỉ xảo để chỉ sử dụng cùng một mảng cho lưu trử Heap và mảng đã được sắp xếp Bất cứ khi nào một phần tử được xóa khỏi Heap, nó giải phóng một không gian lưu trử ở cuối mảng mà phần tử bị xóa có thể được đặt vào

<SPAN style="FONT-FAMILY: arial">//doi cho </SPAN>

<SPAN style="FONT-FAMILY: arial">void Swap(int

&a,int &b)

{

int t; t=a; a=b; b=t;

}

//thu tuc hieu chinh heap

void Shift(int a[],int r,int l)

{ int i,j,x; i=l; j=2*i; //phan tu lien doi

Trang 5

//phuong phap cay

void HeapSort(int a[],int n)

{ int r;

CreateHeap(a,n);

r=n-1; //vi tri phan tu cuoi mang while(r>0)

Trang 6

Thuật toán sắp xếp nổi bọt (Bubble sort)

Thuật toán sắp xếp nổi bọt là một trong các thuật toán phổ biến nhất với những lập trình viên mới bắt đầu sự nghiệp Thuật toán này vận hành dựa trên việc so sánh liên tục các phần tử cạnh nhau của một mảng các số chưa được sắp xếp và cho phép phần tử nào nhẹ hơn sẽ được nổi lên trên (chuyển vị trí sang trái hoặc phải tùy theo việc muốn sắp xếp theo thứ tự tăng dần hay giảm dần) Bubble sort là thuật toán dễ triển khai nhưng cũng là một trong các thuật toán sắp xếp có hiệu suất kém nhất (độ phức tạp lên tới O(n2)) Để có thể xem minh họa về thuật toán này, bạn có thể truy cập trang Algolist (trang web chuyên minh họa về các thuật toán) Tuy vậy, có một cách hay hơn và dễ hiểu hơn để biết về thuật toán nổi tiếng (về sự đơn giản và chậm chạp) này là xem video dưới đây do các thành viên thuộc trường đại học Sapientia (Romania) trình diễn :

Giải thuật

Sắp xếp từ trên xuống

Giả sử dãy cần sắp xếp có n phần tử Khi tiến hành từ trên xuống, ta so sánh hai phần tử đầu, nếu phần tử đứng trước lớn hơn phần tử đứng sau thì đổi chỗ chúng cho nhau Tiếp tục làm như vậy với cặp phần tử thứ hai và thứ ba và tiếp tục cho đến cuối tập hợp dữ liệu, nghĩa là so sánh (và đổi chỗ nếu cần) phần tử thứ n-1 với phần tử thứ n Sau bước này phần tử cuối cùng chính là phần tử lớn nhất của dãy

Sau đó, quay lại so sánh (và đổi chố nếu cần) hai phần tử đầu cho đến khi gặp phần tử thứ n-2

Ghi chú: Nếu trong một lần duyệt, không phải đổi chỗ bất cứ cặp phần tử nào thì danh sách đã được sắp xếp xong

Sắp xếp từ dưới lên

Sắp xếp từ dưới lên so sánh (và đổi chỗ nếu cần) bắt đầu từ việc so sánh cặp phần tử thứ n-1 và n Tiếp theo là so sánh cặp phần tử thứ n-2 và n-1, cho đến khi so sánh và đổi

Trang 7

chỗ cặp phần tử thứ nhất và thứ hai Sau bước này phần tử nhỏ nhất đã được nổi lên vị trí trên cùng (nó giống như hình ảnh của các "bọt" khí nhẹ hơn được nổi lên trên) Tiếp theo tiến hành với các phần tử từ thứ 2 đến thứ n.

Trang 8

Thuật toán sắp xếp Nhanh (Quick-sort)

Sắp xếp nhanh (Quicksort), còn được gọi là sắp xếp kiểu phân chia (part sort) là một thuật toán sắp xếp phát triển bởi C.A.R Hoare, dựa trên phép phân chia danh sách được sắp thành hai danh sách con Khác với sắp xếp trộn, chia danh sách cần sắp xếp a[1 n] thành hai danh sách con có kích thước tương đối bằng nhau nhờ chỉ số đứng giữa danh sách, sắp xếp nhanh chia nó thành hai danh sách bằng cách so sánh từng phần tử của danh sách với một phần tử được chọn được gọi là phần tử chốt Những phần tử nhỏ hơn hoặc bằng phần tử chốt được đưa về phía trước và nằm trong danh sách con thứ nhất, các phần tử lớn hơn chốt được đưa về phía sau và thuộc danh sách đứng sau Cứ tiếp tục chia như vậy tới khi các danh sách con đều có độ dài bằng 1

Phần tử chốt (pivot)

Kỹ thuật chọn phần tử chốt ảnh hưởng khá nhiều đến khả năng rơi vào các vòng lặp vô hạn đối với các trường hợp đặc biệt Tốt nhất là chọn phần tử chốt là trung vị của danh sách Khi đó sau log2(n) lần phân chia ta sẽ đạt tới kích thước danh sách bằng 1 Tuy nhiên điều đó rất khó Có các cách chọn phần tử chốt như sau:

- Chọn phần tử đứng đầu hoặc đứng cuối làm phần tử chốt

Trang 9

Sau khi phần tử chốt được chọn giải thuật phân chia nên tiến hành như thế nào?

- Một giải pháp đơn giản nhất cho vấn đề này là duyệt từ đầu đến cuối lần lượt so sánh các phần tử của danh sách với phần tử chốt Theo cách này, ta phải tiến hành n phép so sánh, ngoài ra còn phải dành n đơn vị bộ nhớ để lưu giữ các giá trị trung gian

- Một giải pháp khác được đề nghị là duyệt theo hai đường Một đường từ đầu danh sách, một đường từ cuối danh sách Theo cách này, ta tìm phần tử đầu tiên tính từ trái lớn hơn phần tử chốt và phần tử đầu tiên phía phải nhỏ hơn hoặc bằng phần tử chốt rồi đổi chỗ cho nhau Tiếp tục như vậy cho đến khi hai đường gặp nhau

- Để có thể gọi đệ quy ta xét bài toán phân chia một danh sách con của a: a[k1,k2] thành hai danh sách

while (a[i] < v) i++; //tìm phần tử phía đầu đoạn mà ≥ v

while (a[j] > v) j ; //tìm phần tử phía cuối đoạn mà ≤ v

//lúc này: a[i] ≥ v ≥ a[j]

Trang 10

//lúc này, a[l] a[j] a[i] a[r], nghĩa là: l ≤ j ≤ i ≤ r

if (l<j) QuickSort(a,l,j); //nếu a[l] a[j] là 1 đoạn (nhiều hơn 1 phần

-Về thời gian: O(nlog n)

- Về dữ liệu: Khác nhau tùy vào cách hiện thực

Thuật toán sắp xếp Chọn (Selection sort)

Giải thuật

Chọn phần tử nhỏ nhất trong n phần tử ban đầu, đưa phần tử này về vị trí đúng là đầu tiên của dãy hiện hành Sau đó không quan tâm đến nó nữa, xem dãy hiện hành chỉ còn n-1 phần tử của dãy 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ử Dãy ban đầu có n phần tử, vậy tóm tắt ý tưởng thuật toán là thực hiện n-1 lượt việc đưa phần tử nhỏ nhất trong dãy hiện hành về vị trí đúng ở đầu dãy

Các bước tiến hành như sau:

Trang 11

Bước 1: i=1

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: Hoán vị a[min] và a[i]

Bước 4: Nếu i<=n-1 thì i=i+1; Lặp lại bước 2

Trang 12

// Doi cho cho phan tu dau

int t = c[i]; // t: bien tam

c[i] = c[m];

c[m] = t;

}

}

Thuật toán sắp xếp Chèn (Insertion sort)

Thuật toán sắp xếp chèn làm việc cũng giống như tên gọi - Nó thực hiện việc quét một tập dữ liệu, với mỗi phân tử, thủ tục kiểm tra và chèn phần tử đó vào vị trí thích hợp trong danh sách đích (chứa các phần tử đứng trước nó đã được sắp xếp) được tiến hành

Phương pháp dễ dàng nhất để thực hiện thuật toán này là dùng hai vùng chứa dữ liệu khác nhau - tập dữ liệu nguồn và tập dữ liệu mà các phần tử đã sắp xếp được chèn vào Tuy nhiên để tiết kiệm bộ nhớ, hầu hết các ứng dụng đều chỉ sử dụng một tập dữ liệu duy nhất Thuật toán được tiến hành bằng cách dịch chuyển phân tử hiện tại đang xét tuần tự qua những phân tử ở vùng dữ liệu phía trước đã được sắp xếp, phép hoán vị nó với phần

tử liền kề được thực hiện một cách lặp lại cho tới khi tiến tới được vị trí thích hợp

Do với mỗi phân tử, insertion sort cần thực hiện so sánh với các phần tử trước nó nên tối

đa số lần duyệt dữ liệu là !N Vì vậy cũng giống như Bubble sort, Insertion sort được coi

là có độ phức tạp O(n2) Mặc dù có cùng độ phức tạp, Insertion sort hiệu quả hơn gần như hai lần so với Bubble sort, tuy nhiên vẫn không hiệu quả với tập dữ liệu lớn

Mô tả:

Trang 14

j ;

} a[j+1] = x;

} }

Thuật toán Shell-sort

Được phát minh bởi Donald Shell vào năm 1959, Shell sort là thuật toán hiệu quả nhất trong nhóm các thuật toán sắp xếp có độ phức tạp O(n2) Đương nhiên, Shell sort cũng phức tạp nhất trong các thuật giải thuộc lớp này

Shell sort là sự cải tiến của Insertion sort dựa vào hai nhận xét sau đây:

Insertion sort sẽ rất hiệu quả nếu dữ liệu đầu vào hầu như đã được sắp xếp (đã được xếp trong từng khoảng cục bộ)

Insertion sort hoạt động kém hiệu quả vì nó di chuyển các giá trị phần tử mỗ i lần chỉ một

vị trí

Shell sort là môt thuật toán sắp xếp với số gia giãm dần, thường được biết đến như là

"comb sort" dành cho những khối chương trình hỗn độn chưa được làm sạch Thuật toán tạo ra nhiều luồng chạy duyệt qua danh sách dữ liệu, và mỗi lần sắp xếp một số trong những tập dữ liệu được định kích cở như nhau (tập phân đoạn được tách ra từ tập dữ liệu ban đầu) dùng Insertion sort Sau mỗi lần duyệt qua hết bộ dữ liệu thông qua các phân đoạn (có kích thước giãm dần >= 1) , kích thước của tập được sắp xếp trở nên lớn hơn, cho tới khi nó chứa toàn bộ danh sách dữ liệu (Chú ý rằng do kích thước của tập tăng lên, số lượng tập dữ liệu cần được sắp xếp sẽ giảm dần) Điều này làm cho Insertion sort đạt tới trường hợp tối ưu nhất, chạy mỗi vòng lặp với độ phức tạp tiến tới O(n)

Các phần tử chứa trong mỗi tập phân đoạn thì không liền kề nhau - cụ thể hơn, nếu có i tập phân đoạn thì mỗi tập chứa các phần tử thứ i liên tiếp kể từ điểm xuất phát của tập đó

Ví dụ, nếu có 3 tập phân đoạn thì tập đầu tiên sẽ chứa những phần tử tại các vị trí 1, 4, 7

Trang 15

và cứ như thế tiếp tục Tập thứ hai sẽ chứa những phần tử tại các vị trí 2, 5, 8, và cứ thế tiếp tục về sau; trong khi tập thứ ba sẽ chứa các phần tử ở vị trí 3, 6, 9, và tương tự kế đó.

Kích thước của tập dữ liệu được sử dụng trong mỗi lần duyệt dữ liệu có ảnh hưỡng lớn tới hiệu quả của việc sắp xếp Vài nhà nghiên cứu hàng đầu về khoa học máy tính, trong

đó có cả Donald Knuth và Robert Sedgewick đã phát triển những phiên bản phức tạp hơn cho shell sort nhằm nâng cao hiệu quả tính toán bằng việc xử lý một cách cẩn thận những tập phân đoạn sao cho có kích thước tốt nhất để dùng cho danh sách dữ liệu được cho

buoc=h[j];

for(int i=buoc;i<n;i++) {

x=a[i];

t=i-buoc;

Trang 16

a[t+buoc]=a[t];

t=t-buoc;

} a[t+buoc]=x;

} } }

Thuật toán sắp xếp trộn (Merge-sort)

Trong khoa học máy tính, sắp xếp trộn (merge sort) là một thuật toán sắp xếp để sắp xếp các danh sách (hoặc bất kỳ cấu trúc dữ liệu nào có thể truy cập tuần tự, v.d luồng tập tin) theo một trật tự nào đó Thuật toán này là một ví dụ tương đối điển hình của lối thuật toán chia để trị Nó được xếp vào thể loại sắp xếp so sánh

Giải thuật

Các bước thực hiện thuật toán trộn tự nhiên như sau:

Bước 1 : // Chuẩn bị r = 0; // r dùng để đếm số đường chạy

Bước 2 : Tách dãy a1, a2, , an thành 2 dãy b, c theo nguyên tắc luân phiên từng đường chạy:

Bước 2.1 : Phân phối cho b một đường chạy; r = r+1; Nếu a còn phần tử chưa phân phối Phân phối cho c một đường chạy; r = r+1;

Bước 2.2 : Nếu a còn phần tử: quay lại bước 2.1;

Bước 3 : Trộn từng cặp đường chạy của 2 dãy b, c vào a

Ngày đăng: 29/04/2014, 17:14

HÌNH ẢNH LIÊN QUAN

Đồ thị trên đã thể hiện khá rỏ, Bubble sort là giải pháp cực kì không hiệu quả, và  shell sort là sự cải tiến tạo ra cuộc bứt phá hết sức ngoạn mục - Tổng quan về thuật toán sắp xếp
th ị trên đã thể hiện khá rỏ, Bubble sort là giải pháp cực kì không hiệu quả, và shell sort là sự cải tiến tạo ra cuộc bứt phá hết sức ngoạn mục (Trang 2)

TỪ KHÓA LIÊN QUAN

w