* BAEL-7408: SinglyLinkedList Example

* BAEL-7408: Extract Node interface

* BAEL-7408: Setup for WrappedNode LinkedList

* BAEL-7408: Removed WrappedNode and cleaned the example

* BAEL-7408: Removed Node interface

* BAEL-7408: Additional test for removeLast
This commit is contained in:
Eugene Kovko 2024-01-04 04:17:12 +01:00 committed by GitHub
parent 7f9d025510
commit 506c2cedc1
4 changed files with 243 additions and 0 deletions

View File

@ -0,0 +1,106 @@
package com.baeldung.linkedlistremove;
import java.util.Objects;
public class SinglyLinkedList<S> {
private int size;
private Node<S> head = null;
private Node<S> tail = null;
public boolean isEmpty() {
return size() == 0;
}
public int size() {
return size;
}
public void add(S element) {
Node<S> newTail = new Node<>(element);
if (head == null) {
tail = newTail;
head = tail;
} else {
tail.next = newTail;
tail = newTail;
}
++size;
}
public void remove(S element) {
if (isEmpty())
return;
Node<S> previous = null;
Node<S> current = head;
while (current != null) {
if (Objects.equals(element, current.element)) {
Node<S> next = current.next;
if (isFistNode(current)) {
head = next;
} else if (isLastNode(current)) {
previous.next = null;
} else {
Node<S> next1 = current.next;
previous.next = next1;
}
--size;
break;
}
previous = current;
current = current.next;
}
}
public void removeLast() {
if (isEmpty())
return;
if (size() == 1) {
tail = null;
head = null;
} else {
Node<S> secondToLast = null;
Node<S> last = head;
while (last.next != null) {
secondToLast = last;
last = last.next;
}
secondToLast.next = null;
}
--size;
}
public boolean contains(S element) {
if (isEmpty())
return false;
Node<S> current = head;
while (current != null) {
if (Objects.equals(element, current.element))
return true;
current = current.next;
}
return false;
}
private boolean isLastNode(Node<S> node) {
return tail == node;
}
private boolean isFistNode(Node<S> node) {
return head == node;
}
public static class Node<T> {
private T element;
private Node<T> next;
public Node(T element) {
this.element = element;
}
}
}

View File

@ -0,0 +1,28 @@
package com.baeldung.linkedlistremove;
import java.util.List;
import java.util.stream.Stream;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
public class CreateListProvider implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of(
Arguments.of(List.of("January"), 1),
Arguments.of(List.of("January", "February"), 2),
Arguments.of(List.of("January", "February", "March"), 3),
Arguments.of(List.of("January","February","March","April"), 4),
Arguments.of(List.of("January","February","March","April","May"), 5),
Arguments.of(List.of("January","February","March","April","May","June"), 6),
Arguments.of(List.of("January","February","March","April","May","June","July"), 7),
Arguments.of(List.of("January","February","March","April","May","June","July","August"), 8),
Arguments.of(List.of("January","February","March","April","May","June","July","August","September"), 9),
Arguments.of(List.of("January","February","March","April","May","June","July","August","September","October"), 10),
Arguments.of(List.of("January","February","March","April","May","June","July","August","September","October","November"), 11),
Arguments.of(List.of("January","February","March","April","May","June","July","August","September","October","November","December"), 12)
);
}
}

View File

@ -0,0 +1,23 @@
package com.baeldung.linkedlistremove;
import java.util.List;
import java.util.stream.Stream;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
public class DeleteListProvider implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of(
Arguments.of(List.of("Monday"), 6),
Arguments.of(List.of("Monday", "Tuesday"), 5),
Arguments.of(List.of("Monday", "Tuesday", "Wednesday"), 4),
Arguments.of(List.of("Monday", "Tuesday", "Wednesday", "Thursday"), 3),
Arguments.of(List.of("Monday", "Tuesday", "Wednesday", "Thursday", "Friday"), 2),
Arguments.of(List.of("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"), 1),
Arguments.of(List.of("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"), 0)
);
}
}

View File

@ -0,0 +1,86 @@
package com.baeldung.linkedlistremove;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ArgumentsSource;
import org.junit.jupiter.params.provider.CsvSource;
class SinglyLinkedListUnitTest {
private SinglyLinkedList<String> linkedList;
@BeforeEach
void setup() {
linkedList = new SinglyLinkedList<>();
}
@Nested
@DisplayName("Given an empty list")
class GivenEmptyLinkedList {
@Test
void whenNewListThenListEmpty() {
assertThat(linkedList.isEmpty()).isTrue();
}
@Test
void whenAddElementThenListNotEmpty() {
linkedList.add("Hello world!");
assertThat(linkedList.isEmpty()).isFalse();
}
@ParameterizedTest
@ArgumentsSource(CreateListProvider.class)
void whenAddingElementsThenSizeIsCorrect(List<String> toAdd, int expectedSize) {
toAdd.forEach(linkedList::add);
assertThat(linkedList.size()).isEqualTo(expectedSize);
toAdd.forEach(s -> assertThat(linkedList.contains(s)).isTrue());
}
}
@Nested
@DisplayName("Given a filled list")
class GivenFilledLinkedList {
private final List<String> SOURCE =
List.of("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday");
@BeforeEach
void setup() {
SOURCE.forEach(linkedList::add);
}
@ParameterizedTest
@ArgumentsSource(DeleteListProvider.class)
void whenDeleteElementsSizeIsCorrect(List<String> toDelete, int expectedSize) {
toDelete.forEach(linkedList::remove);
assertThat(linkedList.size()).isEqualTo(expectedSize);
toDelete.forEach(s -> assertThat(linkedList.contains(s)).isFalse());
}
@ParameterizedTest
@CsvSource({
"1,6",
"2,5",
"3,4",
"4,3",
})
void whenDeleteElementsSizeIsCorrect(int toRemove, int expectedSize) {
for (int i = 0; i < toRemove; i++) {
linkedList.removeLast();
}
assertThat(linkedList.size()).isEqualTo(expectedSize);
SOURCE.subList(0, expectedSize).forEach(s -> assertThat(linkedList.contains(s)).isTrue());
}
}
}