From 17a471e3a091e54acac6b6b58e3d54b7496a7bff Mon Sep 17 00:00:00 2001 From: Mark Beck <> Date: Tue, 18 Nov 2025 07:33:31 +0100 Subject: [PATCH] feat: add Skiplist impl --- .gitignore | 135 ++++++++++++ .mvn/jvm.config | 0 .mvn/maven.config | 0 checkstyle.xml | 205 ++++++++++++++++++ pmd.xml | 60 +++++ pom.xml | 160 ++++++++++++++ .../java/de/hs_mannheim/pr2/Skiplist.java | 196 +++++++++++++++++ .../java/de/hs_mannheim/pr2/SkiplistTest.java | 78 +++++++ 8 files changed, 834 insertions(+) create mode 100644 .gitignore create mode 100644 .mvn/jvm.config create mode 100644 .mvn/maven.config create mode 100644 checkstyle.xml create mode 100644 pmd.xml create mode 100644 pom.xml create mode 100644 src/main/java/de/hs_mannheim/pr2/Skiplist.java create mode 100644 src/test/java/de/hs_mannheim/pr2/SkiplistTest.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fb7783f --- /dev/null +++ b/.gitignore @@ -0,0 +1,135 @@ +# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,java,maven,eclipse +# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,java,maven,eclipse + +### Eclipse ### +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ +.apt_generated_test/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +# Uncomment this line if you wish to ignore the project description file. +# Typically, this file would be tracked if it contains build/dependency configurations: +#.project + +### Eclipse Patch ### +# Spring Boot Tooling +.sts4-cache/ + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +### Maven ### +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +# https://github.com/takari/maven-wrapper#usage-without-binary-jar +.mvn/wrapper/maven-wrapper.jar + +# Eclipse m2e generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,java,maven,eclipse + diff --git a/.mvn/jvm.config b/.mvn/jvm.config new file mode 100644 index 0000000..e69de29 diff --git a/.mvn/maven.config b/.mvn/maven.config new file mode 100644 index 0000000..e69de29 diff --git a/checkstyle.xml b/checkstyle.xml new file mode 100644 index 0000000..8108f76 --- /dev/null +++ b/checkstyle.xml @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pmd.xml b/pmd.xml new file mode 100644 index 0000000..f004da7 --- /dev/null +++ b/pmd.xml @@ -0,0 +1,60 @@ + + + + + + My custom rules + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..76c82f9 --- /dev/null +++ b/pom.xml @@ -0,0 +1,160 @@ + + 4.0.0 + de.hs_mannheim.pr2 + solutions + 1.0-SNAPSHOT + jar + + PR2 Excercises + + + UTF-8 + 21 + 21 + 5.12.2 + 1.12.2 + 7.13.0 + + + + jitpack.io + https://jitpack.io + + + + install + ${basedir}/target + ${project.artifactId}-${project.version} + + + maven-compiler-plugin + 3.10.1 + + + maven-surefire-plugin + 3.5.2 + + + maven-failsafe-plugin + 3.5.2 + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.6.0 + + + com.puppycrawl.tools + checkstyle + 10.4 + + + + checkstyle.xml + true + true + false + + + + validate + validate + + check + + + + + + org.apache.maven.plugins + maven-pmd-plugin + 3.26.0 + + + net.sourceforge.pmd + pmd-core + ${pmdVersion} + + + net.sourceforge.pmd + pmd-java + ${pmdVersion} + + + net.sourceforge.pmd + pmd-javascript + ${pmdVersion} + + + net.sourceforge.pmd + pmd-jsp + ${pmdVersion} + + + + + ./pmd.xml + + true + true + + + + + check + + + + + + + + + + com.github.thomsmits + game-framework + v1.0 + + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} + + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + + + org.junit.jupiter + junit-jupiter-params + ${junit.jupiter.version} + + + org.junit.platform + junit-platform-suite + ${junit.platform.version} + + + org.junit.vintage + junit-vintage-engine + ${junit.jupiter.version} + + + org.jfree + jfreechart + 1.5.3 + + + + + diff --git a/src/main/java/de/hs_mannheim/pr2/Skiplist.java b/src/main/java/de/hs_mannheim/pr2/Skiplist.java new file mode 100644 index 0000000..4ea28ef --- /dev/null +++ b/src/main/java/de/hs_mannheim/pr2/Skiplist.java @@ -0,0 +1,196 @@ +package de.hs_mannheim.pr2; + +import java.util.Comparator; +import java.util.Random; + +/** + * Hello world! + */ +public class Skiplist { + + Node head = null; + int size = 0; + int lvl = 1; + Comparator comparator = null; + Random rng = new Random(); + + int cpr(T x, T y) { + return comparator != null ? comparator.compare(x, y) : ((Comparable)x).compareTo(y); + } + + public Skiplist() { + comparator = null; + head = new Node(null, true); + } + + public Skiplist(Comparator comparator) { + this.comparator = comparator; + head = new Node(null, true); + } + + public int size() { + return size; + } + + public boolean empty() { + return size == 0; + } + + private void insertAtLvl(int lvl, Node oldNode) { + Node newNode = new Node(oldNode.value); + newNode.down = oldNode; + + if (this.lvl < lvl) { + throw new RuntimeException(); + } else if (this.lvl == lvl) { + Node newHead = new Node(null, true); + newHead.down = this.head; + this.head = newHead; + this.lvl += 1; + } + + if (rng.nextDouble() < 0.5) { + insertAtLvl(lvl + 1, newNode); + } + + Node currentNode = this.head; + for (int i = 0; i < this.lvl - lvl - 1; i++) { + currentNode = currentNode.down; + } + + while (true) { + if (currentNode.next == null || cpr(currentNode.next.value, newNode.value) > 0) { + newNode.next = currentNode.next; + currentNode.next = newNode; + return; + } + currentNode = currentNode.next; + } + } + + public void add(T data) { + Node node = new Node(data); + Node currentNode = head; + int counter = 0; + while (true) { + if (currentNode.next == null || cpr(currentNode.next.value, data) > 0) { + if (currentNode.down == null) { + node.next = currentNode.next; + currentNode.next = node; + break; + } else { + currentNode = currentNode.down; + } + } else { + currentNode = currentNode.next; + } + counter++; + } + size += 1; + if (rng.nextDouble() < 0.5) { + insertAtLvl(1, node); + } + System.out.println("adding took " + counter + " steps"); + } + + private void removeUpper(int lvl, Node node) { + Node currentNode = this.head; + for (int i = 0; i < this.lvl - lvl - 1; i++) { + currentNode = currentNode.down; + } + while (currentNode.next != null) { + if (currentNode.next.down == node) { + removeUpper(lvl + 1, currentNode.next); + currentNode.next = currentNode.next.next; + return; + } + currentNode = currentNode.next; + } + + } + + public T pop() { + if (size == 0) { + return null; + } + Node head = this.head; + while (head.down != null) { + head = head.down; + } + removeUpper(1, head.next); + T result = head.next.value; + head.next = head.next.next; + size -= 1; + return result; + } + + public T get(int location) { + if (location >= size) { + return null; + } + Node currentNode = head; + while (currentNode.down != null) { + currentNode = currentNode.down; + } + currentNode = currentNode.next; + + for (int i = 0; i < location; i++) { + currentNode = currentNode.next; + } + return currentNode.value; + } + + @Override + public String toString() { + Node currentHead = head; + StringBuilder result = new StringBuilder(); + while (currentHead != null) { + Node currentNode = currentHead; + while (currentNode != null) { + result.append(currentNode); + currentNode = currentNode.next; + } + currentHead = currentHead.down; + result.append("\n"); + } + return result.toString(); + } + + // @Override + // public String toString() { + // return head.toString(); + // } + + private class Node { + Node next = null; + Node down = null; + T value; + boolean dummy = false; + + Node(T value) { + this.value = value; + } + + Node(T value, Boolean dummy) { + this.dummy = true; + } + + @Override + public String toString() { + // String result = ""; + // if (this.down != null) { + // result += this.down.toString(); + // result += " --v\n"; + // } + // if (this.next != null) { + // result += this.next.toString(); + // } + if (dummy) { + return "[dummy]"; + } else { + return "[" + value + "]"; + } + // return result; + } + } +} diff --git a/src/test/java/de/hs_mannheim/pr2/SkiplistTest.java b/src/test/java/de/hs_mannheim/pr2/SkiplistTest.java new file mode 100644 index 0000000..5978e57 --- /dev/null +++ b/src/test/java/de/hs_mannheim/pr2/SkiplistTest.java @@ -0,0 +1,78 @@ +package de.hs_mannheim.pr2; + +import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +/** + * Unit test for simple App. + */ +public class SkiplistTest { + + /** + * Rigorous Test :-) + */ + @Test + public void shouldAnswerWithTrue() { + assertTrue(true); + } + + @Test + public void canPush() { + Skiplist list = new Skiplist(); + list.add(1); + list.add(3); + list.add(2); + list.add(4); + list.add(10); + list.add(7); + list.add(8); + list.add(6); + list.add(3); + System.out.println(list); + assertEquals(9, list.size()); + } + + @Test + public void canPop() { + Skiplist list = new Skiplist(); + list.add(1); + list.add(3); + list.add(2); + list.add(4); + list.add(10); + list.add(7); + list.add(8); + list.add(6); + list.add(3); + System.out.println(list); + assertEquals(1, list.pop().intValue()); + System.out.println(list); + assertEquals(2, list.pop().intValue()); + System.out.println(list); + assertEquals(3, list.pop().intValue()); + System.out.println(list); + assertEquals(3, list.pop().intValue()); + System.out.println(list); + assertEquals(4, list.pop().intValue()); + System.out.println(list); + assertEquals(6, list.pop().intValue()); + System.out.println(list); + assertTrue(list.size() == 3); + } + + @Test + public void canGet() { + Skiplist list = new Skiplist(); + list.add(1); + list.add(2); + list.add(3); + assertEquals(1, list.get(0).intValue()); + assertEquals(2, list.get(1).intValue()); + assertEquals(3, list.get(2).intValue()); + assertEquals(null, list.get(3)); + } + + +}