Skip to content

Commit 4d4dbde

Browse files
authored
Update README.md
1 parent 341a540 commit 4d4dbde

File tree

1 file changed

+42
-58
lines changed

1 file changed

+42
-58
lines changed

README.md

Lines changed: 42 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,48 @@
1-
linked-list-insertion-sort-cpp
1+
# linked-list-insertion-sort-cpp
22

33
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.
44

5-
What you’ll learn
5+
## What you’ll learn
66
- How a singly linked list is wired: head, next, nodes
77
- Insertion sort as “growing a sorted prefix” (like sorting playing cards)
88
- Pointer hygiene: saving the next node before moving, unlinking, reinserting
99
- Why this version is stable and O(n²) (and when that’s OK)
1010

11-
1211

13-
Mental model (plain English)
12+
## Mental model (plain English)
1413
- Keep the left side of the list sorted.
1514
- Take the first node on the right (“unsorted”), find where it belongs inside the left part, and insert it there.
1615
- Repeat until there’s no right part left.
1716

1817
Think of holding a fan of playing cards in your left hand and inserting the next card into its place.
1918

20-
21-
22-
Key invariants (the golden rules)
19+
## Key invariants (the golden rules)
2320
1. prev always points to the last node of the sorted prefix.
2421
2. curr is the first node of the unsorted part (the one we’re placing).
2522
3. We must save next = curr->next before moving curr.
2623
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).
2724

2825
These rules are exactly what the implementation in main.cpp does.
2926

30-
3127

32-
Why this is stable
28+
## Why this is stable
3329

3430
FindInsertionSpot scans while `curr->data < value` (strictly `<`, not `<=`). So if two equal values appear, the earlier one stays earlier. That’s stability.
3531

36-
3732

38-
Walkthrough on a small list
33+
## Walkthrough on a small list
3934

40-
Start list:
35+
#### Start list:
4136

4237
```
4338
[39] -> [45] -> [11] -> [22]
4439
^ ^
4540
prev curr
4641
```
4742

48-
We maintain: sorted = head..prev, unsorted = curr..end.
43+
**We maintain: sorted = head..prev, unsorted = curr..end**
4944

50-
Iteration 1
45+
#### Iteration 1
5146
- prev = 39, curr = 45, next = 11
5247
- Find spot for 45 in [39] → spot is 39 (the last < 45)
5348
- spot == prev → already in correct place; grow sorted region:
@@ -59,9 +54,9 @@ unsorted: [11] -> [22]
5954
curr next (saved)
6055
```
6156

62-
Advance: prev = 45, curr = 11.
57+
**Advance: prev = 45, curr = 11.**
6358

64-
Iteration 2
59+
#### Iteration 2
6560
- prev = 45, curr = 11, next = 22
6661
- Find spot for 11 in [39 -> 45] → spot is nullptr (new smallest)
6762
- spot != prev → move needed:
@@ -74,9 +69,9 @@ Iteration 2
7469
head prev (unchanged)
7570
```
7671

77-
Advance: curr = 22 (the next we saved earlier).
72+
**Advance: curr = 22 (the next we saved earlier).**
7873

79-
Iteration 3
74+
#### Iteration 3
8075
- prev = 45, curr = 22, next = nullptr
8176
- Find spot for 22 in [11 -> 39 -> 45] → spot is the node 11 (since 11 < 22 and 39 !< 22)
8277
- spot != prev → move needed:
@@ -87,30 +82,27 @@ Iteration 3
8782
[11] -> [22] -> [39] -> [45]
8883
```
8984

90-
Advance curr = next = nullptr → done.
85+
**Advance curr = next = nullptr → done.**
9186

92-
Result is sorted and stable.
87+
**Result is sorted and stable.**
9388

94-
9589

96-
File tour (what does what)
90+
## File tour (what does what)
9791
- Node, List: minimal data structures (head pointer + next links)
9892
- ListPrepend, ListInsertAfter, ListRemoveAfter: tiny, testable building blocks
9993
- 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”)
10094
- ListInsertionSort: the algorithm glue that uses the helpers safely
10195

102-
10396

104-
Complexity
97+
## Complexity
10598
- Time: O(n²) comparisons/moves in the worst case (like array insertion sort)
10699
- Space: O(1) extra space (we move nodes in place)
107100
- Good when you want stable behavior and cheap insertion without shifting elements
108101

109-
110102

111-
Build & run
103+
## Build & run
112104

113-
Quick start (Makefile)
105+
**Quick start (Makefile)**
114106
```
115107
# Default build and run
116108
make run
@@ -119,9 +111,9 @@ make run
119111
make run TRACE=1
120112
```
121113

122-
macOS/Linux direct compile (no Make/CMake)
114+
**macOS/Linux direct compile (no Make/CMake)**
123115
```
124-
# Normal
116+
Normal
125117
clang++ -std=c++20 -O2 -Wall -Wextra -pedantic main.cpp -o ll_isort && ./ll_isort
126118
127119
# With visual TRACE
@@ -132,7 +124,7 @@ g++ -std=c++20 -O2 -Wall -Wextra -pedantic main.cpp -o ll_isort && ./ll_isort
132124
g++ -std=c++20 -O2 -Wall -Wextra -pedantic -DTRACE main.cpp -o ll_isort && ./ll_isort
133125
```
134126

135-
Windows quick start
127+
#### Windows quick start
136128
```
137129
:: Command Prompt (.bat)
138130
run.bat
@@ -143,33 +135,31 @@ run.bat trace :: enable teaching trace
143135
./run.ps1 -Trace
144136
```
145137

146-
Option A: CMake
138+
#### Option A: CMake
147139
```
148140
cmake -S . -B build
149141
cmake --build build
150142
./build/linked_list_insertion_sort
151143
```
152144

153-
Option B: One-liner
145+
#### Option B: One-liner
154146
```
155147
g++ -std=c++17 -O2 -Wall -Wextra -pedantic main.cpp -o ll_isort
156148
./ll_isort
157149
```
158150

159-
Expected output:
151+
#### Expected output:
160152

161153
```
162154
Before sort: 39 -> 45 -> 11 -> 22
163155
After sort: 11 -> 22 -> 39 -> 45
164156
```
165157

166-
167-
168-
(Optional) Trace mode for teaching
158+
### (Optional) Trace mode for teaching
169159

170-
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`.**
171161

