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