Related
I have been running this code and it seems like it times out. I'm not sure how to fix it as it doesn't show me an actual error message or anything like that. The first block of code is the class that the methods in the demo are coming from, and it seems like all the methods that are being called for stringList are just not working. When I test the same thing with an int list it works fine.
public class DoublyLinkedList<E> {
private static class Node<E> {
// Node Fields
private E element; //data
private Node<E> prev; //previous Node
private Node<E> next; //next Node
// Node Constructor
public Node(E e, Node<E> p, Node<E> n) {
this.element = e;
this.prev = p;
this.next = n;
}
// Node Methods
public E getElement() {
return element;
}
public Node<E> getPrev() {
return this.prev;
}
public Node<E> getNext() {
return this.next;
}
public void setPrev(Node<E> p) {
this.prev = p;
}
public void setNext(Node<E> n) {
this.next = n;
}
}
// DLinkedList Fields
private Node<E> header;
private Node<E> trailer;
int size;
// DLinkedList Constructor
public DoublyLinkedList() {
this.header = new Node<>(null, null, null);
this.trailer = new Node<>(null, this.header, null);
this.header.setNext(this.trailer);
}
// DLinkedList Methods
public int size() {
return this.size;
}
public E first() {
if (isEmpty()) {
return null;
}
return this.header.next.getElement();
}
public E last () {
if (isEmpty()) {
return null;
}
return this.trailer.prev.getElement();
}
public boolean isEmpty() {
return size == 0;
}
public void addFirst (E e) {
addBetween(e, this.header, this.header.getNext());
}
public void addLast (E e) {
addBetween(e, this.trailer.getPrev(), this.trailer);
}
private void addBetween(E e, Node<E> predecessor, Node<E> successor) {
Node<E> newest = new Node<>(e, predecessor, successor);
predecessor.setNext(newest);
successor.setPrev(newest);
this.size++;
}
public E removeFirst() {
if (this.isEmpty()) {
return null;
}
return this.remove(header.getNext());
}
public E removeLast() {
if (this.isEmpty()) {
return null;
}
return this.remove(trailer.getPrev());
}
public E remove(Node<E> e) {
e.next.setPrev(e.prev);
e.prev.setNext(e.next);
this.size--;
return e.getElement();
}
public String toString() {
StringBuilder sb = new StringBuilder("(");
Node<E> walk = this.header.next;
while (walk != this.trailer) {
sb.append(walk.element);
if (walk.next != this.trailer)
sb.append(", ");
walk = walk.next;
}
sb.append(")");
return sb.toString();
}
//DONE
public void add(int index, E element) {
Node<E> pred = header;
Node<E> succ = pred.getNext();
int count = 0;
while(succ != null) {
if(count == index) addBetween(element, pred, succ);
count++;
pred = pred.getNext();
succ = succ.getNext();
}
}
//DONE
public void add(E e) {
add(size, e);
}
//DONE
public void clear() {
while(!isEmpty()) {
removeFirst();
}
}
public E get(int index) {
if (isEmpty()) return null;
Node<E> current = header;
int count = 0;
while(current != null) {
if(count == index) return current.getElement();
count++;
current = current.getNext();
}
return null;
}
public E set(int index, E element) {
if(isEmpty()) return null;
Node<E> current = header;
E returnVal = null;
int count = 0;
while(current != null) {
if(count == index) {
if(count == 0) {
returnVal = get(0);
removeFirst();
add(0, element);
}
else if(count == size) {
returnVal = get(size);
removeLast();
add(size, element);
}
else {
returnVal = get(index);
remove(current);
add(index, element);
}
}
}
return returnVal;
}
}
package labs;
public class DoublyLinkedListDemo {
public static void main(String[] args) {
//testing methods on a String DoublyList
DoublyLinkedList<String> stringList = new DoublyLinkedList<>();
stringList.addFirst("Strawberry");
stringList.addFirst("Banana");
stringList.addFirst("Apple");
stringList.set(0, stringList.get(1));
System.out.println(stringList);
stringList.add(1, "Pear");
System.out.println(stringList);
stringList.add("Blueberry");
System.out.println(stringList);
System.out.println(stringList.get(1));
stringList.clear();
System.out.println(stringList);
System.out.println(stringList.set(0, stringList.get(1)));
System.out.println(stringList.get(0));
}
}
So I have an implementation of the Singly Linked List and I am trying to add a method which reports the second to last node of the list. However, I was not sure if I am allowed to write the method under the Node class then access it from the Singly Linked List class. If I do this, my instance variable of the node class('head' is used as a variable to access the penultimate method but also as the input of the penultimate method. Is that okay? Below is my implementation/attempt.
public class SinglyLinkedList {
private static class Node<Integer>{
private Integer element;
private Node<Integer> next;
private Node<Integer> penultimate;
public Node(Integer e, Node<Integer> n) {
element = e;
next = n;
penultimate = null;
}
public Integer getElement() {return element;}
public Node<Integer> getNext(){return next;}
public void setNext(Node<Integer> n) {next = n;}
public Node<Integer> penultimate(Node<Integer> head) {
Node<Integer> current = head;
while(current != null) {
if(head.getNext() == null) {
penultimate = head;
}
else {
current = current.getNext();
}
}
return penultimate;
}
}
private Node<Integer> head = null;
private Node<Integer> tail = null;
private int size = 0;
public SinglyLinkedList() {}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public Integer first() {
if (isEmpty()) {
return null;
}
return head.getElement();
}
public Integer last() {
if(isEmpty()) {
return null;
}
return tail.getElement();
}
public void addFirst(Integer i) {
head = new Node<> (i, head);
if(size == 0) {
tail = head;
}
size++;
}
public void addLast(Integer i) {
Node<Integer> newest = new Node<>(i,null);
if(isEmpty()) {
head = newest;
}
else {
tail.setNext(newest);
tail = newest;
size++;
}
}
public Integer removeFirst() {
if(isEmpty()) {
return null;
}
Integer answer = head.getElement();
head = head.getNext();
size--;
if(size == 0) {
tail = null;
}
return answer;
}
public void getPenultimate() {
if(isEmpty()) {
System.out.println("List is empty. Please check.");
}
else {
System.out.println("The second last node is: " + head.penultimate(head));
}
}
Remove the field penultimate. You do not want it in every node, in fact in no node, but calculated.
In the Node's penultimate method head should not be used in the loop.
//private Node<Integer> penultimate;
// head: ...#->#->#->P->null
public Node<Integer> penultimate(Node<Integer> head) {
Node<Integer> penultimate = null;
Node<Integer> current = head;
while (current != null) {
if (current.getNext() == null) {
penultimate = current;
break;
}
current = current.getNext();
}
return penultimate;
}
Or the third (second?) to last node:
// head: ...#->#->#->P->#->null
public Node<Integer> penultimate(Node<Integer> head) {
Node<Integer> penultimate = null;
Node<Integer> current = head;
while (current != null) {
if (current.getNext() == null) {
break;
}
penultimate = current;
current = current.getNext();
}
return penultimate;
}
Why not keep track of the second to last node?
private Node<Integer> head = null;
private Node<Integer> tail = null;
private Node<Integer> secondToLast = null;
private int size = 0;
public SinglyLinkedList() {}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public Integer first() {
if (isEmpty()) {
return null;
}
return head.getElement();
}
public Integer last() {
if(isEmpty()) {
return null;
}
return tail.getElement();
}
public void addFirst(Integer i) {
if (size == 1) {
secondToLast = head;
}
head = new Node<> (i, head);
if(size == 0) {
tail = head;
}
size++;
}
public void addLast(Integer i) {
Node<Integer> newest = new Node<>(i,null);
if(isEmpty()) {
head = newest;
}
else {
tail.setNext(newest);
secondToLast = tail;
}
tail = newest;
size++;
}
public Integer removeFirst() {
if(isEmpty()) {
return null;
}
Integer answer = head.getElement();
head = head.getNext();
size--;
if(size == 0) {
tail = null;
}
if (size == 1) {
secondToLast = null;
}
return answer;
}
public void getPenultimate() {
if(isEmpty()) {
System.out.println("List is empty. Please check.");
}
else {
System.out.println("The second last node is: " + secondToLast);
}
}
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.
I have implemented a Linked List into Java. I have created everything, but I am having difficulty removing a specific node with specific data. It is throwing a NullPointerException. I believe, I am getting a NullPointerException because the next node is null. If someone could please point me in the right direction that would be great.
Input
anything
one
two
three
exception:
Exception in thread "main" java.lang.NullPointerException
at LinkedList.remove(LinkedList.java:28)
at Main.main(Main.java:29)
Classes:
Linked list class
public class LinkedList {
// fields
private Node head;
private Node last;
private int size = 0;
// constructor, used when the class is first called
public LinkedList() {
head = last = new Node(null);
}
// add method
public void add(String s) {
last.setNext(new Node(s));
last = last.getNext();
size++;
}
// remove method, if it returns false then the specified index element doens not exist
// otherwise will return true
public boolean remove(String data) {
Node current = head;
last = null;
while(current != null) {
if(current.getData().equals(data)) {
current = current.getNext();
if(last == null) {
last = current;
}else {
last.getNext().setNext(current);
size--;
return true;
}
}else {
last = current;
current = current.getNext();
}
}
return false;
}
//will return the size of the list - will return -1 if list is empty
public int size() {
return size;
}
// will check if the list is empty or not
public boolean isEmpty() {
return true;
}
// #param (index) will get the data at specified index
public String getData(int index) {
if(index <= 0) {
return null;
}
Node current = head.getNext();
for(int i = 1;i < index;i++) {
if(current.getNext() == null) {
return null;
}
current = current.getNext();
}
return current.getData();
}
//#param will check if the arguement passed is in the list
// will return true if the list contains arg otherwise false
public boolean contains(String s) {
for(int i = 1;i<=size();i++) {
if(getData(i).equals(s)) {
return true;
}
}
return false;
}
//#return contents of the list - recursively
public String toString() {
Node current = head.getNext();
String output = "[";
while(current != null) {
output += current.getData()+",";
current = current.getNext();
}
return output+"]";
}
//#return first node
public Node getHead() {
return head;
}
// #return (recursively) list
public void print(Node n) {
if(n == null) {
return;
}else {
System.out.println(n.getData());
print(n.getNext());
}
}
}
Main
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
public static void main(String[] args) throws IOException{
LinkedList list = new LinkedList(); // declaring main linked list
LinkedList b_List = new LinkedList(); // declaring the backup list
String input = null;
// getting input from user, will stop when user has entered 'fin'
while(!(input = br.readLine()).equals("fin")) {
list.add(input); // adding to main list
b_List.add(input);
}
list.print(list.getHead().getNext());
System.out.println("Input Complete.");
if(list.size() == 1) {
System.out.println("You have entered only one name. He/She is the survior");
}else {
System.out.println("Enter the name(s) would like to remove: ");
while(b_List.size() != 1) {
String toRemove = br.readLine();
b_List.remove(toRemove);
}
}
System.out.println("The contestants were: ");
list.print(list.getHead().getNext());
}
}
node
public class Node {
// Fields
private String data;
private Node next;
// constructor
public Node(String data) {
this(data,null);
}
// constructor two with Node parameter
public Node(String data, Node node) {
this.data = data;
next = node;
}
/**
* Methods below return information about fields within class
* */
// #return the data
public String getData() {
return data;
}
// #param String data to this.data
public void setData(String data) {
this.data = data;
}
// #return next
public Node getNext() {
return next;
}
// #param Node next set to this.next
public void setNext(Node next) {
this.next = next;
}
}
First of all, your head is just a before-first marker so you shouldn't start the remove check from it.
Second, your remove method fails if node data is null
Third - your implementation is broken anyway because of last.getNext().setNext(current) - it won't link previous node with next, it will link current to next (i.e. will do nothing)
Fourth - it still fails to remove first element because of mysterious operations with last...
Correct implementation of remove would be something like this:
public boolean remove(String data){
Node previous = head;
Node current = head.getNext();
while (current != null) {
String dataOld = current.getData();
if ((dataOld == null && data == null) || (dataOld != null && dataOld.equals(data))) {
Node afterRemoved = current.getNext();
previous.setNext(afterRemoved);
if (afterRemoved == null) { // i.e. removing last element
last = previous;
}
size--;
return true;
} else {
previous = current;
current = current.getNext();
}
}
return false;
}
Here we can see the simple implementation of LinkedList with iterator
class LinkedList implements Iterable{
private Node node;
public void add(Object data){
if(!Optional.ofNullable(node).isPresent()){
node = new Node();
node.setData(data);
}else{
Node node = new Node();
node.setData(data);
Node lastNode = getLastNode(this.node);
lastNode.setNext(node);
}
}
private Node getLastNode(Node node){
if(node.getNext()==null){
return node;
}else{
return getLastNode(node.getNext());
}
}
class Node{
private Object data;
private Node next;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
public Iterator iterator() {
return new NodeIterator();
}
class NodeIterator implements Iterator{
private Node current;
public boolean hasNext() {
if(current == null){
current = node;
return Optional.ofNullable(current).isPresent();
}else{
current = current.next;
return Optional.ofNullable(current).isPresent();
}
}
public Node next() {
return current;
}
}
}
public class LinkedListImpl {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.add("data1");
linkedList.add("data2");
linkedList.add("data3");
for(LinkedList.Node node: linkedList){
System.out.println(node.getData());
}
}
}
Here is Full Implementaion of Linked List
including insertion,deletion,searching,reversing,swaping,size,display and various important operations of linked list
import java.util.NoSuchElementException;
import java.util.Scanner;
class Node<T> {
public Node<T> next;
public T data;
public Node() {
}
public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
#Override
public String toString() {
return "Node [next=" + next + ", data=" + data + "]";
}
}
class LinkedList<T> {
Node<T> start = null;
Node<T> end = null;
public void insertAtStart(T data) {
Node<T> nptr = new Node<T>(data, null);
if (empty()) {
start = nptr;
end = start;
} else {
nptr.next = start;
start = nptr;
}
display();
}
public void insertAtEnd(T data) {
Node<T> nptr = new Node<T>(data, null);
if (empty()) {
insertAtStart(data);
return;
} else {
end.next = nptr;
end = nptr;
}
display();
}
public void insertAtPosition(int position, T data) {
if (position != 1 && empty())
throw new IllegalArgumentException("Empty");
if (position == 1) {
insertAtStart(data);
return;
}
Node<T> nptr = new Node<T>(data, null);
if (position == size()) {
Node<T> startPtr = start;
Node<T> endPtr = startPtr;
while (startPtr.next != null) {
endPtr = startPtr;
startPtr = startPtr.next;
}
endPtr.next = nptr;
nptr.next = end;
} else {
position -= 1;
Node<T> startPtr = start;
for (int i = 1; i < size(); i++) {
if (i == position) {
Node<T> temp = startPtr.next;
startPtr.next = nptr;
nptr.next = temp;
}
startPtr = startPtr.next;
}
}
display();
}
public void delete(int position) {
if (empty())
throw new IllegalArgumentException("Empty");
if (position == 1) {
start = start.next;
} else if (position == size()) {
Node<T> startPtr = start;
Node<T> endPtr = start;
while (startPtr.next != null) {
endPtr = startPtr;
startPtr = startPtr.next;
}
endPtr.next = null;
end = endPtr;
} else {
position -= 1;
Node<T> startPtr = start;
for (int i = 1; i <= position; i++) {
if (i == position) {
Node<T> temp = startPtr.next.next;
startPtr.next = temp;
}
startPtr = startPtr.next;
}
}
display();
}
public int index(T data) {
if (empty())
throw new IllegalArgumentException("Empty");
return index(start, data, 0);
}
private int index(Node<T> link, T data, int index) {
if (link != null) {
if (link.data == data) {
return index;
}
return index(link.next, data, ++index);
}
return -1;
}
public void replace(int position, T data) {
if (empty())
throw new IllegalArgumentException("Empty");
if (position == 1)
start.data = data;
else if (position == size())
end.data = data;
else {
Node<T> startPtr = start;
for (int i = 1; i <= position; i++) {
if (i == position)
startPtr.data = data;
startPtr = startPtr.next;
}
}
display();
}
public void replaceRecursively(int position, T data) {
replaceRecursively(start, position, data, 1);
display();
}
private void replaceRecursively(Node<T> link, int position, T data, int count) {
if (link != null) {
if (count == position) {
link.data = data;
return;
}
replaceRecursively(link.next, position, data, ++count);
}
}
public T middle() {
if (empty())
throw new NoSuchElementException("Empty");
Node<T> slowPtr = start;
Node<T> fastPtr = start;
while (fastPtr != null && fastPtr.next != null) {
slowPtr = slowPtr.next;
fastPtr = fastPtr.next.next;
}
return slowPtr.data;
}
public int occurence(T data) {
if (empty())
throw new NoSuchElementException("Empty");
return occurence(start, data, 0);
}
private int occurence(Node<T> link, T data, int occurence) {
if (link != null) {
if (link.data == data)
++occurence;
return occurence(link.next, data, occurence);
}
return occurence;
}
public void reverseRecusively() {
reverseRecusively(start);
swapLink();
display();
}
private Node<T> reverseRecusively(Node<T> link) {
if (link == null || link.next == null)
return link;
Node<T> nextLink = link.next;
link.next = null;
Node<T> revrseList = reverseRecusively(nextLink);
nextLink.next = link;
return revrseList;
}
public void reverse() {
if (empty())
throw new NoSuchElementException("Empty");
Node<T> prevLink = null;
Node<T> currentLink = start;
Node<T> nextLink = null;
while (currentLink != null) {
nextLink = currentLink.next;
currentLink.next = prevLink;
prevLink = currentLink;
currentLink = nextLink;
}
swapLink();
display();
}
private void swapLink() {
Node<T> temp = start;
start = end;
end = temp;
}
public void swapNode(T dataOne, T dataTwo) {
if (dataOne == dataTwo)
throw new IllegalArgumentException("Can't swap " + dataOne + " and " + dataTwo + " both are same");
boolean foundDataOne = false;
boolean foundDataTwo = false;
Node<T> dataOnePtr = start;
Node<T> dataOnePrevPtr = start;
while (dataOnePtr.next != null && dataOnePtr.data != dataOne) {
dataOnePrevPtr = dataOnePtr;
dataOnePtr = dataOnePtr.next;
}
Node<T> dataTwoPtr = start;
Node<T> dataTwoPrevPtr = start;
while (dataTwoPtr.next != null && dataTwoPtr.data != dataTwo) {
dataTwoPrevPtr = dataTwoPtr;
dataTwoPtr = dataTwoPtr.next;
}
if (dataOnePtr != null && dataOnePtr.data == dataOne)
foundDataOne = true;
if (dataTwoPtr != null && dataTwoPtr.data == dataTwo)
foundDataTwo = true;
if (foundDataOne && foundDataTwo) {
if (dataOnePtr == start)
start = dataTwoPtr;
else if (dataTwoPtr == start)
start = dataOnePtr;
if (dataTwoPtr == end)
end = dataOnePtr;
else if (dataOnePtr == end)
end = dataTwoPtr;
Node<T> tempDataOnePtr = dataOnePtr.next;
Node<T> tempDataTwoPtr = dataTwoPtr.next;
dataOnePrevPtr.next = dataTwoPtr;
dataTwoPtr.next = tempDataOnePtr;
dataTwoPrevPtr.next = dataOnePtr;
dataOnePtr.next = tempDataTwoPtr;
if (dataOnePtr == dataTwoPrevPtr) {
dataTwoPtr.next = dataOnePtr;
dataOnePtr.next = tempDataTwoPtr;
} else if (dataTwoPtr == dataOnePrevPtr) {
dataOnePtr.next = dataTwoPtr;
dataTwoPtr.next = tempDataOnePtr;
}
} else
throw new NoSuchElementException("Either " + dataOne + " or " + dataTwo + " not in the list");
display();
}
public int size() {
return size(start, 0);
}
private int size(Node<T> link, int i) {
if (link == null)
return 0;
else {
int count = 1;
count += size(link.next, 0);
return count;
}
}
public void printNthNodeFromLast(int n) {
if (empty())
throw new NoSuchElementException("Empty");
Node<T> main_ptr = start;
Node<T> ref_ptr = start;
int count = 0;
while (count < n) {
if (ref_ptr == null) {
System.out.println(n + " is greater than the no of nodes in the list");
return;
}
ref_ptr = ref_ptr.next;
count++;
}
while (ref_ptr != null) {
main_ptr = main_ptr.next;
ref_ptr = ref_ptr.next;
}
System.out.println("Node no " + n + " from the last is " + main_ptr.data);
}
public void display() {
if (empty())
throw new NoSuchElementException("Empty");
display(start);
}
private void display(Node<T> link) {
if (link != null) {
System.out.print(link.data + " ");
display(link.next);
}
}
public boolean empty() {
return start == null;
}
}
public class LinkedListTest {
public static void main(String[] args) {
LinkedList<Integer> linkedList = new LinkedList<Integer>();
boolean yes = true;
Scanner scanner = new Scanner(System.in);
do {
System.out.println("\n1. Insert At Start");
System.out.println("2. Insert At End");
System.out.println("3. Insert at Position");
System.out.println("4. Delete");
System.out.println("5. Display");
System.out.println("6. Empty status");
System.out.println("7. Get Size");
System.out.println("8. Get Index of the Item");
System.out.println("9. Replace data at given position");
System.out.println("10. Replace data at given position recusively");
System.out.println("11. Get Middle Element");
System.out.println("12. Get Occurence");
System.out.println("13. Reverse Recusively");
System.out.println("14. Reverse");
System.out.println("15. Swap the nodes");
System.out.println("16. Nth Node from last");
System.out.println("\nEnter your choice");
int choice = scanner.nextInt();
switch (choice) {
case 1:
try {
System.out.println("Enter the item");
linkedList.insertAtStart(scanner.nextInt());
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 2:
try {
System.out.println("Enter the item");
linkedList.insertAtEnd(scanner.nextInt());
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 3:
try {
System.out.println("Enter the position");
int position = scanner.nextInt();
if (position < 1 || position > linkedList.size()) {
System.out.println("Invalid Position");
break;
}
System.out.println("Enter the Item");
linkedList.insertAtPosition(position, scanner.nextInt());
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 4:
try {
System.out.println("Enter the position");
int position = scanner.nextInt();
if (position < 1 || position > linkedList.size()) {
System.out.println("Invalid Position");
break;
}
linkedList.delete(position);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 5:
try {
linkedList.display();
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 6:
System.out.println(linkedList.empty());
break;
case 7:
try {
System.out.println(linkedList.size());
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 8:
try {
System.out.println(linkedList.index(scanner.nextInt()));
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 9:
try {
System.out.println("Enter the position");
int position = scanner.nextInt();
if (position < 1 || position > linkedList.size()) {
System.out.println("Invalid Position");
break;
}
linkedList.replace(position, scanner.nextInt());
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 10:
try {
System.out.println("Enter the position");
int position = scanner.nextInt();
if (position < 1 || position > linkedList.size()) {
System.out.println("Invalid Position");
break;
}
System.out.println("Enter the item");
linkedList.replaceRecursively(position, scanner.nextInt());
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 11:
try {
System.out.println(linkedList.middle());
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 12:
try {
System.out.println("Enter the item");
System.out.println(linkedList.occurence(scanner.nextInt()));
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 13:
try {
linkedList.reverseRecusively();
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 14:
try {
linkedList.reverse();
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 15:
try {
System.out.println("Enter the nodes");
linkedList.swapNode(scanner.nextInt(), scanner.nextInt());
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 16:
try {
System.out.println("Enter which node do you want from last");
linkedList.printNthNodeFromLast(scanner.nextInt());
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
default:
System.out.println("Invalid Choice");
break;
}
} while (yes);
scanner.close();
}
}
Consider another possible implementation of a working non-recursive Linked List with generic T placeholder. It works out of the box and the code is a more simple one:
import java.util.Iterator;
import java.util.NoSuchElementException;
public class LinkedList<T> implements Iterable<T> {
private Node first;
private Node last;
private int N;
public LinkedList() {
first = null;
last = null;
N = 0;
}
public void add(T item) {
if (item == null) { throw new NullPointerException("Null object!"); }
if (!isEmpty()) {
Node prev = last;
last = new Node(item, null);
prev.next = last;
}
else {
last = new Node(item, null);
first = last;
}
N++;
}
public boolean remove(T item) {
if (isEmpty()) { throw new IllegalStateException("Empty list!"); }
boolean result = false;
Node prev = first;
Node curr = first;
while (curr.next != null || curr == last) {
if (curr.data.equals(item)) {
// remove the last remaining element
if (N == 1) { first = null; last = null; }
// remove first element
else if (curr.equals(first)) { first = first.next; }
// remove last element
else if (curr.equals(last)) { last = prev; last.next = null; }
// remove element
else { prev.next = curr.next; }
N--;
result = true;
break;
}
prev = curr;
curr = prev.next;
}
return result;
}
public int size() {
return N;
}
public boolean isEmpty() {
return N == 0;
}
private class Node {
private T data;
private Node next;
public Node(T data, Node next) {
this.data = data;
this.next = next;
}
}
public Iterator<T> iterator() { return new LinkedListIterator(); }
private class LinkedListIterator implements Iterator<T> {
private Node current = first;
public T next() {
if (!hasNext()) { throw new NoSuchElementException(); }
T item = current.data;
current = current.next;
return item;
}
public boolean hasNext() { return current != null; }
public void remove() { throw new UnsupportedOperationException(); }
}
#Override public String toString() {
StringBuilder s = new StringBuilder();
for (T item : this)
s.append(item + " ");
return s.toString();
}
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
while(!StdIn.isEmpty()) {
String input = StdIn.readString();
if (input.equals("print")) { StdOut.println(list.toString()); continue; }
if (input.charAt(0) == ('+')) { list.add(input.substring(1)); continue; }
if (input.charAt(0) == ('-')) { list.remove(input.substring(1)); continue; }
break;
}
}
}
For more LinkedList examples, your can check out the article.
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();
}
}