172-
Enable TRACE:
162+
#### Enable TRACE:
173163

174164
```
175165
# CMake
@@ -182,75 +172,70 @@ make run TRACE=1
182172
g++ -std=c++20 -O2 -Wall -Wextra -pedantic -DTRACE main.cpp -o ll_isort && ./ll_isort
183173
```
184174

185-
186175

187-
Visual trace (ANSI borders + colors)
176+
### Visual trace (ANSI borders + colors)
188177

189178
With TRACE enabled, each step prints an ANSI-bordered box with the list and role markers (H,P,C,N,S). Colors auto-disable if not a TTY.
190179

191-
Example (your terminal will show colors):
180+
#### Example (your terminal will show colors):
192181

193182
```
194183
╔══════════════════════════════════════════════════════════════╗
195184
║ State: BEFORE place (H=head, P=prev, C=curr, N=next, S=spot) ║
196185
║ [39] -> [45] -> [11] -> [22] ║
197-
H P C N ║
186+
║ H P C N
198187
╚══════════════════════════════════════════════════════════════╝
199188
200189
╔═════════════════════════════════════╗
201190
║ State: AFTER unlink (curr isolated) ║
202191
║ [39] -> [45] -> [22] ║
203-
H P N ║
192+
║ H P N
204193
╚═════════════════════════════════════╝
205194
206195
C (isolated): [11]
207196
208197
╔════════════════════════════════════╗
209198
║ State: AFTER insert after S (spot) ║
210199
║ [11] -> [22] -> [39] -> [45] ║
211-
S C P
200+
║ S C P
212201
╚════════════════════════════════════╝
213202
```
214203

215-
Legend
204+
#### Legend
216205
- H = head node
217206
- P = prev (end of sorted prefix)
218207
- C = curr (node being placed)
219208
- N = next (saved pointer for the next loop)
220209
- S = spot (node after which `curr` will be inserted; S at head means insert at head)
221210

222-
Notes
211+
#### Notes
223212
- Colors are 256-color safe and disabled when stdout is not a TTY (e.g., piped to file).
224213
- The bordered state is generated by `trace_ui.hpp` and integrated into `main.cpp` under `#ifdef TRACE`.
225214

226-
227215

228-
Educational purpose and teaching notes
216+
### Educational purpose and teaching notes
229217
- The code favors readability and pointer hygiene over micro-optimizations.
230218
- Each operation is isolated (prepend/insert/remove) so students can test them independently.
231219
- 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.
232220
- Stability comes from scanning with `<` (not `<=`), so equal keys keep their original relative order.
233221

234-
235222

236-
Common pitfalls (and how this code avoids them)
223+
### Common pitfalls (and how this code avoids them)
237224
- Losing the rest of the list: Always set `Node* next = curr->next;` before you move `curr`.
238225
- Breaking links: `ListInsertAfter` sets `newNode->next = prev->next` before `prev->next = newNode`.
239226
- Head updates: When inserting at the front, use `ListPrepend` (it updates `head`).
240227
- Scanning into unsorted area: `FindInsertionSpot` stops at `boundary` to keep the search in the sorted prefix.
241228
- Advancing `prev` incorrectly: Only advance `prev` if no move occurred (i.e., `spot == prev`).
242229

243-
244230

245-
Exercises
231+
### Exercises
246232
1. Make it generic: turn `int` into a templated `T` with a comparator.
247233
2. Add `PushFront`, `PopFront`, `PopAfter` to practice pointer edits.
248234
3. Create randomized tests that compare to `std::stable_sort` on a vector as an oracle.
249235
4. Show stability: add duplicates and verify the original order of equals is preserved.
250236

251-
252237

253-
File tree
238+
### File tree
254239

255240
```
256241
.
@@ -264,9 +249,8 @@ File tree
264249
└── .gitignore # Ignores build artifacts and IDE files
265250
```
266251

267-
268252

269-
Function reference (quick)
253+
### Function reference (quick)
270254

271255
- `struct Node { int data; Node* next; }`
272256
- A single list node. `data` holds the value, `next` points to the next node or `nullptr`.
@@ -287,15 +271,15 @@ Function reference (quick)
287271
- `void PrintList(const List* list)`
288272
- Prints values like `1 -> 2 -> 3`.
289273

290-
Trace UI reference
274+
### Trace UI reference
291275

292276
- Header: `trace_ui.hpp` (enabled only when `TRACE` is defined)
293277
- `traceui::print_state(title, head, roles)` prints a bordered, colored snapshot.
294278
- Roles struct: `traceui::PtrRoles<Node>{H,P,C,N,S}` marks head, prev, curr, next, spot.
295279
- Palette constants (256‑color): `C_HEAD, C_PREV, C_CURR, C_NEXT, C_SPOT, C_TEXT, C_BORDER`.
296280
- Colors auto‑disable if stdout is not a TTY.
297281

298-
Troubleshooting
282+
### Troubleshooting
299283

300284
- Compiler not found on Windows
301285
- Use `run.bat` or `run.ps1` with g++/clang++ installed (MSYS2/MinGW or LLVM). Or use CMake + Visual Studio generator.

0 commit comments

Comments
 (0)