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

View File

@ -1,6 +1,7 @@
package de.hs_mannheim.pr2;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
@ -63,15 +64,28 @@ public class SkiplistTest {
}
@Test
public void canGet() {
public void canContains() {
Skiplist<Integer> list = new Skiplist<Integer>();
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));
list.add(2);
list.add(4);
list.add(10);
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));
}