feat: change to array of next nodes

main
Mark Beck 2025-11-18 09:29:05 +01:00
parent 17a471e3a0
commit ad1bc62a7c
2 changed files with 82 additions and 97 deletions

View File

@ -1,12 +1,12 @@
package de.hs_mannheim.pr2; package de.hs_mannheim.pr2;
import java.lang.reflect.Array;
import java.util.Comparator; import java.util.Comparator;
import java.util.Random; import java.util.Random;
/**
* Hello world!
*/
public class Skiplist<T> { public class Skiplist<T> {
private static final double PROBABILITY = 0.5;
private static final int MAX_LEVEL = 32;
Node head = null; Node head = null;
int size = 0; int size = 0;
@ -36,121 +36,89 @@ public class Skiplist<T> {
return size == 0; return size == 0;
} }
private void insertAtLvl(int lvl, Node oldNode) { private int randomLevel() {
Node newNode = new Node(oldNode.value); int level = 1;
newNode.down = oldNode; while (rng.nextDouble() < PROBABILITY && level < MAX_LEVEL) {
level++;
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;
} }
return level;
} }
public void add(T data) { public void add(T data) {
Node node = new Node(data); int level = randomLevel();
Node node = new Node(data, level);
Node currentNode = head; Node currentNode = head;
int counter = 0; int counter = 0;
while (true) {
if (currentNode.next == null || cpr(currentNode.next.value, data) > 0) { for (; level > 0; level--) {
if (currentNode.down == null) { while (currentNode.next[level-1] != null && cpr(currentNode.next[level-1].value, data) < 0) {
node.next = currentNode.next; currentNode = currentNode.next[level-1];
currentNode.next = node;
break;
} else {
currentNode = currentNode.down;
}
} else {
currentNode = currentNode.next;
}
counter++; counter++;
} }
size += 1; node.next[level-1] = currentNode.next[level-1];
if (rng.nextDouble() < 0.5) { currentNode.next[level-1] = node;
insertAtLvl(1, node);
} }
size += 1;
System.out.println("adding took " + counter + " steps"); System.out.println("adding took " + counter + " steps");
} }
private void removeUpper(int lvl, Node node) { private void remove(Node node) {
Node currentNode = this.head; int level = node.next.length;
for (int i = 0; i < this.lvl - lvl - 1; i++) { Node currentNode = head;
currentNode = currentNode.down; int counter = 0;
}
while (currentNode.next != null) {
if (currentNode.next.down == node) {
removeUpper(lvl + 1, currentNode.next);
currentNode.next = currentNode.next.next;
return;
}
currentNode = currentNode.next;
}
for (; level > 0; level--) {
while (currentNode.next[level-1] != null) {
if (currentNode.next[level-1] == node) {
currentNode.next[level-1] = node.next[level-1];
break;
}
currentNode = currentNode.next[level-1];
counter++;
}
}
size -= 1;
System.out.println("removing took " + counter + " steps");
} }
public T pop() { public T pop() {
if (size == 0) { if (size == 0) {
return null; return null;
} }
Node head = this.head;
while (head.down != null) { Node node = this.head.next[0];
head = head.down; remove(node);
} return node.value;
removeUpper(1, head.next);
T result = head.next.value;
head.next = head.next.next;
size -= 1;
return result;
} }
public T get(int location) { public boolean contains(T data) {
if (location >= size) {
return null;
}
Node currentNode = head; Node currentNode = head;
while (currentNode.down != null) { int counter = 0;
currentNode = currentNode.down;
}
currentNode = currentNode.next;
for (int i = 0; i < location; i++) { for (int level = MAX_LEVEL; level > 0; level--) {
currentNode = currentNode.next; while (currentNode.next[level-1] != null && cpr(currentNode.next[level-1].value, data) <= 0) {
if (currentNode.next[level-1].value.equals(data)) {
System.out.println("looking for took " + counter + " steps");
return true;
} }
return currentNode.value; currentNode = currentNode.next[level-1];
counter++;
}
}
System.out.println("looking for took " + counter + " steps");
return false;
} }
@Override @Override
public String toString() { public String toString() {
Node currentHead = head;
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
while (currentHead != null) { Node node = this.head;
Node currentNode = currentHead; for (int i = 0; i <= size; i++) {
while (currentNode != null) { result.append(String.format("%5s |", node.toString()));
result.append(currentNode); for (int j = 0; j < node.next.length; j++) {
currentNode = currentNode.next; result.append("#");
} }
currentHead = currentHead.down; node = node.next[0];
result.append("\n"); result.append("\n");
} }
return result.toString(); return result.toString();
@ -162,17 +130,20 @@ public class Skiplist<T> {
// } // }
private class Node { private class Node {
Node next = null; Node[] next;
Node down = null;
T value; T value;
boolean dummy = false; boolean dummy = false;
Node(T value) { @SuppressWarnings("unchecked")
Node(T value, int level) {
this.value = value; this.value = value;
this.next = (Node[]) Array.newInstance(Node.class, level);
} }
@SuppressWarnings("unchecked")
Node(T value, Boolean dummy) { Node(T value, Boolean dummy) {
this.dummy = true; this.dummy = true;
this.next = (Node[]) Array.newInstance(Node.class, MAX_LEVEL);
} }
@Override @Override

View File

@ -1,6 +1,7 @@
package de.hs_mannheim.pr2; package de.hs_mannheim.pr2;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -63,15 +64,28 @@ public class SkiplistTest {
} }
@Test @Test
public void canGet() { public void canContains() {
Skiplist<Integer> list = new Skiplist<Integer>(); Skiplist<Integer> list = new Skiplist<Integer>();
list.add(1); list.add(1);
list.add(2);
list.add(3); list.add(3);
assertEquals(1, list.get(0).intValue()); list.add(2);
assertEquals(2, list.get(1).intValue()); list.add(4);
assertEquals(3, list.get(2).intValue()); list.add(10);
assertEquals(null, list.get(3)); list.add(7);
list.add(8);
list.add(6);
list.add(3);
assertTrue(list.contains(1));
assertTrue(list.contains(2));
assertTrue(list.contains(3));
assertTrue(list.contains(4));
assertTrue(list.contains(6));
assertTrue(list.contains(7));
assertTrue(list.contains(8));
assertTrue(list.contains(10));
assertFalse(list.contains(5));
assertFalse(list.contains(9));
assertFalse(list.contains(11));
} }