list/sort: add some explanatory comments
This commit is contained in:
parent
455e917070
commit
2969cb3954
@ -22,10 +22,25 @@ namespace cruft::list {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Find the midpoint of the list specified by the sub-list [first, last].
|
||||||
|
///
|
||||||
|
/// On even length lists the earlier middle node will be returned.
|
||||||
|
///
|
||||||
|
/// Uses the fast/slow walking method. Double advancing the fast iterator,
|
||||||
|
/// and singly advancing the slow iterator.
|
||||||
|
///
|
||||||
|
/// This necessarily walks the entire list, so the performance may be
|
||||||
|
/// quite low.
|
||||||
|
///
|
||||||
|
/// NOTE: `last` is a valid node and forms part of the sub-list.
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
node<ValueT>*
|
node<ValueT>*
|
||||||
midpoint (node<ValueT> *first, node<ValueT> *last)
|
midpoint [[gnu::nonnull]] (
|
||||||
{
|
node<ValueT> *first,
|
||||||
|
node<ValueT> *last
|
||||||
|
) {
|
||||||
|
// Pre-increment the fast node to trigger a preference for the earlier
|
||||||
|
// of the middle nodes.
|
||||||
auto slow = first;
|
auto slow = first;
|
||||||
auto fast = first->next;
|
auto fast = first->next;
|
||||||
|
|
||||||
@ -41,14 +56,31 @@ namespace cruft::list {
|
|||||||
return slow;
|
return slow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Merges a list that has been divided into two sorted halves.
|
||||||
|
///
|
||||||
|
/// This operation will mutate the `next` pointers but will not mutate
|
||||||
|
/// the inner data objects.
|
||||||
|
///
|
||||||
|
/// NOTE: The list is specified inclusively, and the `last` node is a
|
||||||
|
/// valid piece of data.
|
||||||
|
///
|
||||||
|
/// Returns the first node of the newly sorted list. The caller _must_
|
||||||
|
/// store this value otherwise a portion of the list will be lost.
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
node<ValueT>*
|
node<ValueT>*
|
||||||
merge (
|
merge [[nodiscard]] [[using gnu: nonnull, returns_nonnull]] (
|
||||||
node<ValueT> *first,
|
node<ValueT> *first,
|
||||||
node<ValueT> *middle,
|
node<ValueT> *middle,
|
||||||
node<ValueT> *last
|
node<ValueT> *last
|
||||||
) {
|
) {
|
||||||
|
// clang#xxxx clang mistakenly warns that the values of 'first' and
|
||||||
|
// 'middle' will be unconditionally true on the first iteration of the
|
||||||
|
// while loop.
|
||||||
|
#if defined(COMPILER_CLANG)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wpointer-bool-conversion"
|
||||||
|
#endif
|
||||||
|
|
||||||
CHECK (first);
|
CHECK (first);
|
||||||
CHECK (middle);
|
CHECK (middle);
|
||||||
CHECK (last);
|
CHECK (last);
|
||||||
@ -56,7 +88,9 @@ namespace cruft::list {
|
|||||||
if (first == last)
|
if (first == last)
|
||||||
return first;
|
return first;
|
||||||
|
|
||||||
auto extract = [&] () {
|
// Return a reference to the lower of 'first' and 'middle', and
|
||||||
|
// advance the cursor.
|
||||||
|
auto extract = [&first, &middle] () {
|
||||||
auto &target = first->data < middle->data ? first : middle;
|
auto &target = first->data < middle->data ? first : middle;
|
||||||
auto res = target;
|
auto res = target;
|
||||||
target = target->next;
|
target = target->next;
|
||||||
@ -66,26 +100,35 @@ namespace cruft::list {
|
|||||||
node<ValueT> *cursor = extract ();
|
node<ValueT> *cursor = extract ();
|
||||||
auto head = cursor;
|
auto head = cursor;
|
||||||
|
|
||||||
|
// Keep adding the lowest node to the new list until we exhaust one
|
||||||
|
// or both of our sources.
|
||||||
while (first && middle && first != middle && middle != last->next) {
|
while (first && middle && first != middle && middle != last->next) {
|
||||||
auto target = extract ();
|
auto target = extract ();
|
||||||
cursor->next = target;
|
cursor->next = target;
|
||||||
cursor = target;
|
cursor = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Append the remaining data to the new list.
|
||||||
if (first == middle || !first)
|
if (first == middle || !first)
|
||||||
cursor->next = middle;
|
cursor->next = middle;
|
||||||
else if (middle == last->next || !middle)
|
else if (middle == last->next || !middle)
|
||||||
cursor->next = first;
|
cursor->next = first;
|
||||||
|
|
||||||
|
#if defined(COMPILER_CLANG)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Merge sort for singly-linked lists
|
/// An in-place merge sort for singly linked lists.
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
node<ValueT>*
|
node<ValueT>*
|
||||||
sort (node<ValueT> *first, node<ValueT> *last)
|
sort [[nodiscard]] [[using gnu: nonnull, returns_nonnull]] (
|
||||||
{
|
node<ValueT> *first,
|
||||||
|
node<ValueT> *last
|
||||||
|
) {
|
||||||
if (first == last)
|
if (first == last)
|
||||||
return first;
|
return first;
|
||||||
|
|
||||||
@ -99,9 +142,12 @@ namespace cruft::list {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Tests if a singly linked list is sorted.
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
bool is_sorted (node<ValueT> const *head)
|
bool
|
||||||
{
|
is_sorted [[gnu::nonnull]] (
|
||||||
|
node<ValueT> const *head
|
||||||
|
) {
|
||||||
if (!head->next)
|
if (!head->next)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user