Implemented QueuedLinkedList

This commit is contained in:
Andrey Terentev 2024-01-11 18:09:36 +07:00
parent 52039e9804
commit 2e1b50c96c
2 changed files with 172 additions and 0 deletions

View File

@ -0,0 +1,109 @@
package ru.dragonestia.picker.service.impl.collection;
import java.util.HashMap;
import java.util.Map;
public class QueuedLinkedList<ITEM extends QueuedLinkedList.Item> {
private Node<ITEM> first;
private Node<ITEM> last;
private Node<ITEM> cursor;
private final Map<String, Node<ITEM>> itemMap = new HashMap<>();
public void add(ITEM item) {
if (itemMap.containsKey(item.getId())) return;
Node<ITEM> node = new Node<>(item);
if (first == null) {
first = node;
last = first;
} else {
node.prev = last;
last.next = node;
last = node;
}
itemMap.put(item.getId(), node);
}
public void remove(ITEM item) {
if (!itemMap.containsKey(item.getId())) return;
var node = itemMap.get(item.getId());
itemMap.remove(item.getId());
node.removed = true;
if (node.prev == null) { // first element
first = node.next;
if (first != null) {
first.prev = null;
}
}
if (node.next == null) { // last element
last = node.prev;
if (last != null) {
last.next = null;
}
}
if (node.next != null && node.prev != null) { // middle element
var prev = node.prev;
var next = node.next;
prev.next = next;
next.prev = prev;
}
}
public int size() {
return itemMap.size();
}
public void resetCursor() {
cursor = null;
}
public ITEM pick() {
if (first == null) {
throw new RuntimeException("List is empty");
}
if (cursor == null) cursor = first;
Node<ITEM> item = cursor;
while (item != null && item.removed) {
item = item.next;
}
if (item == null) item = first;
cursor = item.next;
return item.object;
}
private static class Node<ITEM extends Item> {
private final ITEM object;
private Node<ITEM> prev, next;
private boolean removed = false;
public Node(ITEM object) {
this.object = object;
}
@Override
public String toString() {
return "{Node id=%s, prev=%s, next=%s, removed=%s }".formatted(
object.getId(),
prev == null? null : prev.object.getId(),
next == null? null : next.object.getId(),
removed
);
}
}
public interface Item {
String getId();
}
}

View File

@ -0,0 +1,63 @@
package ru.dragonestia.picker.collection;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import ru.dragonestia.picker.service.impl.collection.QueuedLinkedList;
import java.util.HashSet;
public class QueuedLinkedListTests {
@Test
void testQueuedLinkedList() {
var list = new QueuedLinkedList<Item>();
for (int i = 0; i < 10; i++) {
list.add(new Item(Integer.toString(i)));
}
printList(list);
var removed = new HashSet<String>();
for (int i = 5; i < 8; i++) {
var id = Integer.toString(i);
list.remove(new Item(id));
System.out.println("Removed: " + id);
removed.add(id);
}
printList(list);
for (int i = 0; i < 20; i++) {
var item = list.pick();
System.out.println("Picked: " + item.getId());
Assertions.assertFalse(removed.contains(item.getId()));
}
}
private void printList(QueuedLinkedList<Item> list) {
list.resetCursor();
var sb = new StringBuilder("List(" + list.size() + "): ");
for (int i = 0, n = list.size(); i < n; i++) {
sb.append(i);
if (i + 1 != n) sb.append(", ");
}
System.out.println(sb);
}
public static class Item implements QueuedLinkedList.Item {
private final String id;
public Item(String id) {
this.id = id;
}
@Override
public String getId() {
return id;
}
}
}