# Các giải thuật sắp xếp - P1: Interchange sort **1 . Interchange sort** Ý tưởng: Thuật toán interchange sort (đổi chỗ trực tiếp) sẽ bắt cặp tất cả các phần tử và đổi chỗ chúng nếu như chúng nghịch thế. Do đó nó mang tên gọi "đổi chỗ trực tiếp" Mã giả: ``` for(int i=0;i<n-1;i++) for(int j=i+1;j<n;j++) if ( a[i] > a[j] ){ swap (a[i],a[j]) } ``` Best time complexity: n^2 Worst time complexity : n^2 Average time complexity : n^2 **2. Bubble sort** Ý tưởng: Tương tự như interchange sort, nhưng thay vì bắt cặp i,j, bubble sortbắt cặp 2 phần tử liên tiếp. Nếu chúng nghịch thế thì đổi chỗ Mã giả: ``` for(int i=0;i<n-1;i++){ swapped = false for(int j=0;j<n-i-1;j++){ if ( a[j] > a[j+1]){ swap(a[j],a[j+1]); swapped = true; } if (!swapped) break; } } ``` Phần tử lớn nhất sẽ "nổi bọt" lên đầu. Best time complexity: n Worst time complexity : n^2 Average time complexity : n^2 **3. Quick sort** Ý tưởng: Quick sort là thuật toán sắp xếp dạng chia để trị, dựa trên cách phân hoạch (partition). Ý tưởng chung của các phân hoạch là chọn ra phần tử chốt và chia đôi mảng ra thành 2 phần, 1 phần nhỏ hơn pivot và cùng nằm về một phía với pivot, ngược lại với các phần tử lớn hơn pivot. Cách phân hoạch ảnh hưởng tới độ phức tạp thời gian của Quick sort. Mã giả: ``` function quicksort(A, lo, hi) is // Ensure indices are in correct order if lo >= hi || lo < 0 then return // Partition array and get the pivot index p = partition(A, lo, hi) // Sort the two partitions quicksort(A, lo, p - 1) // Left side of pivot quicksort(A, p + 1, hi) // Right side of pivot ``` Phân hoạch lomuto: Phân hoạch lomuto chọn phần tử cuối cùng là pivot, sau đó set i = lf - 1 (i sau này là vị trí của pivot), sau đó xếp chúng theo quy tắc đã nêu (chia thành 2 phần). Mã giả ``` function LomutoPartition(array, lf, rt): pivot = array[rt] // Select the pivot element (usually the last element) i = lf - 1 // Initialize the index of the smaller element for j = lf to rt - 1: if array[j] <= pivot: i = i + 1 // Increment the index of the smaller element swap array[i] and array[j] // Swap array[i] and array[j] swap array[i + 1] and array[high] // Swap the pivot element with the element at (i + 1) return (i + 1) // Return the partitioning index ``` Vì luôn chọn phần tử cuối cùng nên đôi khi mảng sẽ không được chia đều (trường hợp phần tử cuối là lớn nhất). Lomuto partition sẽ thực hiện nhiều lần swap hơn so với Hoare, vì vậy nó sẽ chậm hơn. Time complexity O(n) Phân hoạch Hoare: Phân hoạch Hoare thường chọn pivot là phần tử giữa hoặc phần tử đầu. Set 2 con trỏ tại 2 điểm i = lf và j = rt của mảng. Bắt đầu tìm 2 giá trị a[i] và a[j] mà tại đó xảy ra a[i] > pivot và a[j] < pivot. Swap(a[i], a[j]). Tiếp tục cho đến khi i và j vượt qua nhau là hết một lần phân hoạch. Mã giả: ``` function HoarePartition(array, low, high): pivot_index = (low + high) / 2 // Calculate the index of the middle element pivot = array[pivot_index] // Select the middle element as the pivot i = low - 1 // Initialize the left pointer j = high + 1 // Initialize the right pointer while true: do: i = i + 1 // Move the left pointer towards the right while array[i] < pivot do: j = j - 1 // Move the right pointer towards the left while array[j] > pivot if i >= j: return j // Return the partitioning index swap array[i] and array[j] // Swap array[i] and array[j] ``` Trường hợp tệ nhất cũng là khi mảng được phân hoạch không đều. Time complexity O(n) Khi mảng được phân hoạch không đều, quick sort phải sort lại cả mảng trừ đi phần tử cuối, do đó Best time complexity: nlogn Worst time complexity : n^2 Average time complexity : nlogn 4. Cocktail shaker sort Cocktail sort tương tự như bubble sort, nhưng cocktail sort sẽ có 2 vòng iterate đẩy phần tử lớn nhất lên đầu và đẩy phần tử bé xuống cuối Mã giả ``` function CocktailSort(array): n = length(array) swapped = true start = 0 end = n - 1 while swapped: swapped = false // Forward pass: Move the largest element to the end for i from start to end - 1: if array[i] > array[i + 1]: swap array[i] and array[i + 1] swapped = true if not swapped: break // If no swaps occurred, the array is sorted swapped = false end-- // Decrease the end pointer // Backward pass: Move the smallest element to the beginning for i from end - 1 to start step -1: if array[i] > array[i + 1]: swap array[i] and array[i + 1] swapped = true start++ // Increase the start pointer return array ``` Best time complexity: n Worst time complexity : n^2 Average time complexity : n^2