Quick Sort
Quick Sort, "Divide and Conquer" (Böl və Hökm et) strategiyasından istifadə edən çox effektiv sıralama alqoritmdir. Bu alqoritm ortalama halda O(n log n) time complexity-ə malikdir və praktikada ən sürətli sıralama alqoritmlərindən biri hesab olunur.
Alqoritmin İşləmə Prinsipi
- Pivot seçimi: Massivdən bir element pivot kimi seçilir
- Partitioning: Massiv pivot elementə görə iki hissəyə bölünür:
- Sol hissə: pivot-dan kiçik elementlər
- Sağ hissə: pivot-dan böyük elementlər
- Rekursiv çağırış: Sol və sağ hissələr üçün eyni proses təkrarlanır
- Base case: Massivdə 1 və ya 0 element qaldıqda rekursiya dayanır
Vizual Nümunə
İlk massiv: [64, 34, 25, 12, 22, 11, 90]
Pivot: 64 (ilk element)
Partitioning:
[34, 25, 12, 22, 11] [64] [90]
(kiçiklər) pivot (böyüklər)
Sol hissə üçün rekursiya: [34, 25, 12, 22, 11]
Pivot: 34
[25, 12, 22, 11] [34] []
Sol hissə: [25, 12, 22, 11]
Pivot: 25
[12, 22, 11] [25] []
Davam edir...
Final nəticə: [11, 12, 22, 25, 34, 64, 90]
Java İmplementasiyası
Sadə Quick Sort
Koda bax
public class QuickSort {
public static void quickSort(int[] arr, int low, int high) {
if (low < high) {
// Partition indeksini tap
int pivotIndex = partition(arr, low, high);
// Pivot-dan əvvəlki hissəni sırala
quickSort(arr, low, pivotIndex - 1);
// Pivot-dan sonrakı hissəni sırala
quickSort(arr, pivotIndex + 1, high);
}
}
private static int partition(int[] arr, int low, int high) {
// Son elementi pivot kimi seç
int pivot = arr[high];
int i = low - 1; // Kiçik elementlərin indeksi
for (int j = low; j < high; j++) {
// Əgər current element pivot-dan kiçik və ya bərabərdirsə
if (arr[j] <= pivot) {
i++;
swap(arr, i, j);
}
}
// Pivot-u düzgün yerinə qoy
swap(arr, i + 1, high);
return i + 1;
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
int[] arr = {64, 34, 25, 12, 22, 11, 90};
System.out.println("Sıralamadan əvvəl:");
printArray(arr);
quickSort(arr, 0, arr.length - 1);
System.out.println("Sıralamadan sonra:");
printArray(arr);
}
public static void printArray(int[] arr) {
for (int value : arr) {
System.out.print(value + " ");
}
System.out.println();
}
}
Randomized Quick Sort
Koda bax
import java.util.Random;
public class RandomizedQuickSort {
private static Random random = new Random();
public static void randomizedQuickSort(int[] arr, int low, int high) {
if (low < high) {
// Random pivot seç
int randomIndex = low + random.nextInt(high - low + 1);
swap(arr, randomIndex, high);
int pivotIndex = partition(arr, low, high);
randomizedQuickSort(arr, low, pivotIndex - 1);
randomizedQuickSort(arr, pivotIndex + 1, high);
}
}
private static int partition(int[] arr, int low, int high) {
int pivot = arr[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] <= pivot) {
i++;
swap(arr, i, j);
}
}
swap(arr, i + 1, high);
return i + 1;
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
int[] arr = {64, 34, 25, 12, 22, 11, 90};
System.out.println("Randomized Quick Sort:");
System.out.println("Sıralamadan əvvəl:");
printArray(arr);
randomizedQuickSort(arr, 0, arr.length - 1);
System.out.println("Sıralamadan sonra:");
printArray(arr);
}
public static void printArray(int[] arr) {
for (int value : arr) {
System.out.print(value + " ");
}
System.out.println();
}
}
3-Way Quick Sort (Dutch National Flag)
Koda bax
public class ThreeWayQuickSort {
public static void threeWayQuickSort(int[] arr, int low, int high) {
if (low >= high) return;
int[] pivots = threeWayPartition(arr, low, high);
int lt = pivots[0]; // pivot-dan kiçik elementlərin sonu
int gt = pivots[1]; // pivot-dan böyük elementlərin başlanğıcı
threeWayQuickSort(arr, low, lt - 1);
threeWayQuickSort(arr, gt + 1, high);
}
private static int[] threeWayPartition(int[] arr, int low, int high) {
int pivot = arr[low];
int lt = low; // arr[low..lt-1] < pivot
int i = low + 1; // arr[lt..i-1] == pivot
int gt = high; // arr[gt+1..high] > pivot
while (i <= gt) {
if (arr[i] < pivot) {
swap(arr, lt++, i++);
} else if (arr[i] > pivot) {
swap(arr, i, gt--);
} else {
i++;
}
}
return new int[]{lt, gt};
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
int[] arr = {64, 34, 25, 12, 22, 11, 90, 25, 25};
System.out.println("3-Way Quick Sort:");
System.out.println("Sıralamadan əvvəl:");
printArray(arr);
threeWayQuickSort(arr, 0, arr.length - 1);
System.out.println("Sıralamadan sonra:");
printArray(arr);
}
public static void printArray(int[] arr) {
for (int value : arr) {
System.out.print(value + " ");
}
System.out.println();
}
}
Generic Quick Sort
Koda bax
import java.util.Comparator;
public class GenericQuickSort {
public static <T> void quickSort(T[] arr, int low, int high, Comparator<T> comparator) {
if (low < high) {
int pivotIndex = partition(arr, low, high, comparator);
quickSort(arr, low, pivotIndex - 1, comparator);
quickSort(arr, pivotIndex + 1, high, comparator);
}
}
private static <T> int partition(T[] arr, int low, int high, Comparator<T> comparator) {
T pivot = arr[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (comparator.compare(arr[j], pivot) <= 0) {
i++;
swap(arr, i, j);
}
}
swap(arr, i + 1, high);
return i + 1;
}
private static <T> void swap(T[] arr, int i, int j) {
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
// Integer array
Integer[] intArr = {64, 34, 25, 12, 22, 11, 90};
quickSort(intArr, 0, intArr.length - 1, Integer::compareTo);
System.out.println("Sıralanmış integer array: " + java.util.Arrays.toString(intArr));
// String array
String[] strArr = {"banana", "apple", "cherry", "date"};
quickSort(strArr, 0, strArr.length - 1, String::compareTo);
System.out.println("Sıralanmış string array: " + java.util.Arrays.toString(strArr));
}
}
Java Built-in Quick Sort
Java-da Arrays.sort() metodu Dual-Pivot Quick Sort istifadə edir:
Koda bax
import java.util.Arrays;
public class JavaBuiltInSort {
public static void main(String[] args) {
int[] arr = {64, 34, 25, 12, 22, 11, 90};
System.out.println("Java built-in sort:");
System.out.println("Əvvəl: " + Arrays.toString(arr));
Arrays.sort(arr); // Dual-Pivot Quick Sort
System.out.println("Sonra: " + Arrays.toString(arr));
// Partial sorting
int[] arr2 = {64, 34, 25, 12, 22, 11, 90};
Arrays.sort(arr2, 1, 5); // Index 1-dən 5-ə qədər sırala
System.out.println("Partial sort: " + Arrays.toString(arr2));
}
}
Mürəkkəblik Analizi
Time Complexity
- Best Case: O(n log n) - Pivot həmişə massivi bərabər iki hissəyə bölür
- Average Case: O(n log n) - Pivot ortalama olaraq yaxşı seçilir
- Worst Case: O(n²) - Pivot həmişə ən kiçik və ya ən böyük elementdir
Space Complexity
- Best/Average Case: O(log n) - Rekursiya stack-i üçün
- Worst Case: O(n) - Unbalanced partitioning zamanı
Pivot Seçim Strategiyaları
- İlk element: Sadə, lakin sorted array-lər üçün worst case
- Son element: Ən çox istifadə olunan
- Orta element: Median-of-three kimi strategiyalar
- Random element: Worst case ehtimalını azaldır
- Median-of-three: İlk, orta və son elementlərin medianı
Üstünlüklər
- Sürətli: Ortalama halda ən sürətli sıralama alqoritmlərindən biri
- In-place: Əlavə yaddaş tələb etmir (O(log n) stack space istisna olmaqla)
- Cache-friendly: Locality of reference yaxşıdır
- Praktiki: Real dünyada geniş istifadə olunur
Çatışmazlıqlar
- Worst case: O(n²) time complexity
- Unstable: Eyni dəyərli elementlərin sırası dəyişə bilər
- Rekursiya: Stack overflow riski (çox dərin rekursiya)
- Pivot dependency: Pivot seçimi performansa təsir edir
Real Dünya Tətbiqləri
- Java Arrays.sort(): Primitive types üçün Dual-Pivot Quick Sort
- C++ std::sort(): Introsort (Quick Sort + Heap Sort hibrid)
- Database sistemləri: Böyük data setlərinin sıralanması
- Operating sistemlər: Process scheduling
- Axtarış mühərrikləri: Search result ranking
LeetCode Problemləri
- Sort an Array (912) - Quick Sort implementasiyası
- Kth Largest Element in an Array (215) - Quick Select alqoritmi
- Sort Colors (75) - 3-way partitioning
- Wiggle Sort II (324) - Quick Select + partitioning
- Top K Frequent Elements (347) - Quick Select variation
Müsahibə Sualları
1. Quick Sort-un average case time complexity-si nədir və niyə?
Cavab: O(n log n) - çünki ortalama halda pivot massivi təxminən bərabər iki hissəyə bölür, bu da log n dərinlik verir və hər səviyyədə O(n) iş görülür.
2. Quick Sort-un worst case nə vaxt baş verir?
Cavab: Pivot həmişə ən kiçik və ya ən böyük element seçildikdə. Bu halda partitioning unbalanced olur və O(n²) time complexity yaranır.
3. Quick Sort-u necə optimizasiya etmək olar?
Cavab: Random pivot seçimi, median-of-three, 3-way partitioning (duplicate elements üçün), tail recursion optimization, kiçik massivlər üçün insertion sort.
4. Quick Sort stable alqoritmdir?
Cavab: Xeyr, çünki partitioning zamanı eyni dəyərli elementlərin nisbi sırası dəyişə bilər.
5. Quick Sort vs Merge Sort - hansını seçmək lazımdır?
Cavab: Quick Sort ortalama halda daha sürətli və daha az yaddaş istifadə edir. Merge Sort həmişə O(n log n) və stable-dir. Worst case performance vacibdirsə Merge Sort, ortalama performance vacibdirsə Quick Sort.
6. Quick Select nədir?
Cavab: Quick Sort-un modifikasiyası olan Quick Select k-th smallest elementi tapmaq üçün istifadə olunur və O(n) average time complexity-ə malikdir.
7. 3-way partitioning nə vaxt faydalıdır?
Cavab: Çoxlu duplicate elementlər olduqda. Bu halda eyni dəyərli elementlər bir yerdə qruplaşdırılır və onlar üçün rekursiya çağırılmır.