SORTING › INSERTION SORT
Open — the attempt gate is not wired up yet
This editorial is meant to unlock after you have run the problem at least once, with the worked solution behind one further deliberate click. That needs per-learner unlock state nothing stores today, so for now the whole article is open.
Try it yourself first →Insertion sort keeps two regions: a sorted output prefix and the remaining input suffix. Take the first node from the suffix, find the first sorted node whose value is not smaller, and place the taken node immediately before it. Because the nodes are already linked objects, you can move each node by changing pointers instead of creating a second list or copying values.
The sorted prefix is usually extended at its end, so the next node can be accepted immediately when its value is at least the last sorted value. Only a node that is smaller than that last value needs a search from the beginning. A dummy node sits before the sorted prefix, giving the search a predecessor even when the current node belongs at the new head.
| MEASURE | BOUND | WHY |
|---|---|---|
| Time | O(n^2) worst case | Each node is removed once, but a node that belongs near the front can require scanning many nodes in the sorted prefix. Across a reverse-ordered list, the scan lengths are 1, 2, through n - 1, which sum to O(n^2). Already ordered input takes O(n) because every node uses the append fast path. |
| Space | O(1) extra | The algorithm keeps only a dummy node and a constant number of ListNode pointers; it reuses every original link. The returned list is required output and is excluded from the extra-space bound. The bound stays O(1) for every input shape. |
#include <cstddef>
using namespace std;
class Solution {
public:
ListNode* insertionSortList(ListNode* head) {
if (head == nullptr || head->next == nullptr) {
return head;
}
ListNode dummy(0);
dummy.next = head;
ListNode* prev = head;
ListNode* curr = head->next;
while (curr != nullptr) {
if (curr->val >= prev->val) {
prev = curr;
curr = curr->next;
} else {
ListNode* scan = &dummy;
while (scan->next->val < curr->val) {
scan = scan->next;
}
prev->next = curr->next;
curr->next = scan->next;
scan->next = curr;
curr = prev->next;
}
}
return dummy.next;
}
};The three pointer assignments in the insertion branch must be read as one operation. First prev skips over curr, removing it from its old position. Then curr points to the node that used to follow scan. Finally scan points to curr, placing it into the sorted prefix. The last assignment to curr resumes at the next unprocessed node; prev deliberately stays where it is because the inserted node is before it.