ladybird/AK/QuickSort.h
Brian Gianforcaro 1682f0b760 Everything: Move to SPDX license identifiers in all files.
SPDX License Identifiers are a more compact / standardized
way of representing file license information.

See: https://spdx.dev/resources/use/#identifiers

This was done with the `ambr` search and replace tool.

 ambr --no-parent-ignore --key-from-file --rep-from-file key.txt rep.txt *
2021-04-22 11:22:27 +02:00

131 lines
3.4 KiB
C++

/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/StdLibExtras.h>
namespace AK {
/* This is a dual pivot quick sort. It is quite a bit faster than the single
* pivot quick_sort below. The other quick_sort below should only be used when
* you are stuck with simple iterators to a container and you don't have access
* to the container itself.
*/
template<typename Collection, typename LessThan>
void dual_pivot_quick_sort(Collection& col, int start, int end, LessThan less_than)
{
if (start >= end) {
return;
}
int left_pointer, right_pointer;
if (!less_than(col[start], col[end])) {
swap(col[start], col[end]);
}
int j = start + 1;
int k = start + 1;
int g = end - 1;
auto&& left_pivot = col[start];
auto&& right_pivot = col[end];
while (k <= g) {
if (less_than(col[k], left_pivot)) {
swap(col[k], col[j]);
j++;
} else if (!less_than(col[k], right_pivot)) {
while (!less_than(col[g], right_pivot) && k < g) {
g--;
}
swap(col[k], col[g]);
g--;
if (less_than(col[k], left_pivot)) {
swap(col[k], col[j]);
j++;
}
}
k++;
}
j--;
g++;
swap(col[start], col[j]);
swap(col[end], col[g]);
left_pointer = j;
right_pointer = g;
dual_pivot_quick_sort(col, start, left_pointer - 1, less_than);
dual_pivot_quick_sort(col, left_pointer + 1, right_pointer - 1, less_than);
dual_pivot_quick_sort(col, right_pointer + 1, end, less_than);
}
template<typename Iterator, typename LessThan>
void single_pivot_quick_sort(Iterator start, Iterator end, LessThan less_than)
{
for (;;) {
int size = end - start;
if (size <= 1)
return;
int pivot_point = size / 2;
if (pivot_point)
swap(*(start + pivot_point), *start);
auto&& pivot = *start;
int i = 1;
for (int j = 1; j < size; ++j) {
if (less_than(*(start + j), pivot)) {
swap(*(start + j), *(start + i));
++i;
}
}
swap(*start, *(start + i - 1));
// Recur into the shorter part of the remaining data
// to ensure a stack depth of at most log(n).
if (i > size / 2) {
single_pivot_quick_sort(start + i, end, less_than);
end = start + i - 1;
} else {
single_pivot_quick_sort(start, start + i - 1, less_than);
start = start + i;
}
}
}
template<typename Iterator>
void quick_sort(Iterator start, Iterator end)
{
single_pivot_quick_sort(start, end, [](auto& a, auto& b) { return a < b; });
}
template<typename Iterator, typename LessThan>
void quick_sort(Iterator start, Iterator end, LessThan less_than)
{
single_pivot_quick_sort(start, end, move(less_than));
}
template<typename Collection, typename LessThan>
void quick_sort(Collection& collection, LessThan less_than)
{
dual_pivot_quick_sort(collection, 0, collection.size() - 1, move(less_than));
}
template<typename Collection>
void quick_sort(Collection& collection)
{
dual_pivot_quick_sort(collection, 0, collection.size() - 1,
[](auto& a, auto& b) { return a < b; });
}
}
using AK::quick_sort;