diff --git a/src/main/kotlin/data_structures/linked_list/LinkedList.kt b/src/main/kotlin/data_structures/linked_list/LinkedList.kt index 613c090..f1df7c6 100644 --- a/src/main/kotlin/data_structures/linked_list/LinkedList.kt +++ b/src/main/kotlin/data_structures/linked_list/LinkedList.kt @@ -43,6 +43,43 @@ class LinkedList : Iterable> { size += 1 } + /** + * Inserts an element at the given position. + */ + fun insert(value: T, position: Int) { + // handle invalid position + if (position < 0 || position > size) { + throw IllegalArgumentException("invalid position given") + } + // handle insert last + if (position == size) { + append(value) + return + } + // handle insert first + if (position == 0) { + val newNode = Node(value, head) + head = newNode + size += 1 + return + } + var currentPosition = 0 + var currentNode: Node? = head + var previousNode: Node? = null + // search for position to insert at + while (true) { + if (currentPosition == position) { + val newNode = Node(value, currentNode) + previousNode?.next = newNode + size += 1 + break + } + currentPosition += 1 + previousNode = currentNode + currentNode = currentNode?.next + } + } + /** * Returns from the list */ @@ -64,7 +101,7 @@ class LinkedList : Iterable> { */ fun delete(position: Int) { if (size == 0 || position < 0 || position >= size) { - return + throw IllegalArgumentException("invalid position given") } // delete head if (position == 0) { @@ -84,8 +121,10 @@ class LinkedList : Iterable> { previousNode = currentNode currentNode = currentNode?.next currentPosition += 1 + // we found element at position N which is about to get deleted if (currentPosition == position) { previousNode!!.next = currentNode?.next + // we deleted the tail, so we need to update tail var. if (currentPosition == size - 1) { tail = previousNode } @@ -109,6 +148,32 @@ class LinkedList : Iterable> { return size } + /** + * Reverses the list in place. + */ + fun reverse() { + if (size == 1) { + return + } + tail = head + var currentNode = head + var previousNode: Node? = null + var next = head + // we iterate through the list and updates next accordingly, until we reach the tail. + while (next != null) { + // save the next + next = currentNode?.next + // current node's next will be set to previous node. + currentNode?.next = previousNode + // track previous node by settings it to current node + previousNode = currentNode + // track the current node by setting it to next + currentNode = next + } + // update the head + head = previousNode + } + /** * NodeIterator that iterates over linked list nodes. */ diff --git a/src/test/kotlin/data_structures/linked_list/LinkedListTest.kt b/src/test/kotlin/data_structures/linked_list/LinkedListTest.kt index b5c9f6c..fdf4f35 100644 --- a/src/test/kotlin/data_structures/linked_list/LinkedListTest.kt +++ b/src/test/kotlin/data_structures/linked_list/LinkedListTest.kt @@ -150,6 +150,21 @@ class LinkedListTest { assertEquals("Second", linkedList.getLast()) } + @Test + fun deleteInvalidPosition() { + // Setup + val linkedList = LinkedList() + linkedList.append("First") + + // Test + assertThrows(IllegalArgumentException::class.java) { + linkedList.delete(-1) + } + assertThrows(IllegalArgumentException::class.java) { + linkedList.delete(99) + } + } + @Test fun toJavaList() { // Setup @@ -164,4 +179,99 @@ class LinkedListTest { // Assert assertContentEquals(listOf("First", "Second", "Third"), result) } + + @Test + fun insertFirst() { + // Setup + val linkedList = LinkedList() + linkedList.append("Second") + + // Test + linkedList.insert("First", 0) + + // Assert + assertContentEquals(listOf("First", "Second"), linkedList.toJavaList()) + assertEquals("First", linkedList.getFirst()) + assertEquals("Second", linkedList.getLast()) + } + + @Test + fun insertLast() { + // Setup + val linkedList = LinkedList() + linkedList.append("First") + + // Test + linkedList.insert("Second", linkedList.size()) + + // Assert + assertContentEquals(listOf("First", "Second"), linkedList.toJavaList()) + assertEquals("First", linkedList.getFirst()) + assertEquals("Second", linkedList.getLast()) + } + + @Test + fun insertMiddle() { + // Setup + val linkedList = LinkedList() + linkedList.append("First") + linkedList.append("Second") + + // Test + linkedList.insert("Middle", linkedList.size() - 1) + + // Assert + assertContentEquals(listOf("First", "Middle", "Second"), linkedList.toJavaList()) + assertEquals("First", linkedList.getFirst()) + assertEquals("Second", linkedList.getLast()) + } + + @Test + fun reverseOneElement() { + // Setup + val linkedList = LinkedList() + linkedList.append("First") + + // Test + linkedList.reverse() + + // Assert + assertContentEquals(listOf("First"), linkedList.toJavaList()) + } + + @Test + fun reverseTwoElements() { + // Setup + val linkedList = LinkedList() + linkedList.append("First") + linkedList.append("Second") + + // Test + linkedList.reverse() + + // Assert + assertContentEquals(listOf("Second", "First"), linkedList.toJavaList()) + assertEquals("Second", linkedList.getFirst()) + assertEquals("First", linkedList.getLast()) + } + + @Test + fun reverseFiveElements() { + // Setup + val linkedList = LinkedList() + linkedList.append("First") + linkedList.append("Second") + linkedList.append("Third") + linkedList.append("Fourth") + linkedList.append("Fifth") + + + // Test + linkedList.reverse() + + // Assert + assertContentEquals(listOf("Fifth", "Fourth", "Third", "Second", "First"), linkedList.toJavaList()) + assertEquals("Fifth", linkedList.getFirst()) + assertEquals("First", linkedList.getLast()) + } } \ No newline at end of file