Skip to content

Яркова А.В., SkipList, гр.3530901/00006 #19

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
plugins {
id 'java'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories {
mavenCentral()
}

dependencies {
implementation 'org.jetbrains:annotations:16.0.2'
implementation 'junit:junit:4.13.1'
implementation 'org.testng:testng:7.1.0'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
}

test {
useTestNG()
}
Binary file added gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
6 changes: 6 additions & 0 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#Mon Aug 29 18:05:53 MSK 2022
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rootProject.name = 'algorithms-project-2022'
102 changes: 102 additions & 0 deletions src/main/java/Node.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;

public class Node<T>
{

static <R> void wire(@NotNull Node<R> from, @Nullable Node<R> to, int atLevel)
{
if (to == null)
{
from.childAtLevel.remove(atLevel);
}
else
{
// from -> to
if (from.childAtLevel.size() > atLevel)
from.childAtLevel.set(atLevel, to);
else
from.childAtLevel.add(atLevel, to);
// from <- to
if (to.parentAtLevel.size() > atLevel)
to.parentAtLevel.set(atLevel, from);
else
to.parentAtLevel.add(atLevel, from);
}
}

private final @NotNull ArrayList<Node<T>> childAtLevel;
private final @NotNull ArrayList<Node<T>> parentAtLevel;
private final @NotNull T key;

Node(@NotNull T key) {
this.key = key;
this.childAtLevel = new ArrayList<>();
this.parentAtLevel = new ArrayList<>();
}

@NotNull T key() {
return this.key;
}

@NotNull Node<T> next(int atLevel) {
return childAtLevel.get(atLevel);
}

@Nullable Node<T> child(int atLevel)
{
return (hasNext(atLevel)) ? next(atLevel) : null;
}

boolean hasNext(int atLevel)
{
return atLevel < childAtLevel.size();
}

boolean hasPrev(int atLevel)
{
return parentAtLevel.size() > atLevel;
}

@NotNull Node<T> prev(int atLevel)
{
return parentAtLevel.get(atLevel);
}

@Nullable Node<T> parent(int atLevel)
{
return (hasPrev(atLevel)) ? prev(atLevel) : null;
}

@NotNull Node<T> nextLowest() {
return next(0);
}

void connect(@NotNull Node<T> child, int atLevel)
{
if (atLevel > childAtLevel.size())
throw new RuntimeException("Semantic error: " + this + " to " + child + " at level " + atLevel);
final @Nullable Node<T> hisParent = child.parent(atLevel);
if (hisParent != null)
wire(hisParent, this, atLevel);
wire(this, child, atLevel);
}

int childLevelsSize()
{
return childAtLevel.size();
}

int parentLevelSize()
{
return parentAtLevel.size();
}

@Override
public String toString()
{
return key.toString();
}
}
245 changes: 245 additions & 0 deletions src/main/java/SkipList.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
import com.google.common.collect.Iterators;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.AbstractSet;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.SortedSet;
import java.util.Stack;
import java.util.TreeSet;

public class SkipList<T extends Comparable<T>> extends AbstractSet<T> implements SortedSet<T> {

private static Random entropy = new Random();

private static boolean heads() { return entropy.nextBoolean(); }

private int size;

// tail всегда null;
private @Nullable Node<T> head;

SkipList() { }

SkipList(T firstKey) {
this.head = new Node<>(firstKey);
}

void insert(T key)
{
final Node<T> born = new Node<>(key);
if (head == null) // so, no head?
head = born;
else
{
final @NotNull Stack<Node<T>> trace = new Stack<>();
final @Nullable Node<T> leftmost = leftmost(head, key, nOfLevels() - 1, trace);
if (leftmost == null) // new head
{
for (int level = 0; level < nOfLevels(); level++)
born.connect(head, level);
this.head = born;
}
else
{
trace.push(leftmost);
bubbleUp(born, trace);
}
}
size++;
}

private void bubbleUp(final @NotNull Node<T> node, final @NotNull Stack<Node<T>> trace)
{
int atLevel = 0;
do {
final Node<T> parent = (trace.empty()) ? head : trace.pop();
parent.connect(node, atLevel++);
} while (heads());
}

boolean delete(T key)
{
if (head == null)
return false;
if (equalTo(head.key(), key))
{
head = (head.hasNext(0)) ? head.child(0) : null;
size--;
return true;
}
final @Nullable Node<T> leftmost = leftmost(key);
if (leftmost == null || !equalTo(leftmost.key(), key))
return false;
for (int level = 0; level < leftmost.parentLevelSize(); level++)
Node.wire(leftmost.parent(level), leftmost.child(level), level);
size--;
return true;
}

List<T> keys()
{
final List<T> keys = new LinkedList<>();
Iterators.addAll(keys, iterator());
return keys;
}

boolean contains(T key)
{
Node<T> leftmost = leftmost(key);
return (leftmost != null) && (equalTo(leftmost.key(), key));
}

private @Nullable Node<T> leftmost(T key) {
return (head != null) ? leftmost(head, key, nOfLevels() - 1, null) : null;
}

// find closest to "key" element from the left. Null if key should become a new head.
private @Nullable Node<T> leftmost(@NotNull Node<T> current, T key, int atLevel,
@Nullable Stack<Node<T>> trace)
{
if (equalTo(current.key(), key))
return current;
else if (lessThan(current.key(), key))
{
// find first node >= key or reach the end of level
@NotNull Node<T> leftmostOnCurrentLevel = current;
while (leftmostOnCurrentLevel.hasNext(atLevel) && lessOrEqual(leftmostOnCurrentLevel.next(atLevel).key(), key))
leftmostOnCurrentLevel = leftmostOnCurrentLevel.next(atLevel);
return (atLevel > 0) ?
leftmost(leftmostOnCurrentLevel, key, atLevel - 1, push(leftmostOnCurrentLevel, trace)) :
leftmostOnCurrentLevel;
}
else // current > key
return null;
}

private Stack<Node<T>> push(@NotNull Node<T> node, @Nullable Stack<Node<T>> stack)
{
if (stack == null)
return null;
stack.push(node);
return stack;
}

private int nOfLevels() {
return (head == null) ? 0 :
(head.childLevelsSize() == 0) ? 1 :
head.childLevelsSize();
}

@NotNull
@Override
public Iterator<T> iterator() {
return new SkipIterator(0);
}

@Override
public int size() {
return this.size;
}

@Override
public Comparator<? super T> comparator() {
return Comparator.naturalOrder();
}

@NotNull
@Override
public SortedSet<T> subSet(T fromElement, T toElement) {
final TreeSet<T> result = new TreeSet<>();
iterator().forEachRemaining(result::add);
return result.subSet(fromElement, toElement);
}

@NotNull
@Override
public SortedSet<T> headSet(T toElement) {
final TreeSet<T> result = new TreeSet<>();
iterator().forEachRemaining(result::add);
return result.headSet(toElement);
}

@NotNull
@Override
public SortedSet<T> tailSet(T fromElement) {
final TreeSet<T> result = new TreeSet<>();
iterator().forEachRemaining(result::add);
return result.tailSet(fromElement);
}

@Override
public T first() {
if (head == null)
throw new NoSuchElementException();
return head.key();
}

@Override
public T last() {
return Iterators.getLast(iterator());
}

private class SkipIterator implements Iterator<T> {

private Node<T> current;
private int level;
private boolean firstTime = true;

SkipIterator(int level) {
this.current = head;
this.level = level;
}

@Override
public boolean hasNext()
{
return current.hasNext(level);
}

@Override
public T next()
{
if (firstTime)
{
firstTime = false;
return current.key();
}
current = current.next(level);
return current.key();
}
}

private boolean equalTo(T x, T y) {
return x.compareTo(y) == 0;
}

private boolean lessThan(T x, T y) {
return x.compareTo(y) < 0;
}

private boolean lessOrEqual(T x, T y)
{
return (lessThan(x, y) || equalTo(x, y));
}

@Override
public String toString()
{
final StringBuilder result = new StringBuilder();
for (int level = 0; level < nOfLevels(); level++)
{
final List<String> elementsAtLevel = new LinkedList<>();
new SkipIterator(level)
.forEachRemaining(el -> elementsAtLevel.add(el.toString()));
result.append(String.join(" <-> ", elementsAtLevel));
result.append("\n");
}
return result.toString();
}
}
Loading