In the split-reverse-interleave reorder of a linked chain, which half gets the odd extra node?
answer
- count the splices the loop performs
- each back node follows a front node
- which half can afford to run out first
- five jobs split three and two
- front half must never be shorter
basics
~20 sThe front half keeps the extra node: ceil(n/2) in front, floor(n/2) behind. The splice attaches one back node after each front node, so a longer back half leaves a trailing node with no front node to follow.
solid answer
~50 sThe interleave has an invariant: the front half must never be shorter than the reversed back half, because every iteration consumes exactly one node from each and each back node is spliced in after a front node. With an odd count that forces ceil(n/2) into the front half — the leftover front node ends up as the tail of the result, which is exactly right for the target order. Hand the extra node to the back half instead and the final iteration finds `front` already null and dereferences it, or silently drops the last node depending on how the loop is written. The second parity trap is forgetting to cut the front half loose at the split: its old tail still points into the back half, and after the splice that stray link closes a cycle, so traversing the result never terminates.
code
pseudocode · 9 lines// front: head of the detached front half (terminated)
// back: head of the reversed back half
while back != null:
t1 = front.next
t2 = back.next
front.next = back
back.next = t1
front = t1
back = t2go deeper
Know the target order — first, last, second, second-to-last — and that it is built by splitting the chain, reversing the back part, and alternating between the two halves.
Trace a five-node chain out loud with three nodes in the front half, and explain the loop condition that stops the moment the reversed back half is exhausted.
Name the two failure modes precisely: a null dereference or a dropped node when the back half is longer, and a non-terminating cycle when the front half was never cut at the split.
Weigh whether this in-place rewiring belongs in shared code at all — an array-of-references version costs a few bytes per node and removes a class of review-resistant link bugs.
## The target shape Take a print queue held as a singly linked chain and rearrange it so jobs alternate from the two ends inward: first job, last job, second job, second-to-last job, and so on. The constant-space construction has three moves: 1. **Split** the chain into a front half and a back half. 2. **Reverse** the back half in place, so its last job becomes the head of that segment. 3. **Splice** alternately: one front node, one back node, one front node, one back node, until the back half is used up. All three moves rewire existing links, so the whole reorder is O(n) time and O(1) extra space. ## The invariant the splice depends on Look at one iteration of the splice loop in the fragment: it saves both successors, points the current front node at the current back node, points that back node at the saved front successor, then advances both pointers. Every iteration consumes **exactly one node from each half**, and every back node is placed **after** a front node. That gives the invariant directly: *the front half must never be shorter than the back half*. If the two are equal (even `n`), the loop consumes them together and both pointers land on null at the same moment. If the front half is one longer (odd `n`), the loop stops when the back half runs out, and the surviving front node is the last one placed — the tail of the result — which is exactly where the middle job belongs in the alternating order. So: **ceil(n/2) in front, floor(n/2) behind.** ## Trace it on five jobs Jobs `a b c d e`. Split gives front `a b c`, back `d e`; reversing the back half gives `e d`. - Iteration 1: save `b` and `d`; link `a -> e`, `e -> b`; advance to front `b`, back `d`. - Iteration 2: save `c` and null; link `b -> d`, `d -> c`; advance to front `c`, back null. - Loop ends. `c` is the front half's tail, already terminating. Result: `a e b d c` — first, last, second, second-to-last, middle. Correct. ## Now give the extra node to the back half Same five jobs, front `a b`, back `c d e` reversed to `e d c`. - Iteration 1: link `a -> e`, `e -> b`; front `b`, back `d`. - Iteration 2: `b` is the front tail, so its successor is null; link `b -> d`, `d -> null`; front becomes null, back becomes `c`. - The loop condition still holds — the back half is not exhausted — so iteration 3 reads `front.next` on a null front. Depending on the environment that is a crash, and in a variant of the loop written to guard against it, node `c` is simply dropped from the result. One node of misallocation, two different production failures. That is why the parity convention is not cosmetic. ## The second trap: cutting the front half Splitting is not just "note where the middle is". The front half's last node must be terminated. If it is left pointing at the first node of the back half, then after the splice that stray link points at a node the loop has already placed somewhere earlier in the result. Traversing the finished chain walks forward into a node it has already visited and never terminates — a cycle, produced by an omission that looks like tidiness. The symptom in a real service is a request that hangs rather than one that fails, which is strictly worse to diagnose. ## Which pointer drives the loop Drive the loop from the **back-half pointer**. When it hits null, every back node has been placed and the front half is either exhausted (even `n`) or holding exactly the leftover tail (odd `n`). Driving from the front pointer instead re-introduces the parity as a special case you must code by hand, and that is where the double-placed node and the dropped tail come from. ## The alternative worth naming If O(n) extra space is acceptable, walk the chain once collecting node references into an array, then relink them by taking references alternately from the front and the back of the array. It is much easier to get right, has no parity subtlety at all beyond a single loop bound, and mutates nothing until the final relink. The in-place version earns its keep when the chain can be long and memory is the binding constraint — not because it is more elegant to read, because it is not. ## What to say "Front half takes the extra node, so it is never shorter than the reversed back half; the splice consumes one from each per step; the loop is driven by the back half so odd length needs no special case; and the front half's tail is terminated at the split, or the result closes a cycle."
- What happens if the front half is never cut loose from the back half at the split?Its old tail still points at the first node of the back half, and after the splice that node sits earlier in the result. Traversing the finished chain therefore walks forward into a node it has already visited and loops forever. Terminating the front half is part of the split, not optional tidiness — and the failure mode is a hang rather than a crash, which is harder to diagnose in production.
- Which pointer should drive the interleave loop, and why does it matter?The reversed back half's pointer. When it runs out, every back node has been placed and the front half is either exhausted (even count) or holding exactly the leftover node, which is already the terminated tail. Driving the loop from the front pointer turns parity into a hand-coded special case, and that is where double-placed nodes and dropped tails come from.
- Does this reorder need auxiliary space?No — split, reverse and splice all rewire existing links, so it is O(n) time and O(1) extra space. The linear-space alternative is to collect node references into an array and relink by taking from the front and the back of that array alternately. That version has no parity subtlety worth speaking of and is far easier to review, which often makes it the one worth shipping.
saying these in an interview costs you the question
- Gives the extra node to the back half
- Leaves the front half pointing into the back half
- Drives the interleave loop from the front pointer
- Says parity cannot affect the splice
- Claims the reorder requires an auxiliary array