feat: change to array of next nodes
parent
17a471e3a0
commit
ad1bc62a7c
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue