list/sort: add some explanatory comments

This commit is contained in:
Danny Robson 2019-09-09 10:48:38 +10:00
parent 455e917070
commit 2969cb3954

View File

@ -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;