Insert After Value
Problem Statement
Write a Java program that extends a doubly linked list implementation to include a method that inserts a new node with a given value after the first occurrence of a specified target value. The doubly linked list consists of nodes, each containing an integer value, a reference to the next node, and a reference to the previous node. The program should insert the new node by updating the next and prev pointers appropriately 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 card to a chain of numbered cards, placing it right after the first card with a specific number.
Input:
- A doubly linked list of integers (e.g., 1↔2↔3), 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 in forward order (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, target = 2, newValue = 4
- Output: true, "1 2 4 3"
- Explanation: Inserts 4 after the first 2, resulting in 1↔2↔4↔3.
- Input: List = 1↔2↔3, 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 DoublyNode
SET value to integer
SET next to DoublyNode (null by default)
SET prev to DoublyNode (null by default)
ENDCLASS
FUNCTION insertAfterValue(head, target, newValue)
IF head is null THEN
RETURN false
ENDIF
SET current to head
WHILE current is not null
IF current.value equals target THEN
CREATE newNode as new DoublyNode(newValue)
SET newNode.next to current.next
SET newNode.prev to current
IF current.next is not null THEN
SET current.next.prev to newNode
ENDIF
SET current.next to newNode
RETURN true
ENDIF
SET current to current.next
ENDWHILE
RETURN false
ENDFUNCTION
FUNCTION printForward(head)
IF head is null THEN
RETURN "[]"
ENDIF
CREATE result as new StringBuilder
SET current to head
WHILE current is not null
APPEND current.value to result
IF current.next is not null 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, 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 printForward
ENDFOR
ENDFUNCTION
Algorithm Steps
- Define a
DoublyNodeclass with: a. An integervalue. b. Anextpointer to the next node. c. Aprevpointer to the previous node. - In
insertAfterValue: a. If head is null, return false (empty list). b. Traverse the list usingcurrentuntil the target value is found or the list ends. c. If target is found:- Create a new node with
newValue. - Set
newNode.nexttocurrent.nextandnewNode.prevtocurrent. - Update
current.next.prevtonewNodeifcurrent.nextexists. - Set
current.nexttonewNode. - Return true. d. If target is not found, return false.
- Create a new node with
- In
printForward: a. If head is null, return "[]". b. Traverse the list usingnextpointers, appending each value 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
public class InsertAfterValue {
// Node class for the doubly linked list
static class DoublyNode {
int value;
DoublyNode next;
DoublyNode prev;
DoublyNode(int value) {
this.value = value;
this.next = null;
this.prev = null;
}
}
// Inserts a new node after the first occurrence of target
public boolean insertAfterValue(DoublyNode head, int target, int newValue) {
if (head == null) {
return false;
}
DoublyNode current = head;
while (current != null) {
if (current.value == target) {
DoublyNode newNode = new DoublyNode(newValue);
newNode.next = current.next;
newNode.prev = current;
if (current.next != null) {
current.next.prev = newNode;
}
current.next = newNode;
return true;
}
current = current.next;
}
return false;
}
// Prints the list in forward direction
public String printForward(DoublyNode head) {
if (head == null) {
return "[]";
}
StringBuilder result = new StringBuilder();
DoublyNode current = head;
while (current != null) {
result.append(current.value);
if (current.next != null) {
result.append(" ");
}
current = current.next;
}
return result.toString();
}
// Helper class for test cases
static class TestCase {
DoublyNode 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 DoublyNode(values[0]);
DoublyNode current = head;
for (int i = 1; i < values.length; i++) {
DoublyNode newNode = new DoublyNode(values[i]);
newNode.prev = current;
current.next = newNode;
current = newNode;
}
}
}
// Main method to test insert after value
public static void main(String[] args) {
InsertAfterValue inserter = new InsertAfterValue();
// 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.printForward(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.printForward(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.
- 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.
- Test case 5: Inserts 2 after first 1 in 1↔1↔1, resulting in 1↔2↔1↔1.
How It Works
- DoublyNode: Stores an integer value, a
nextpointer, and aprevpointer. - insertAfterValue:
- Returns false for empty lists.
- Traverses list to find first node with target value.
- If found, inserts new node, updating
nextandprevpointers, returns true. - If not found, returns false.
- printForward: Traverses list using
nextpointers, returns space-separated string or "[]". - Example Trace (Test case 1):
- Input: 1↔2↔3, target=2, newValue=4.
- current=1, no match, move to 2.
- current=2, match: create newNode(4), newNode.next=3, newNode.prev=2, 3.prev=newNode, 2.next=newNode.
- Result: 1↔2↔4↔3, 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) |
| Print Forward | 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 printForward (traverse list).
- Space complexity: O(1) for insertAfterValue (constant pointers); O(n) for printForward (StringBuilder).
- Worst case: O(n) time, O(n) space for output with large lists.
✅ Tip: Use the doubly linked list’s
prevpointers to easily link the new node to the next node’s previous pointer, ensuring bidirectional consistency. Test with duplicates to verify insertion after the first occurrence.
⚠ Warning: Update both
nextandprevpointers carefully to maintain the doubly linked list structure. Check for null pointers to handle edge cases like empty lists or inserting at the end.