I am struggling to understand how to implement a remove(); for both a double and single linked class. I have figured out how to remove the first node in the double, but not in the single. First I would like to debug, problem solve the single linked class, then work on the double after that.
Here is the code I have so far for the Single Linked Class.
public class SingleLinkedClass<T> {
private Node <T> head;
private Node <T> tail;
private int size;
public SingleLinkedClass() {
size = 0;
head = null;
tail = null;
}
public void insertAtHead(T v)
{
//Allocate new node
Node newNode = new Node(v, head);
//Change head to point to new node
head = newNode;
if(tail == null)
{
tail = head;
}
//Increase size
size++;
}
public void insertAtTail(T v)
{
if(tail == null)
{
tail = new Node(v, null);
head = tail;
size++;
return;
}
Node newNode = new Node(v, null);
tail.nextNode = newNode;
tail = newNode;
size++;
}
public T removeHead()
{
if(head == null)
{
throw new IllegalStateException("list is empty! cannot delete");
}
T value = head.value;
head = head.nextNode;
size--;
return value;
}
public void removeTail()
{
//Case 1: list empty
if(head == null)
{
return;
}
//Case 2: list has one node
else if(head == tail)
{
head = tail = null;
}
else
{
Node temp = head;
while(temp.nextNode != tail)
{
temp = temp.nextNode;
}
tail = temp;
tail.nextNode = null;
}
size--;
}
public boolean remove(T v) {
Node<T> previous = head;
Node<T> cursor = head.nextNode;
if (head.nextNode == null) {
return false;
}
while(cursor != tail){
if (cursor.value.equals(v)) {
previous = cursor.nextNode;
return true;
}
previous = cursor;
cursor = cursor.nextNode;
}
return false;
}
public String toString() {
if (head == null) {
return "The list is Empty!";
}
String result = "";
Node temp = head;
while (temp != null) {
result += temp.toString() + " ";
temp = temp.nextNode;
}
return result;
}
public int size() {
return size;
}
private class Node <T> {
private T value;
private Node <T> nextNode;
public Node(T v, Node<T> n) {
value = v;
nextNode = n;
}
public String toString() {
return "" + value;
}
}
}
Here is my Double Linked Class
public class DoubelyLinkedList<E> {
private int size;
private Node<E> header;
private Node<E> trailer;
public DoubelyLinkedList() {
size = 0;
header = new Node<E>(null, null, null);
trailer = new Node<E>(null, null, header);
header.next = trailer;
}
public boolean remove(E v) {
//If the list is empty return false
if(header.next == trailer){
return false;
}
//If v is the head of the list remove and return true
Node <E> cursor = header.next;
for (int i = 0; i < size; i++) {
//Remove at Head
if(cursor.value.equals(v)){
removeAtHead();
}
cursor = cursor.next;
}
return true;
}
/*
} */
public void insertAtHead(E v) {
insertBetween(v, header, header.next);
}
public void insertAtTail(E v) {
insertBetween(v, trailer.prev, trailer);
}
private void insertBetween(E v, Node<E> first, Node<E> second) {
Node<E> newNode = new Node<>(v, second, first);
first.next = newNode;
second.prev = newNode;
size++;
}
public E removeAtHead() {
return removeBetween(header, header.next.next);
}
public E removeAtTail() {
return removeBetween(trailer.prev.prev, trailer);
}
private E removeBetween(Node<E> first, Node<E> second) {
if (header.next == trailer)// if the list is empty
{
throw new IllegalStateException("The list is empty!");
}
E result = first.next.value;
first.next = second;
second.prev = first;
size--;
return result;
}
public String toStringBackward() {
if (size == 0) {
return "The list is empty!";
}
String r = "";
Node<E> temp = trailer.prev;
while (temp != header) {
r += temp.toString() + " ";
temp = temp.prev;
}
return r;
}
public String toString() {
if (size == 0) {
return "The list is empty!";
}
String r = "";
Node<E> temp = header.next;
while (temp != trailer) {
r += temp + " ";
temp = temp.next;
}
return r;
}
private static class Node<T> {
private T value;
private Node<T> next;
private Node<T> prev;
public Node(T v, Node<T> n, Node<T> p) {
value = v;
next = n;
prev = p;
}
public String toString() {
return value.toString();
}
}
}
Here is my Driver
public class Driver {
public static void main(String[] args) {
DoubelyLinkedList<String> doubley = new DoubelyLinkedList();
SingleLinkedClass<String> single = new SingleLinkedClass();
single.insertAtHead("Bob");
single.insertAtHead("Sam");
single.insertAtHead("Terry");
single.insertAtHead("Don");
System.out.println(single);
single.remove("Bob");
System.out.println("Single Remove Head: " + single);
/*
single.remove("Don");
System.out.println("Single Remove Tail: " + single);
single.remove("Terry");
System.out.println("Single Remove Inbetween: " + single);
*/
System.out.println();
System.out.println();
doubley.insertAtHead("Bob");
doubley.insertAtHead("Sam");
doubley.insertAtHead("Terry");
doubley.insertAtHead("Don");
System.out.println(doubley);
doubley.remove("Bob");
System.out.println("Double Remove Head: " + doubley);
doubley.remove("Don");
System.out.println("Double Remove Tail: " + doubley);
/*
doubley.remove("Sam");
System.out.println("Double Remove Inbetween: " + doubley);
*/
}
}
In the removeHead moving head to its next, it might become null. Then tail was the head too. Then tail should be set to null too.
DoublyLinkedList is better English than DoubelyLinkedList.
As this is homework, I leave it by this.
Hello I implemented a multiset using a linkedlist and I want to implement the multiset using sorted linkedlist. This is multiset abstract class.
import java.io.PrintStream;
public abstract class Multiset<T> {
/**
* Delimiter string for print operation.
*/
protected static final String printDelim = " | ";
public abstract void add(T item);
public abstract int search(T item);
public abstract void removeOne(T item);
public abstract void removeAll(T item);
public abstract void print(PrintStream out);
}
This is my implementation of linkedlist.
import java.io.PrintStream;
public class LinkedListMultiset<T> extends Multiset<T> {
protected Node mHead;
protected int mLength;
public LinkedListMultiset() {
// Implement me!
mHead = null;
mLength = 0;
}
public void add(T item) {
Node newNode = new Node((String) item);
if (mHead == null)
mHead = newNode;
else {
Node currNode = mHead;
Node parentNode = null;
while (currNode != null) {
if (currNode.getValue().
equals(newNode.getValue())) {
currNode.addCounter();
return;
}
parentNode = currNode;
currNode = currNode.getNext();
}
parentNode.setNext(newNode);
}
mLength++;
}
public int search(T item) {
Node currNode = mHead;
while (currNode != null) {
if (currNode.getValue().equals((String) item)) {
return currNode.getCounter();
}
currNode = currNode.getNext();
}
return 0;
}
public void removeOne(T item) {
Node currNode = mHead;
Node lastNode = null;
while (currNode != null) {
if (currNode.getValue().equals((String) item)) {
currNode.minusCounter();
if (currNode.getCounter() == 0) {
if (currNode == mHead)
mHead = currNode.getNext();
else
lastNode.setNext
(currNode.getNext());
mLength--;
}
return;
}
lastNode = currNode;
currNode = currNode.getNext();
}
}
public void removeAll(T item) {
Node currNode = mHead;
Node lastNode = null;
while (currNode != null) {
if (currNode.getValue().equals((String) item)) {
if (currNode == mHead)
mHead = currNode.getNext();
else
lastNode.setNext(currNode.getNext());
mLength--;
return;
}
lastNode = currNode;
currNode = currNode.getNext();
}
}
public void print(PrintStream out) {
Node currNode = mHead;
while (currNode != null) {
out.printf("%s | %d\n", currNode.getValue()
, currNode.getCounter());
currNode = currNode.getNext();
}
}
private class Node {
protected String mValue;
protected Node mNext;
int counter;
public Node(String value) {
mValue = value;
mNext = null;
counter = 1;
}
public void addCounter() {
counter++;
}
public void minusCounter() {
counter--;
}
public int getCounter() {
return counter;
}
public String getValue() {
return mValue;
}
public Node getNext() {
return mNext;
}
public void setValue(String value) {
mValue = value;
}
public void setNext(Node next) {
mNext = next;
}
}
}
I want to implement sorted linkedlist but I want to change my code as minimum as possible.
This is my user class and i found that i have to use the compareTo method but i need a method which adding in a Rb list.
There is an already existed add method and i have make a similar which order the users alphabetically.
import java.lang.Comparable;
public class LaptopUser implements Comparable<LaptopUser>
{
private String username;
private String password;
public LaptopUser(String username,String password)
{
this.username=username;
this.password=password;
}
public String getUsername(){
return username ;
}
public String getPass()
{
return password;
}
public String toString(){
return(username+","+password);
}
#Override
public int compareTo(LaptopUser n)
{
if(this.toString().compareTo(n.toString())>0)
{
return 1;
}
else if(this.toString().compareTo(n.toString())<0)
{
return -1;
}
return 0;
}
public boolean equals(LaptopUser p)
{
return(this.toString().equals(p.toString()));
}
}
public class ReferenceBasedList implements ListInterface
{
private ListNode head;
private ListNode tail;
int numItems;
public ReferenceBasedList()
{
head = tail = null;
numItems = 0;
}
public int size()
{
return numItems;
}
public boolean isEmpty()
{
return (numItems == 0);
}
public void removeAll()
{
head = tail = null;
numItems = 0;
}
private ListNode find(int index)
{
ListNode curr = head;
for (int skip = 1; skip < index; skip++)
curr = curr.getNext();
return curr;
}
public Object get(int index)
throws ListIndexOutOfBoundsException
{
if (index >= 1 && index <= numItems)
{
ListNode curr = find(index);
return curr.getItem();
}
else
{
throw new ListIndexOutOfBoundsException(
"List index out of bounds exception on get");
}
}
public void add(int index, Object newDataItem)
throws ListIndexOutOfBoundsException
{
if (index >= 1 && index <= numItems+1)
{
if ( index == 1 )
{
ListNode newNode = new ListNode(newDataItem, head);
head = newNode;
if (tail==null)
tail = head;
}
else if ( index==numItems+1 )
{
ListNode newNode = new ListNode(newDataItem);
tail.setNext(newNode);
tail = newNode;
}
else
{
ListNode prev = find(index-1);
ListNode newNode = new ListNode(newDataItem, prev.getNext());
prev.setNext(newNode);
}
numItems++;
}
else
{
throw new ListIndexOutOfBoundsException(
"List index out of bounds exception on add");
}
}
public void insert(Object newDataItem)
{
this.add(1,newDataItem);
}
public void append(Object newDataItem)
{
this.add(numItems+1,newDataItem);
}
public Object showFront()
{
return this.get(1);
}
public Object showLast()
{
return this.get(numItems);
}
public void remove(int index)
throws ListIndexOutOfBoundsException
{
if (index >= 1 && index <= numItems)
{
if (index == 1)
{
head = head.getNext();
if (head == null)
tail = null;
}
else
{
ListNode prev = find(index-1);
ListNode curr = prev.getNext();
prev.setNext(curr.getNext());
if (index == numItems)
tail = prev;
}
numItems--;
}
else
{
throw new ListIndexOutOfBoundsException(
"List index out of bounds exception on remove");
}
}
public boolean exists(Object dataItem)
{
for (ListNode tmp=head; tmp!=null; tmp=tmp.getNext())
if (tmp.getItem().equals(dataItem))
return true;
return false;
}
public Object removeLast() throws ListException
{
if (isEmpty())
throw new ListException("The linked list is empty");
else
{
Object lastDataItem = tail.getItem();
if (head == tail)
head = tail = null;
else
{
ListNode tmp = head;
while (tmp.getNext().getNext() != null)
tmp = tmp.getNext();
tail = tmp;
tail.setNext(null);
}
numItems--;
return lastDataItem;
}
}
public Object removeFront() throws ListException
{
if (isEmpty())
throw new ListException("The linked list is empty");
else
{
Object frontDataItem = head.getItem();
head = head.getNext();
if (head == null)
tail = null;
numItems--;
return frontDataItem;
}
}
}
You can use the Collections.binarySearch method to find at what index a LaptopUser should be added to a List in order for it to be alphabetically ordered.
SortedList:
public class SortedList implements Iterable<LaptopUser> {
public List<LaptopUser> users = new ArrayList<LaptopUser>();
public void add(LaptopUser user) {
int index = Collections.binarySearch(users, user);
if (index < 0)
users.add(-index - 1, user);
else
users.add(index, user);
}
#Override
public Iterator<LaptopUser> iterator() {
return users.iterator();
}
Example Code:
public class LaptopUser implements Comparable<LaptopUser> {
public String username;
public String password;
public LaptopUser(String username, String password) {
this.username = username;
this.password = password;
}
#Override
public int compareTo(LaptopUser o) {
return toString().compareTo(o.toString());
}
#Override
public String toString() {
return username.concat(password);
}
}
public Sorted() {
LaptopUser a =new LaptopUser("a", "password");
LaptopUser b =new LaptopUser("b", "password");
LaptopUser c =new LaptopUser("c", "password");
SortedList list = new SortedList();
list.add(c);
list.add(a);
list.add(b);
for(LaptopUser user : list)
System.out.println(user);
}
public static void main(String[] args) {
new Sorted();
}
Output:
apassword
bpassword
cpassword
public class LinkedList
{
private Node head;
private Node tail;
private int numberOfElements;
public LinkedList()
{
head = null;
tail = null;
this.numberOfElements = 0;
}
public int length()
{
return this.numberOfElements;
}
public void removeFront()
{
Node currNode = head;
head = head.getNextNode();
currNode.setNextNode(null);
this.numberOfElements--;
}
public void removeLast()
{
this.tail = this.tail.prev;
}
public void removeAtIndex(int index) throws AmishException
{
if (index == 0) {
Node q = head;
head = q.getNextNode();
}
else if ((index > numberOfElements - 1) || (index < 0))
System.out.println("Index out bounds.");
else {
Node currNode = head;
for (int i = 0; i < index; i++) {
currNode = currNode.getNextNode();
}
Node temp = currNode;
currNode = temp.getPrevNode();
currNode.setNextNode(temp.getNextNode());
temp = null;
numberOfElements--;
}
}
Node -
public class Node
{
private int payload;
private Node nextNode;
public Node prev;
public Node previous;
public Node next;
public Node(int payload)
{
this.payload = payload;
nextNode = null;
}
public Node getNextNode()
{
return this.nextNode;
}
public Node getPrevNode()
{
return this.getPrevNode();
}
public void setNextNode(Node n)
{
this.nextNode = n;
}
public void display()
{
System.out.print("(" + super.toString() + " : " + this.payload + ")");
if(this.nextNode != null)
{
System.out.print(" -> ");
this.nextNode.display();
}
else
{
System.out.println("");
}
}
public String toString()
{
return "" + super.toString() + " : " + this.payload;
}
public void setPrevNode(Node n)
{
previous = n;
}
}
Driver -
public class Driver
{
public static void main(String[] args) throws Exception
{
LinkedList ll = new LinkedList();
ll.addFront(7);
ll.addFront(5);
ll.addEnd(13);
ll.addEnd(27);
ll.addFront(2);
ll.addAtIndex(1, 0);
ll.addAtIndex(12, 6);
ll.addAtIndex(9, 2);
ll.addAtIndex(11, 2);
//ll.removeFront();
//ll.removeLast();
ll.removeAtIndex(1);
for(int i = 0; i < ll.length(); i++)
{
System.out.println(ll.get(i));
}
}
}
I got what I need to remove the head's index, but how to do anything else is beyond me.
I have the methods to remove the head and the tail now I just need to know how to remove at an index just Like if I were to add at an index.
Okay, completely editing this answer. I took your code and went from that. There were some issues with your Node class, check out mine. I created a barebones Node class, add the any other functionality you may need/want. For the LinkedList class, I created a simple add method that adds to the end of the list. Use this as a prototype for your other adds. Everything right now is working and I put some println's to help you see where the program is at. I highly recommend using a debugger. Also note that this is a doubly linked list.
Linked List
public class LinkedList {
private Node head;
private Node tail;
private int numberOfElements;
public LinkedList()
{
head = null;
tail = null;
numberOfElements = 0;
}
public int length()
{
return numberOfElements;
}
public void removeAtIndex(int index)
{
if (index == 0) {
Node q = head;
head = q.getNextNode();
numberOfElements--;
}
else if ((index > numberOfElements - 1) || (index < 0))
System.out.println("Index out of bounds.");
else {
Node currNode = head;
for (int i = 0; i < index; i++) {
//Node p = currNode;
System.out.println("At this payload " + currNode.getPayload());
currNode = currNode.getNextNode();
System.out.println("Now at this payload " + currNode.getPayload());
}
Node temp = currNode;
System.out.println("Removing the node with payload " + temp.getPayload());
currNode = temp.getPrevNode();
currNode.setNextNode(temp.getNextNode());
temp = null;
numberOfElements--;
}
}
public void add(int num) {
Node newNode = new Node(num);
newNode.setNextNode(null);
if (numberOfElements == 0) {
newNode.setPrevNode(null);
head = newNode;
tail = newNode;
}
else if (numberOfElements == 1) {
head.setNextNode(newNode);
tail = newNode;
tail.setPrevNode(head);
}
else {
newNode.setPrevNode(tail);
tail.setNextNode(newNode);
tail = newNode;
}
System.out.println("Inserted " + num + " into the linked list");
numberOfElements++;
}
public void printList() {
Node temp = head;
while (temp != null) {
System.out.println("Node with payload " + temp.getPayload());
temp = temp.getNextNode();
}
}
}
Node
public class Node {
private int payload;
private Node next;
private Node prev;
public Node(int payload) {
this.payload = payload;
prev = null;
next = null;
}
public Node getNextNode() {
return next;
}
public Node getPrevNode() {
return prev;
}
public void setNextNode(Node n) {
next = n;
}
public void setPrevNode(Node n) {
prev = n;
}
public int getPayload() {
return payload;
}
}
Driver
public class Driver {
public static void main(String[] args) {
LinkedList ll = new LinkedList();
ll.add(7);
ll.add(5);
ll.add(13);
ll.add(27);
ll.add(2);
ll.printList();
ll.removeAtIndex(3);
ll.printList();
}
}
I find ConcurrentSkipListSet in Java Collection Framework, which is backed up with a skip list. But is there a skip list in Java? A set does not work in my use case. I need a indexable list that supports duplicates.
This answer is 3 years late but I hope it will be useful for those wanting a Java skip list from this moment on :)
This solution allows duplicates as you asked. I follow roughly the guide here http://igoro.com/archive/skip-lists-are-fascinating, so the complexities are similar to that, except delete costs O(nlogn) - as I didn't bother using doubly-linked nodes, I imagine doing so would bring delete down to O(logn).
Code comprises of: an interface, the skip list implementing the interface, and the node class. It is also generic.
You can tune the parameter LEVELS for performance, but remember the space-time tradeoff.
import java.util.Random;
interface SkippableList<T extends Comparable<? super T>> {
int LEVELS = 5;
boolean delete(T target);
void print();
void insert(T data);
SkipNode<T> search(T data);
}
public class SkipList<T extends Comparable<? super T>> implements SkippableList<T> {
public static void main(String[] args) {
SkipList<Integer> sl = new SkipList<>();
int[] data = {4,2,7,0,9,1,3,7,3,4,5,6,0,2,8};
for (int i : data) {
sl.insert(i);
}
sl.print();
sl.search(4);
sl.delete(9);
sl.print();
sl.insert(69);
sl.print();
sl.search(69);
}
private final SkipNode<T> head = new SkipNode<>(null);
private final Random rand = new Random();
#Override
public void insert(T data) {
SkipNode<T> SkipNode = new SkipNode<>(data);
for (int i = 0; i < LEVELS; i++) {
if (rand.nextInt((int) Math.pow(2, i)) == 0) { //insert with prob = 1/(2^i)
insert(SkipNode, i);
}
}
}
#Override
public boolean delete(T target) {
System.out.println("Deleting " + target.toString());
SkipNode<T> victim = search(target, false);
if (victim == null) return false;
victim.data = null;
for (int i = 0; i < LEVELS; i++) {
head.refreshAfterDelete(i);
}
System.out.println();
return true;
}
#Override
public SkipNode<T> search(T data) {
return search(data, true);
}
#Override
public void print() {
for (int i = 0; i < LEVELS; i++) {
head.print(i);
}
System.out.println();
}
private void insert(SkipNode<T> SkipNode, int level) {
head.insert(SkipNode, level);
}
private SkipNode<T> search(T data, boolean print) {
SkipNode<T> result = null;
for (int i = LEVELS-1; i >= 0; i--) {
if ((result = head.search(data, i, print)) != null) {
if (print) {
System.out.println("Found " + data.toString() + " at level " + i + ", so stoppped" );
System.out.println();
}
break;
}
}
return result;
}
}
class SkipNode<N extends Comparable<? super N>> {
N data;
#SuppressWarnings("unchecked")
SkipNode<N>[] next = (SkipNode<N>[]) new SkipNode[SkippableList.LEVELS];
SkipNode(N data) {
this.data = data;
}
void refreshAfterDelete(int level) {
SkipNode<N> current = this.getNext(level);
while (current != null && current.getNext(level) != null) {
if (current.getNext(level).data == null) {
SkipNode<N> successor = current.getNext(level).getNext(level);
current.setNext(successor, level);
return;
}
current = current.getNext(level);
}
}
void setNext(SkipNode<N> next, int level) {
this.next[level] = next;
}
SkipNode<N> getNext(int level) {
return this.next[level];
}
SkipNode<N> search(N data, int level, boolean print) {
if (print) {
System.out.print("Searching for: " + data + " at ");
print(level);
}
SkipNode<N> result = null;
SkipNode<N> current = this.getNext(level);
while (current != null && current.data.compareTo(data) < 1) {
if (current.data.equals(data)) {
result = current;
break;
}
current = current.getNext(level);
}
return result;
}
void insert(SkipNode<N> SkipNode, int level) {
SkipNode<N> current = this.getNext(level);
if (current == null) {
this.setNext(SkipNode, level);
return;
}
if (SkipNode.data.compareTo(current.data) < 1) {
this.setNext(SkipNode, level);
SkipNode.setNext(current, level);
return;
}
while (current.getNext(level) != null && current.data.compareTo(SkipNode.data) < 1 &&
current.getNext(level).data.compareTo(SkipNode.data) < 1) {
current = current.getNext(level);
}
SkipNode<N> successor = current.getNext(level);
current.setNext(SkipNode, level);
SkipNode.setNext(successor, level);
}
void print(int level) {
System.out.print("level " + level + ": [");
int length = 0;
SkipNode<N> current = this.getNext(level);
while (current != null) {
length++;
System.out.print(current.data.toString() + " ");
current = current.getNext(level);
}
System.out.println("], length: " + length);
}
}
Fixed the bug in the implementation provided by #PoweredByRice. It threw an NPE for cases when the node deleted was the first node. Other updates include renamed variable names and reverse printing the order of the skip list.
import java.util.Random;
interface SkippableList<T extends Comparable<? super T>> {
int LEVELS = 5;
boolean delete(T target);
void print();
void insert(T data);
SkipNode<T> search(T data);
}
class SkipNode<N extends Comparable<? super N>> {
N data;
#SuppressWarnings("unchecked")
SkipNode<N>[] next = (SkipNode<N>[]) new SkipNode[SkippableList.LEVELS];
SkipNode(N data) {
this.data = data;
}
void refreshAfterDelete(int level) {
SkipNode<N> current = this;
while (current != null && current.getNext(level) != null) {
if (current.getNext(level).data == null) {
SkipNode<N> successor = current.getNext(level).getNext(level);
current.setNext(successor, level);
return;
}
current = current.getNext(level);
}
}
void setNext(SkipNode<N> next, int level) {
this.next[level] = next;
}
SkipNode<N> getNext(int level) {
return this.next[level];
}
SkipNode<N> search(N data, int level, boolean print) {
if (print) {
System.out.print("Searching for: " + data + " at ");
print(level);
}
SkipNode<N> result = null;
SkipNode<N> current = this.getNext(level);
while (current != null && current.data.compareTo(data) < 1) {
if (current.data.equals(data)) {
result = current;
break;
}
current = current.getNext(level);
}
return result;
}
void insert(SkipNode<N> skipNode, int level) {
SkipNode<N> current = this.getNext(level);
if (current == null) {
this.setNext(skipNode, level);
return;
}
if (skipNode.data.compareTo(current.data) < 1) {
this.setNext(skipNode, level);
skipNode.setNext(current, level);
return;
}
while (current.getNext(level) != null && current.data.compareTo(skipNode.data) < 1 &&
current.getNext(level).data.compareTo(skipNode.data) < 1) {
current = current.getNext(level);
}
SkipNode<N> successor = current.getNext(level);
current.setNext(skipNode, level);
skipNode.setNext(successor, level);
}
void print(int level) {
System.out.print("level " + level + ": [ ");
int length = 0;
SkipNode<N> current = this.getNext(level);
while (current != null) {
length++;
System.out.print(current.data + " ");
current = current.getNext(level);
}
System.out.println("], length: " + length);
}
}
public class SkipList<T extends Comparable<? super T>> implements SkippableList<T> {
private final SkipNode<T> head = new SkipNode<>(null);
private final Random rand = new Random();
#Override
public void insert(T data) {
SkipNode<T> skipNode = new SkipNode<>(data);
for (int i = 0; i < LEVELS; i++) {
if (rand.nextInt((int) Math.pow(2, i)) == 0) {
//insert with prob = 1/(2^i)
insert(skipNode, i);
}
}
}
#Override
public boolean delete(T target) {
System.out.println("Deleting " + target);
SkipNode<T> victim = search(target, true);
if (victim == null) return false;
victim.data = null;
for (int i = 0; i < LEVELS; i++) {
head.refreshAfterDelete(i);
}
System.out.println("deleted...");
return true;
}
#Override
public SkipNode<T> search(T data) {
return search(data, true);
}
#Override
public void print() {
for (int i = LEVELS-1; i >= 0 ; i--) {
head.print(i);
}
System.out.println();
}
private void insert(SkipNode<T> SkipNode, int level) {
head.insert(SkipNode, level);
}
private SkipNode<T> search(T data, boolean print) {
SkipNode<T> result = null;
for (int i = LEVELS-1; i >= 0; i--) {
if ((result = head.search(data, i, print)) != null) {
if (print) {
System.out.println("Found " + data.toString() + " at level " + i + ", so stopped" );
System.out.println();
}
break;
}
}
return result;
}
public static void main(String[] args) {
SkipList<Integer> sl = new SkipList<>();
int[] data = {4,2,7,0,9,1,3,7,3,4,5,6,0,2,8};
for (int i : data) {
sl.insert(i);
}
sl.print();
sl.search(4);
sl.delete(4);
System.out.println("Inserting 10");
sl.insert(10);
sl.print();
sl.search(10);
}
}
Since you've mentioned a List that is both Indexable (I assume you want speedy retrieval) and need to allow duplicates, I would advise you go for a custom Set with a LinkedList or ArrayList perhaps.
You need to have a base Set, an HashSet for example and keep adding values to it. If you face a duplicate, the value of that Set should point to a List. So, that you will have both Speedy retrieval and of course you will store your objects in a psuedo Collection manner.
This should give you good efficiency for retrieval. Ideally if your Keys are not duplicates, you will achieve an O(1) as the retrieval speed.
When you create a ConcurrentSkipListSet, you pass a comparator to the constructor.
new ConcurrentSkipListSet<>(new ExampleComparator());
public class ExampleComparator implements Comparator<Event> {//your impl }
You could create a comparator that will make your SkipListSet behave as a normal List.
You can make use the below to code make your own basic skiplist :
1)Make start and end to represent start and end of skip list.
2)Add the nodes and assign pointers to next based on
if(node is even)
then ,assign a fast lane pointer with next pointer
else
assign only pointer to next node
Java code for basic skip list (you can add more features if you want):
public class MyClass {
public static void main(String args[]) {
Skiplist skiplist=new Skiplist();
Node n1=new Node();
Node n2=new Node();
Node n3=new Node();
Node n4=new Node();
Node n5=new Node();
Node n6=new Node();
n1.setData(1);
n2.setData(2);
n3.setData(3);
n4.setData(4);
n5.setData(5);
n6.setData(6);
skiplist.insert(n1);
skiplist.insert(n2);
skiplist.insert(n3);
skiplist.insert(n4);
skiplist.insert(n5);
skiplist.insert(n6);
/*print all nodes*/
skiplist.display();
System.out.println();
/* print only fast lane node*/
skiplist.displayFast();
}
}
class Node{
private int data;
private Node one_next; //contain pointer to next node
private Node two_next; //pointer to node after the very next node
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public Node getOne_next() {
return one_next;
}
public void setOne_next(Node one_next) {
this.one_next = one_next;
}
public Node getTwo_next() {
return two_next;
}
public void setTwo_next(Node two_next) {
this.two_next = two_next;
}
}
class Skiplist{
Node start; //start pointer to skip list
Node head;
Node temp_next; //pointer to store last used fast lane node
Node end; //end of skip list
int length;
public Skiplist(){
start=new Node();
end=new Node();
length=0;
temp_next=start;
}
public void insert(Node node){
/*if skip list is empty */
if(length==0){
start.setOne_next(node);
node.setOne_next(end);
temp_next.setTwo_next(end);
head=start;
length++;
}
else{
length++;
Node temp=start.getOne_next();
Node prev=start;
while(temp != end){
prev=temp;
temp=temp.getOne_next();
}
/*add a fast lane pointer for even no of nodes*/
if(length%2==0){
prev.setOne_next(node);
node.setOne_next(end);
temp_next.setTwo_next(node);
temp_next=node;
node.setTwo_next(end);
}
/*odd no of node will not contain fast lane pointer*/
else{
prev.setOne_next(node);
node.setOne_next(end);
}
}
}
public void display(){
System.out.println("--Simple Traversal--");
Node temp=start.getOne_next();
while(temp != end){
System.out.print(temp.getData()+"=>");
temp=temp.getOne_next();
}
}
public void displayFast(){
System.out.println("--Fast Lane Traversal--");
Node temp=start.getTwo_next();
while(temp !=end){
System.out.print(temp.getData()+"==>");
temp=temp.getTwo_next();
}
}
}
Output:
--Simple Traversal--
1=>2=>3=>4=>5=>6=>
--Fast Lane Traversal--
2==>4==>6==>
I approve to use TreeList from apache-collections and decorate it with SortedList from Happy Java Libraries
https://sourceforge.net/p/happy-guys/wiki/Sorted%20List/
I am not claiming that this is my own implementation. I just cannot remember where I found it. If you know let me know and I will update. This has been working quite well for me:
public class SkipList<T extends Comparable<? super T>> implements Iterable<T> {
Node<T> _head = new Node<>(null, 33);
private final Random rand = new Random();
private int _levels = 1;
private AtomicInteger size = new AtomicInteger(0);
/// <summary>
/// Inserts a value into the skip list.
/// </summary>
public void insert(T value) {
// Determine the level of the new node. Generate a random number R. The
// number of
// 1-bits before we encounter the first 0-bit is the level of the node.
// Since R is
// 32-bit, the level can be at most 32.
int level = 0;
size.incrementAndGet();
for (int R = rand.nextInt(); (R & 1) == 1; R >>= 1) {
level++;
if (level == _levels) {
_levels++;
break;
}
}
// Insert this node into the skip list
Node<T> newNode = new Node<>(value, level + 1);
Node<T> cur = _head;
for (int i = _levels - 1; i >= 0; i--) {
for (; cur.next[i] != null; cur = cur.next[i]) {
if (cur.next[i].getValue().compareTo(value) > 0)
break;
}
if (i <= level) {
newNode.next[i] = cur.next[i];
cur.next[i] = newNode;
}
}
}
/// <summary>
/// Returns whether a particular value already exists in the skip list
/// </summary>
public boolean contains(T value) {
Node<T> cur = _head;
for (int i = _levels - 1; i >= 0; i--) {
for (; cur.next[i] != null; cur = cur.next[i]) {
if (cur.next[i].getValue().compareTo(value) > 0)
break;
if (cur.next[i].getValue().compareTo(value) == 0)
return true;
}
}
return false;
}
/// <summary>
/// Attempts to remove one occurence of a particular value from the skip
/// list. Returns
/// whether the value was found in the skip list.
/// </summary>
public boolean remove(T value) {
Node<T> cur = _head;
boolean found = false;
for (int i = _levels - 1; i >= 0; i--) {
for (; cur.next[i] != null; cur = cur.next[i]) {
if (cur.next[i].getValue().compareTo(value) == 0) {
found = true;
cur.next[i] = cur.next[i].next[i];
break;
}
if (cur.next[i].getValue().compareTo(value) > 0)
break;
}
}
if (found)
size.decrementAndGet();
return found;
}
#SuppressWarnings({ "rawtypes", "unchecked" })
#Override
public Iterator<T> iterator() {
return new SkipListIterator(this, 0);
}
public int size() {
return size.get();
}
public Double[] toArray() {
Double[] a = new Double[size.get()];
int i = 0;
for (T t : this) {
a[i] = (Double) t;
i++;
}
return a;
}
}
class Node<N extends Comparable<? super N>> {
public Node<N>[] next;
public N value;
#SuppressWarnings("unchecked")
public Node(N value, int level) {
this.value = value;
next = new Node[level];
}
public N getValue() {
return value;
}
public Node<N>[] getNext() {
return next;
}
public Node<N> getNext(int level) {
return next[level];
}
public void setNext(Node<N>[] next) {
this.next = next;
}
}
class SkipListIterator<E extends Comparable<E>> implements Iterator<E> {
SkipList<E> list;
Node<E> current;
int level;
public SkipListIterator(SkipList<E> list, int level) {
this.list = list;
this.current = list._head;
this.level = level;
}
public boolean hasNext() {
return current.getNext(level) != null;
}
public E next() {
current = current.getNext(level);
return current.getValue();
}
public void remove() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
}