Cách sắp xếp nào ít lần so sánh nhất

Nhiều người cho rằng việc khử đệ quy của sắp xếp nhanh thực ra không cần thiết, nó chỉ có tác dụng cho những người mới tiếp cận khoa học máy tính hiểu sâu sắc hơn về khái niệm đệ quy. Bản chất của các giải thuật đệ quy là lưu trữ các tham biến đệ quy vào một ngăn xếp (stack) để lần lượt lấy ra xử lý.

Khi khử đệ quy của giải thuật đệ quy, mỗi lần phân chia danh sách thành 2 danh sách con ta lưu trữ các tham số của danh sách đứng sau vào một ngăn xếp, rồi phân chia tiếp danh sách đứng trước.

Giải thuật đơn giản nhất để khử đệ quy của sắp xếp nhanh như sau:

________3

Ưu điểm của sắp xếp nhanh không đệ quy nằm ở những cải tiến của giải thuật trên đây. Có thể cải tiến theo những hướng sau: Cất vào ngăn xếp danh sách con ít phần tử hơn trong hai danh sách con và đối với các danh sách con có độ dài đủ nhỏ thì dùng một phương pháp sắp xếp sơ cấp (chẳng hạn sắp xếp chèn).

Quick sort chia ba[sửa | sửa mã nguồn]

Một phương pháp chia khác là chia danh sách thành 3 danh sách con, lần lượt nhỏ hơn, bằng và lớn hơn phần tử chốt.

Giải thuật Selection Sort là 1 trong các thuật toán sắp xếp kinh điển, cơ bản và dễ hiện thực, là thuật toán được tiếp cận sớm nhất khi bắt đầu học các giải thuật sắp xếp cơ bản. Trong 1 số trường hợp đơn giản, thuật toán này rất hữu hiệu, chẳng hạn với các mảng dữ liệu nhỏ không đòi hỏi phải tối ưu về thời gian.

Selection Sort

Ý tưởng

Chọn phần tử nhỏ nhất đưa về vị trí đầu tiên của mảng hiện tại và không cần quan tâm đến nó nữa. Khi đó mảng chỉ còn lại n - 1 phần tử của mảng ban đầu, tiếp tục xét từ phần tử thứ 2 của mảng.

Thuật toán Sắp xếp bong bóng là một kỹ thuật sắp xếp dựa trên so sánh, liên tục so sánh các phần tử liền kề và hoán đổi chúng nếu chúng sắp xếp sai thứ tự. Thuật toán tiến hành lặp đi lặp lại cho đến khi toàn bộ danh sách được sắp xếp. Nó có độ phức tạp về thời gian là O(n^2), trong đó n đại diện cho số phần tử trong danh sách.

Sắp xếp là quá trình bố trí lại các phần tử trong một tập hợp theo một trình tự nào đó nhằm mục đích giúp quản lý và tìm kiếm các phần tử dễ dàng và nhanh chóng hơn.

Tại sao phải sắp xếp?

  • Để có thể sử dụng thuật toán tìm nhị phân
  • Để thực hiện thao tác nào đó được nhanh hơn

Các phương pháp sắp xếp thông dụng:

  • Phương pháp Đổi chỗ trực tiếp (Interchange sort)
  • Phương pháp Nổi bọt (Bubble sort)
  • Phương pháp Chèn trực tiếp (Insertion sort)
  • Phương pháp Chọn trực tiếp (Selection sort)

Interchange Sort

Khái niệm nghịch thế:

  • Xét một mảng các số a[0], a[1], … a[n-1]
  • Nếu có i a[j], thì ta gọi đó là một nghịch thế

Mảng chưa sắp xếp sẽ có nghịch thế

Mảng đã có thứ tự sẽ không chứa nghịch thế

a[0] <= a[1] <=… <=[n -1]

Nhận xét:

  • Để sắp xếp một dãy số, ta có thể xét các nghịch thế có trong dãy và làm triệt tiêu dần chúng đi

Ý tưởng:

  • Xuất phát từ đầu dãy, tìm tất cả nghịch thế chứa phần tử này, triệt tiêu chúng bằng cách đổi chỗ phần tử này với phần tử tương ứng trong cặp nghịch thế
  • Lặp lại xử lý trên với các phần tử tiếp theo trong dãy

