Problem: Move Matching Values to the End of a Linked List

Write a recursive function:

Item* ll_movtoend(Item* head, int val);

that moves every Item node whose val equals val to the end of the singly-linked list and returns a pointer to the head of the (possibly) updated list.

Requirements and clarifications

You must NOT allocate new Item nodes. You must relink the existing nodes (remove them from their current position and append them to the moved list).

It is not required to preserve the original relative order of the moved nodes; they may appear in any order at the end, but the nodes that are NOT moved must preserve their relative order.

Examples

Node definition

Assume the following Item struct:

struct Item {
    int val;
    Item* next;
    Item(int v, Item* n) : val(v), next(n) {}
};

Solution

#include <iostream>

// Item definition
struct Item {
    int val;
    Item* next;
    Item(int v, Item* n) : val(v), next(n) {}
};

Item* ll_movtoend_helper(Item* head, Item* duphead, int val) 
{
  if(head == nullptr){
    return duphead;
  }  else if(head->val == val) {
    Item* mynext = head->next;
    head->next = duphead;
    return ll_movtoend_helper(mynext, head, val);
  } else {
    head->next = ll_movtoend_helper(head->next, duphead, val);
    return head;
  }

}
Item* ll_movtoend(Item* head, int val) 
{
  return ll_movtoend_helper(head, nullptr, val);
}

Why it Works (Intuition)

ll_movtoend_helper(head, duphead, val) processes the list starting at head and accumulates all nodes whose value equals val onto the front of duphead. It always returns the head of a partially rebuilt list consisting of:


How the Recursion Works

Base Case

If head == nullptr, the original list has been fully processed.
Return duphead, which contains all nodes that were removed. Notice in the lower cases, that whatever is returned from a recursion is used to fill in the next pointer upon return to nodes that are still in the main list (i.e. whose value does NOT match val).

If head->val == val

If head->val != val

As recursion unwinds, the non-matching nodes rebuild their chain in original order, and at the very end the accumulated duphead list is appended to them.


Example Traces

Example 1

Input:
[3, 1, 3, 2, 3], val = 3

Processing steps (conceptually):

Final result:
[1, 2, 3, 3, 3]

(The moved nodes may be in reverse order of discovery — which is allowed.)


Example 2

Input:
[5, 5, 5], val = 5

All nodes match. Each is moved to duphead.
Final list consists only of those nodes (order may differ from original).


Example 3

Input:
[]

Base case immediately returns nullptr.


Complexity