You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+42-58Lines changed: 42 additions & 58 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,53 +1,48 @@
1
-
linked-list-insertion-sort-cpp
1
+
# linked-list-insertion-sort-cpp
2
2
3
3
A tiny, well-commented C++ program that implements stable insertion sort on a singly linked list. It’s written for learning: clear names, ASCII diagrams, and a step-by-step walkthrough.
4
4
5
-
What you’ll learn
5
+
## What you’ll learn
6
6
- How a singly linked list is wired: head, next, nodes
7
7
- Insertion sort as “growing a sorted prefix” (like sorting playing cards)
8
8
- Pointer hygiene: saving the next node before moving, unlinking, reinserting
9
9
- Why this version is stable and O(n²) (and when that’s OK)
10
10
11
-
⸻
12
11
13
-
Mental model (plain English)
12
+
## Mental model (plain English)
14
13
- Keep the left side of the list sorted.
15
14
- Take the first node on the right (“unsorted”), find where it belongs inside the left part, and insert it there.
16
15
- Repeat until there’s no right part left.
17
16
18
17
Think of holding a fan of playing cards in your left hand and inserting the next card into its place.
19
18
20
-
⸻
21
-
22
-
Key invariants (the golden rules)
19
+
## Key invariants (the golden rules)
23
20
1. prev always points to the last node of the sorted prefix.
24
21
2. curr is the first node of the unsorted part (the one we’re placing).
25
22
3. We must save next = curr->next before moving curr.
26
23
4. If curr already belongs at the end of the sorted part, just advance prev. Otherwise, unlink curr and re-insert it earlier (possibly at the head).
27
24
28
25
These rules are exactly what the implementation in main.cpp does.
29
26
30
-
⸻
31
27
32
-
Why this is stable
28
+
## Why this is stable
33
29
34
30
FindInsertionSpot scans while `curr->data < value` (strictly `<`, not `<=`). So if two equal values appear, the earlier one stays earlier. That’s stability.
35
31
36
-
⸻
37
32
38
-
Walkthrough on a small list
33
+
## Walkthrough on a small list
39
34
40
-
Start list:
35
+
#### Start list:
41
36
42
37
```
43
38
[39] -> [45] -> [11] -> [22]
44
39
^ ^
45
40
prev curr
46
41
```
47
42
48
-
We maintain: sorted = head..prev, unsorted = curr..end.
- Find spot for 11 in [39 -> 45] → spot is nullptr (new smallest)
67
62
- spot != prev → move needed:
@@ -74,9 +69,9 @@ Iteration 2
74
69
head prev (unchanged)
75
70
```
76
71
77
-
Advance: curr = 22 (the next we saved earlier).
72
+
**Advance: curr = 22 (the next we saved earlier).**
78
73
79
-
Iteration 3
74
+
#### Iteration 3
80
75
- prev = 45, curr = 22, next = nullptr
81
76
- Find spot for 22 in [11 -> 39 -> 45] → spot is the node 11 (since 11 < 22 and 39 !< 22)
82
77
- spot != prev → move needed:
@@ -87,30 +82,27 @@ Iteration 3
87
82
[11] -> [22] -> [39] -> [45]
88
83
```
89
84
90
-
Advance curr = next = nullptr → done.
85
+
**Advance curr = next = nullptr → done.**
91
86
92
-
Result is sorted and stable.
87
+
**Result is sorted and stable.**
93
88
94
-
⸻
95
89
96
-
File tour (what does what)
90
+
## File tour (what does what)
97
91
- Node, List: minimal data structures (head pointer + next links)
98
92
- ListPrepend, ListInsertAfter, ListRemoveAfter: tiny, testable building blocks
99
93
- FindInsertionSpot(list, value, boundary): scans only within the sorted prefix (from head up to boundary), returning the node after which to insert (or nullptr for “insert at head”)
100
94
- ListInsertionSort: the algorithm glue that uses the helpers safely
101
95
102
-
⸻
103
96
104
-
Complexity
97
+
## Complexity
105
98
- Time: O(n²) comparisons/moves in the worst case (like array insertion sort)
106
99
- Space: O(1) extra space (we move nodes in place)
107
100
- Good when you want stable behavior and cheap insertion without shifting elements
Trace hooks are already built into main.cpp. Enabling TRACE prints both a textual trace and a visual two‑line ASCII diagram that marks `head`, `prev`, `curr`, `next`, and `spot`.
160
+
**Trace hooks are already built into main.cpp. Enabling TRACE prints both a textual trace and a visual two‑line ASCII diagram that marks `head`, `prev`, `curr`, `next`, and `spot`.**
- S = spot (node after which `curr` will be inserted; S at head means insert at head)
221
210
222
-
Notes
211
+
#### Notes
223
212
- Colors are 256-color safe and disabled when stdout is not a TTY (e.g., piped to file).
224
213
- The bordered state is generated by `trace_ui.hpp` and integrated into `main.cpp` under `#ifdef TRACE`.
225
214
226
-
⸻
227
215
228
-
Educational purpose and teaching notes
216
+
### Educational purpose and teaching notes
229
217
- The code favors readability and pointer hygiene over micro-optimizations.
230
218
- Each operation is isolated (prepend/insert/remove) so students can test them independently.
231
219
- The trace shows the invariants in action: prev marks the end of the sorted prefix; curr is the node being placed; next is saved before rewiring; spot marks where curr re-enters.
232
220
- Stability comes from scanning with `<` (not `<=`), so equal keys keep their original relative order.
233
221
234
-
⸻
235
222
236
-
Common pitfalls (and how this code avoids them)
223
+
### Common pitfalls (and how this code avoids them)
237
224
- Losing the rest of the list: Always set `Node* next = curr->next;` before you move `curr`.
0 commit comments