피벗을 하나 선택한다.
피벗을 기준으로 양쪽에서 피벗보다 큰 값, 혹은 작은 값을 찾는다. 왼쪽에서부터는 피벗보다 큰 값을 찾고, 오른쪽에서부터는 피벗보다 작은 값을 찾는다.
양 방향에서 찾은 두 원소를 교환한다.
왼쪽에서 탐색하는 위치와 오른쪽에서 탐색하는 위치가 엇갈리지 않을 때 까지 2번으로 돌아가 위 과정을 반복한다.
엇갈린 기점을 기준으로 두 개의 부분리스트로 나누어 1번으로 돌아가 해당 부분리스트의 길이가 1이 아닐 때 까지 1번 과정을 반복한다. (Divide : 분할)
인접한 부분리스트끼리 합친다. (Conqure : 정복)
public class QuickSorter {
public static List<Integer> quickSort(List<Integer> list) {
if (list.size() <= 1) return list;
int pivot = list.get(list.size() / 2);
List<Integer> lesserArr = new LinkedList<>();
List<Integer> equalArr = new LinkedList<>();
List<Integer> greaterArr = new LinkedList<>();
for (int num : list) {
if (num < pivot) lesserArr.add(num);
else if (num > pivot) greaterArr.add(num);
else equalArr.add(num);
}
return Stream.of(quickSort(lesserArr), equalArr, quickSort(greaterArr))
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
}
매번 재귀 호출될 때 마다 새로운 리스트를 생성하여 리턴하기 때문에 메모리 사용 측면에서 비효율적.
public class QuickSorter {
public static void quickSort(int[] arr) {
sort(arr, 0, arr.length - 1);
}
private static void sort(int[] arr, int low, int high) {
if (low >= high) return;
int mid = partition(arr, low, high);
sort(arr, low, mid - 1);
sort(arr, mid, high);
}
private static int partition(int[] arr, int low, int high) {
int pivot = arr[(low + high) / 2];
while (low <= high) {
while (arr[low] < pivot) low++;
while (arr[high] > pivot) high--;
if (low <= high) {
swap(arr, low, high);
low++;
high--;
}
}
return low;
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}