- vừa được xem lúc

Merge Sort

0 0 16

Người đăng: Hạnh

Theo Viblo Asia

Chào các bạn! Tiếp theo chuỗi series về các thuật toán sắp xếp và tìm kiếm căn bản, thì ở bài viết này mình sẽ trình bày các bạn phần thuật toán Sắp xếp trộn - Merge Sort.

Không chậm chạp như Selection Sort, cũng không thất thường như cô nàng Quick Sort. Đây được đánh giá là một thuật toán mang tính ổn định cao. Độ phức tạp thuật toán luôn luôn O(NlogN)O(N*logN).

Hãy cùng tìm hiểu nó ngay sau đây nhé!


Đặt vấn đề

Quá quen thuộc rồi: Cho dãy số gồm NN phần tử, việc của bạn là sắp xếp chúng theo thứ tự tăng dần. Tất nhiên NN ứng với cả triệu số.

Ý tưởng thuật toán

Thuật toán có các bước sau đây:

  1. Nếu dãy số có không quá 1 phần tử, thì coi như xong. Không cần làm gì nữa.
  2. Nếu dãy số nhiều hơn 1 phần tử, thì chia dãy ra làm 2 phần bằng nhau
  3. Sắp xếp 2 dãy con này
  4. Gộp 2 dãy có thứ tự này thành dãy có kích thước ban đầu

Nhận xét: Sau khi đọc xong 4 bước ở trên, bạn có thấy ảo diệu không nào?


Giờ mình sẽ giải thích từ bước 2 trở đi nhé.

Chia dãy ra làm 2 phần bằng nhau

Việc này coi ra dễ, bạn chỉ cần cho rằng:

  • Dãy thứ nhất bắt đầu từ left đến mid
  • Dãy thứ hai là phần còn lại, bắt đầu từ mid + 1 đến right.

Ở đây, mid tương ứng là vị trí ngay giữa của dãy: mid = (left + right) / 2

Sắp xếp 2 dãy con này

Chỉ cần gọi đệ quy là được.

Ta đã biết rằng, nguyên tắc để có thể dùng đệ quy, ta cần đảm bảo 2 yếu tố:

  1. Có tồn tại trường hợp thoát đệ quy
  2. Có cách tổng hợp kết quả bài toán lớn, từ các bài toán con đệ quy

Thì ở đây, yếu tố thứ (1) ta đã có rồi - trường hợp thoát đệ quy của ta chính là khi dãy số có không quá 1 phần tử.

Còn yếu tố thứ (2) thì ta hãy cùng theo dõi tiếp bước tiếp theo nhé.

Gộp 2 dãy có thứ tự

Ta sẽ cùng giải quyết bài toán lớn này, thông qua một bài toán nhỏ hơn nào.

Bài toán: Cho 2 dãy số đã được sắp xếp tăng dần, hãy gộp chúng lại thành một dãy mới. Dãy mới phải đảm bảo cũng được sắp xếp tăng dần.

Cách giải quyết khá đơn giản, ta chỉ cần giải thuật O(M+N)O(M + N) là có thể giải quyết được (với NNMM là lần lượt là kích thước của 2 dãy con).

Dưới đây là đoạn code mẫu để giúp mình làm điều này:

void mergeParts(int *arr, int l, int mid, int r) { int i = l, j = mid + 1; int k = 0; while (i <= mid && j <= r) { int nextValue; if (arr[i] < arr[j]) nextValue = arr[i++]; else nextValue = arr[j++]; temp[k++] = nextValue; } while (i <= mid) temp[k++] = arr[i++]; while (j <= r) temp[k++] = arr[j++]; for (int i=0; i<k; i++) arr[l + i] = temp[i]; } 

Đoạn này, mình cần merge 2 đoạn có kích thước bằng nhau, và liên tục nhau.

  • Đoạn 1: từ left đến mid
  • Đoạn 2: từ mid + 1 đến right

temp chính là dãy số phụ để ta lưu lại kết quả trong khi merge.


Và dưới đây là code cho merge sort mà mình đã chuẩn bị:


void mergeSort(int *arr, int l, int r) { if (l >= r) return; int mid = (l + r) / 2; mergeSort(arr, l, mid); mergeSort(arr, mid + 1, r); mergeParts(arr, l, mid, r);
} 

Full code bạn có thể xem ở đây: https://ideone.com/ej0MV8

Đánh giá độ phức tạp

Dễ thấy rằng, độ phức tạp của giải thuật trên là O(NlogN)O(N*logN) bất kể dãy số ban đầu có thứ tự như thế nào đi nữa.

Và nếu bạn nhấn vào link full code ở phía trên, không bất ngờ bạn cũng có thể tìm thấy dòng Memory + thời gian thực thi:

Success #stdin #stdout 0.19s 11316KB

Với thời gian thực thi không khác Quick Sort là bao với dãy số 1 triệu phần tử.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Học lập trình game cần những gì?

Lập trình game là làm gì. Các ngôn ngữ các bạn có thể sử dụng để lập trình game : C, C++, C#, Java, Python,... Các bước cơ bản để lập trình game. . Hiển thị: Đã là game thì hiển thị không thể thiếu, lúc đầu các bạn chỉ làm cho phần hiển thị thật đơn giản, các bạn đừng quá chú tâm vào việc làm sao ch

0 0 44

- vừa được xem lúc

[MFC] Http request with winsock2.h

Giới thiệu. Xin chào, trong bài này mình sẽ giới thiệu 1 số lưu ý khi sử dụng thư viện winsock2.h (thư viện window socket) sử dụng trong window app. Đầu tiên, bạn sẽ dễ dàng search được 1 ví dụ cụ thể trên document của winsock2.

0 0 35

- vừa được xem lúc

Design parttern

Builder. 1. Ý tưởng. Builder là một mẫu thiết kế sáng tạo cho phép bạn xây dựng các đối tượng phức tạp theo từng bước.

0 0 32

- vừa được xem lúc

Kỹ thuật viết mã nguồn hiệu quả

Kỹ thuật viết mã nguồn hiệu quả? Hôm nay bài viết này mình không đề cập tới thuật toán, hãy coi như rằng chúng ta đã có thuật toán tốt nhất có thể và bây giờ chúng ta phải làm gì để có thể tăng tính hiệu quả của code. Bài viết này mình sẽ lấy ngôn ngữ lập trình C/C++ để minh họa về các hàm, các thao

0 0 38

- vừa được xem lúc

Singleton Design pattern

Singleton Design pattern. 1. Vấn đề. - Ý tưởng:.

0 0 35

- vừa được xem lúc

So sánh Python và C++

Cuộc tranh luận giữa Python và C ++ là một chủ đề hấp dẫn vì cả hai ngôn ngữ lập trình đều rất khác nhau về cú pháp, tính đơn giản, cách sử dụng và cách tiếp cận tổng thể để lập trình. Vì vậy, mọi người cảm thấy khó khăn khi lựa chọn ngôn ngữ lập trình nào để học.

0 0 38