Insert After Value in Circular Linked List
Problem Statement
Write a Java program that adds a method to insert a new node with a given value after the first occurrence of a specified target value in a circular linked list. A circular linked list is a singly linked list where the last node’s next pointer points to the head, forming a cycle. The method should insert the new node by updating the next pointers to maintain the circular structure and return true if the insertion is successful (target value found) or false if the target value is not found. Test the implementation with cases where the target value exists in the list and where it does not, including empty lists and single-node lists. You can visualize this as adding a new numbered card to a circular chain of cards, placing it right after the first card with a specific number.
Input:
- A circular linked list of integers (e.g., 1→2→3→1, where 3→1 forms the cycle), a target value (e.g., 2), and a new value to insert (e.g., 4). Output: A boolean indicating whether the insertion was successful, and the updated list printed as a string, listing nodes from the head until just before it cycles (e.g., "1 2 4 3"). Constraints:
- The list size is between 0 and 10^5.
- Node values and the new value are integers in the range [-10^9, 10^9].
- The list may be empty or not contain the target value. Example:
- Input: List = 1→2→3→1, target = 2, newValue = 4
- Output: true, "1 2 4 3"
- Explanation: Inserts 4 after the first 2, resulting in 1→2→4→3→1.
- Input: List = 1→2→3→1, target = 5, newValue = 4
- Output: false, "1 2 3"
- Explanation: Target 5 not found, list unchanged.
- Input: List = [], target = 1, newValue = 2
- Output: false, "[]"
- Explanation: Empty list, no insertion possible.
Pseudocode
CLASS Node
SET value to integer
SET next to Node (null by default)
ENDCLASS
FUNCTION insertAfterValue(head, target, newValue)
IF head is null THEN
RETURN false
ENDIF
SET current to head
SET found to false
REPEAT
IF current.value equals target THEN
SET found to true
BREAK
ENDIF
SET current to current.next
UNTIL current equals head
IF not found THEN
RETURN false
ENDIF
CREATE newNode as new Node(newValue)
SET newNode.next to current.next
SET current.next to newNode
RETURN true
ENDFUNCTION
FUNCTION toString(head)
IF head is null THEN
RETURN "[]"
ENDIF
CREATE result as new StringBuilder
SET current to head
SET visited as new Set
WHILE current is not null AND current not in visited
ADD current to visited
APPEND current.value to result
IF current.next is not head THEN
APPEND " " to result
ENDIF
SET current to current.next
ENDWHILE
RETURN result as string
ENDFUNCTION
FUNCTION main()
SET testCases to array of test cases (list values, target, newValue)
FOR each testCase in testCases
PRINT test case details
CALL insertAfterValue(testCase.head, testCase.target, testCase.newValue)
PRINT insertion result and updated list using toString
ENDFOR
ENDFUNCTION
Algorithm Steps
- Define a
Nodeclass with: a. An integervalue. b. Anextpointer to the next node. - In
insertAfterValue: a. If the list is empty, return false. b. Traverse the list starting from head until the target value is found or the traversal returns to head. c. If target is not found, return false. d. If target is found:- Create a new node with
newValue. - Set
newNode.nexttocurrent.next. - Set
current.nexttonewNode. - Return true.
- Create a new node with
- In
toString: a. If head is null, return "[]". b. Traverse from head, use a Set to avoid cycling, append values with spaces. c. Return the string representation. - In
main, test with cases where the target exists, does not exist, and edge cases like empty or single-node lists.
Java Implementation
import java.util.*;
public class InsertAfterValueCircular {
// Node class for the circular linked list
static class Node {
int value;
Node next;
Node(int value) {
this.value = value;
this.next = null;
}
}
// Inserts a new node after the first occurrence of target
public boolean insertAfterValue(Node head, int target, int newValue) {
if (head == null) {
return false;
}
Node current = head;
boolean found = false;
do {
if (current.value == target) {
found = true;
break;
}
current = current.next;
} while (current != head);
if (!found) {
return false;
}
Node newNode = new Node(newValue);
newNode.next = current.next;
current.next = newNode;
return true;
}
// Converts circular linked list to string
public String toString(Node head) {
if (head == null) {
return "[]";
}
StringBuilder result = new StringBuilder();
Node current = head;
Set<Node> visited = new HashSet<>();
while (current != null && !visited.contains(current)) {
visited.add(current);
result.append(current.value);
if (current.next != head) {
result.append(" ");
}
current = current.next;
}
return result.toString();
}
// Helper class for test cases
static class TestCase {
Node head;
int target;
int newValue;
TestCase(int[] values, int target, int newValue) {
this.target = target;
this.newValue = newValue;
if (values.length == 0) {
head = null;
return;
}
head = new Node(values[0]);
Node current = head;
for (int i = 1; i < values.length; i++) {
current.next = new Node(values[i]);
current = current.next;
}
// Make circular
current.next = head;
}
}
// Main method to test insert after value
public static void main(String[] args) {
InsertAfterValueCircular inserter = new InsertAfterValueCircular();
// Test cases
TestCase[] testCases = {
new TestCase(new int[]{1, 2, 3}, 2, 4), // Target exists
new TestCase(new int[]{1, 2, 3}, 5, 4), // Target does not exist
new TestCase(new int[]{}, 1, 2), // Empty list
new TestCase(new int[]{5}, 5, 6), // Single node, target exists
new TestCase(new int[]{1, 1, 1}, 1, 2) // Duplicates, insert after first
};
// Run test cases
for (int i = 0; i < testCases.length; i++) {
TestCase test = testCases[i];
System.out.println("Test case " + (i + 1) + ":");
System.out.println("Input list: " + inserter.toString(test.head));
System.out.println("Insert " + test.newValue + " after " + test.target);
boolean result = inserter.insertAfterValue(test.head, test.target, test.newValue);
System.out.println("Insertion successful: " + result);
System.out.println("Updated list: " + inserter.toString(test.head) + "\n");
}
}
}
Output
Running the main method produces:
Test case 1:
Input list: 1 2 3
Insert 4 after 2
Insertion successful: true
Updated list: 1 2 4 3
Test case 2:
Input list: 1 2 3
Insert 4 after 5
Insertion successful: false
Updated list: 1 2 3
Test case 3:
Input list: []
Insert 2 after 1
Insertion successful: false
Updated list: []
Test case 4:
Input list: 5
Insert 6 after 5
Insertion successful: true
Updated list: 5 6
Test case 5:
Input list: 1 1 1
Insert 2 after 1
Insertion successful: true
Updated list: 1 2 1 1
Explanation:
- Test case 1: Inserts 4 after first 2, resulting in 1→2→4→3→1.
- Test case 2: Target 5 not found, list unchanged, returns false.
- Test case 3: Empty list, no insertion, returns false.
- Test case 4: Inserts 6 after 5 in single-node list, resulting in 5→6→5.
- Test case 5: Inserts 2 after first 1 in 1→1→1→1, resulting in 1→2→1→1→1.
How It Works
- Node: Stores an integer value and a
nextpointer. - insertAfterValue:
- Returns false for empty lists.
- Traverses the list in a loop, stopping at the first node with the target value or when returning to head.
- If target is not found, returns false.
- If found, inserts new node, updating
nextpointers, returns true.
- toString: Traverses from head, uses a Set to prevent cycling, returns space-separated string or "[]".
- Example Trace (Test case 1):
- Input: 1→2→3→1, target=2, newValue=4.
- current=1, no match, current=2, match.
- newNode(4).next=3, 2.next=newNode.
- Result: 1→2→4→3→1, return true.
- Main Method: Tests target exists, target does not exist, empty list, single node, and duplicates.
Complexity Analysis Table
| Operation | Time Complexity | Space Complexity |
|---|---|---|
| Insert After Value | O(n) | O(1) |
| To String | O(n) | O(n) |
Note:
- n is the number of nodes in the list.
- Time complexity: O(n) for insertAfterValue (traverse to find target); O(n) for toString (traverse list).
- Space complexity: O(1) for insertAfterValue (constant pointers); O(n) for toString (StringBuilder and Set).
- Worst case: O(n) time, O(n) space for output with large lists.
✅ Tip: Use a do-while loop to traverse the circular list and stop at the head to avoid infinite loops. Insert the new node by carefully updating
nextpointers to maintain the circular structure.
⚠ Warning: Check for the target value in one full cycle to handle cases where it doesn’t exist. Ensure proper handling of edge cases like empty or single-node lists to avoid null pointer issues.