Cách sắp xếp nào ít lần so sánh nhất
void Swap(int &a, int &b){
    int temp = a;
    a = b;
    b = temp;
}
void InterchangeSort(int a[], int n){  
    for (int i = 0; i < n - 1; i++)
        for (int j = i + 1; j < n; j++)
          if(a[i] > a[j])  //nếu có nghịch thế thì đổi chỗ
            Swap(a[i], a[j]);
}

Đánh giá:

  • Số lượng các phép so sánh xảy ra không phụ thuộc vào tình trạng của dãy số ban đầu
  • Số lượng phép hoán vị thực hiện tùy thuộc vào kết quả so sánh

Cách sắp xếp nào ít lần so sánh nhấ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í đầu dãy hiện hành, sau đó sẽ không xét đến nó ở bước tiếp theo
  • Ở lần xử lý thứ i 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

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])
           Swap(a[j], a[j-1]);
}

Cách sắp xếp nào ít lần so sánh nhất

Đánh giá:

  • Số lượng các phép so sánh xảy ra không phụ thuộc vào tình trạng của dãy số ban đầu
  • Số lượng phép hoán vị thực hiện tùy thuộc vào kết quả so sánh

Cách sắp xếp nào ít lần so sánh nhất

Khuyết điểm:

  • Không nhận diện được tình trạng dãy đã có thứ tự hay có thứ tự từng phần
  • Các phần tử nhỏ được đưa về vị trí đúng rất nhanh, trong khi các phần tử lớn lại được đưa về vị trí đúng rất chậm

Insertion Sort

Nhận xét:

  • Mọi dãy a[0] , a[1] ,..., a[n-1] luôn có i-1 phần tử đầu tiên a[0] , a[1] ,... , a[i-2] đã có thứ tự (i ≥ 2)

Ý tưởng chính:

  • Tìm cách chèn phần tử a[i] vào vị trí thích hợp của đoạn đã được sắp để có dãy mới a[0] , a[1] ,... , a[i-1] trở nên có thứ tự
  • Vị trí này chính là pos thỏa : a[pos-1] <= a[i ]< a[pos] (1 <= pos <= i)

Cách sắp xếp nào ít lần so sánh nhất
void InsertionSort(int a[], int n){  
  int pos, x;
  for(int i = 1; i < n; i++){ //đoạn a[0] đã sắp
    x = a[i]; 
    pos = i;
    while(pos > 0 && x < a[pos-1]){
      a[pos] = a[pos-1];  // dời chỗ
      pos--;
    }
    a[pos] = x;
  }
}

Đánh giá:

  • Giải thuật thực hiện tất cả N-1 vòng lặp tìm pos, do số lượng phép so sánh và dời chỗ này phụ thuộc vào tình trạng của dãy số ban đầu, nên chỉ có thể ước lược trong từng trường hợp như sau:

Cách sắp xếp nào ít lần so sánh nhất

Selection Sort

Nhận xét:

  • Mảng có thứ tự thì a[i] = min(a[i], a[i+1], …, a[n-1])

Ý tưởng: mô phỏng một trong những cách sắp xếp tự nhiên nhất trong thực 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 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 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ử

Cách sắp xếp nào ít lần so sánh nhất
void SelectionSort(int a[], int n)
{
  int min; // chỉ số phần tử nhỏ nhất trong dãy hiện hành
  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 vị trí phần tử nhỏ nhất
    if (min != i)
          Swap(a[min], a[i]);
  }
}

Đánh giá:

  • Ở lượt thứ i, cần (n-i) lần so sánh để xác định phần tử nhỏ nhất hiện hành
  • Số lượng phép so sánh không phụ thuộc vào tình trạng của dãy số ban đầu
  • Trong mọi trường hợp, số lần so sánh là:

Cách sắp xếp nào ít lần so sánh nhất

Cách sắp xếp nào ít lần so sánh nhất

Tạm kết

Như vậy là mình đã giới thiệu cho các bạn 4 thuật toán sắp xếp thông dụng. Ở phần tới mình sẽ giới thiệu thêm cho các bạn thêm các thuật toán sắp xếp khác.