From 506c2cedc1802ca8cd310b9b62d546b8ce57aa3d Mon Sep 17 00:00:00 2001 From: Eugene Kovko <37694937+eukovko@users.noreply.github.com> Date: Thu, 4 Jan 2024 04:17:12 +0100 Subject: [PATCH] Bael 7408 (#15541) * 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 --- .../linkedlistremove/SinglyLinkedList.java | 106 ++++++++++++++++++ .../linkedlistremove/CreateListProvider.java | 28 +++++ .../linkedlistremove/DeleteListProvider.java | 23 ++++ .../SinglyLinkedListUnitTest.java | 86 ++++++++++++++ 4 files changed, 243 insertions(+) create mode 100644 core-java-modules/core-java-collections-list-6/src/main/java/com/baeldung/linkedlistremove/SinglyLinkedList.java create mode 100644 core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/linkedlistremove/CreateListProvider.java create mode 100644 core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/linkedlistremove/DeleteListProvider.java create mode 100644 core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/linkedlistremove/SinglyLinkedListUnitTest.java diff --git a/core-java-modules/core-java-collections-list-6/src/main/java/com/baeldung/linkedlistremove/SinglyLinkedList.java b/core-java-modules/core-java-collections-list-6/src/main/java/com/baeldung/linkedlistremove/SinglyLinkedList.java new file mode 100644 index 0000000000..58cf2ada6d --- /dev/null +++ b/core-java-modules/core-java-collections-list-6/src/main/java/com/baeldung/linkedlistremove/SinglyLinkedList.java @@ -0,0 +1,106 @@ +package com.baeldung.linkedlistremove; + +import java.util.Objects; + +public class SinglyLinkedList { + + private int size; + private Node head = null; + private Node tail = null; + + public boolean isEmpty() { + return size() == 0; + } + + public int size() { + return size; + } + + public void add(S element) { + Node 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 previous = null; + Node current = head; + while (current != null) { + if (Objects.equals(element, current.element)) { + Node next = current.next; + if (isFistNode(current)) { + head = next; + } else if (isLastNode(current)) { + previous.next = null; + } else { + Node 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 secondToLast = null; + Node 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 current = head; + while (current != null) { + if (Objects.equals(element, current.element)) + return true; + current = current.next; + } + return false; + } + + private boolean isLastNode(Node node) { + return tail == node; + } + + private boolean isFistNode(Node node) { + return head == node; + } + + + public static class Node { + private T element; + private Node next; + + public Node(T element) { + this.element = element; + } + } + +} diff --git a/core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/linkedlistremove/CreateListProvider.java b/core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/linkedlistremove/CreateListProvider.java new file mode 100644 index 0000000000..2b92903310 --- /dev/null +++ b/core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/linkedlistremove/CreateListProvider.java @@ -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 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) + ); + } +} diff --git a/core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/linkedlistremove/DeleteListProvider.java b/core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/linkedlistremove/DeleteListProvider.java new file mode 100644 index 0000000000..8f74a66d6b --- /dev/null +++ b/core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/linkedlistremove/DeleteListProvider.java @@ -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 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) + ); + } +} diff --git a/core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/linkedlistremove/SinglyLinkedListUnitTest.java b/core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/linkedlistremove/SinglyLinkedListUnitTest.java new file mode 100644 index 0000000000..1bc16caefa --- /dev/null +++ b/core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/linkedlistremove/SinglyLinkedListUnitTest.java @@ -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 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 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 SOURCE = + List.of("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"); + + @BeforeEach + void setup() { + SOURCE.forEach(linkedList::add); + } + + @ParameterizedTest + @ArgumentsSource(DeleteListProvider.class) + void whenDeleteElementsSizeIsCorrect(List 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()); + } + } + +}