LinkedList: implement insert and reverse

This commit is contained in:
Denis-Cosmin Nutiu 2024-04-14 10:13:07 +03:00
parent 3759d5eb84
commit e43fc8e7f0
2 changed files with 176 additions and 1 deletions

View file

@ -43,6 +43,43 @@ class LinkedList<T> : Iterable<Node<T>> {
size += 1 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<T>? = head
var previousNode: Node<T>? = 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 * Returns from the list
*/ */
@ -64,7 +101,7 @@ class LinkedList<T> : Iterable<Node<T>> {
*/ */
fun delete(position: Int) { fun delete(position: Int) {
if (size == 0 || position < 0 || position >= size) { if (size == 0 || position < 0 || position >= size) {
return throw IllegalArgumentException("invalid position given")
} }
// delete head // delete head
if (position == 0) { if (position == 0) {
@ -84,8 +121,10 @@ class LinkedList<T> : Iterable<Node<T>> {
previousNode = currentNode previousNode = currentNode
currentNode = currentNode?.next currentNode = currentNode?.next
currentPosition += 1 currentPosition += 1
// we found element at position N which is about to get deleted
if (currentPosition == position) { if (currentPosition == position) {
previousNode!!.next = currentNode?.next previousNode!!.next = currentNode?.next
// we deleted the tail, so we need to update tail var.
if (currentPosition == size - 1) { if (currentPosition == size - 1) {
tail = previousNode tail = previousNode
} }
@ -109,6 +148,32 @@ class LinkedList<T> : Iterable<Node<T>> {
return size return size
} }
/**
* Reverses the list in place.
*/
fun reverse() {
if (size == 1) {
return
}
tail = head
var currentNode = head
var previousNode: Node<T>? = 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. * NodeIterator that iterates over linked list nodes.
*/ */

View file

@ -150,6 +150,21 @@ class LinkedListTest {
assertEquals("Second", linkedList.getLast()) assertEquals("Second", linkedList.getLast())
} }
@Test
fun deleteInvalidPosition() {
// Setup
val linkedList = LinkedList<String>()
linkedList.append("First")
// Test
assertThrows(IllegalArgumentException::class.java) {
linkedList.delete(-1)
}
assertThrows(IllegalArgumentException::class.java) {
linkedList.delete(99)
}
}
@Test @Test
fun toJavaList() { fun toJavaList() {
// Setup // Setup
@ -164,4 +179,99 @@ class LinkedListTest {
// Assert // Assert
assertContentEquals(listOf("First", "Second", "Third"), result) assertContentEquals(listOf("First", "Second", "Third"), result)
} }
@Test
fun insertFirst() {
// Setup
val linkedList = LinkedList<String>()
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<String>()
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<String>()
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<String>()
linkedList.append("First")
// Test
linkedList.reverse()
// Assert
assertContentEquals(listOf("First"), linkedList.toJavaList())
}
@Test
fun reverseTwoElements() {
// Setup
val linkedList = LinkedList<String>()
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<String>()
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())
}
} }