JavaAlgorithms/DataStructures/Lists/SinglyLinkedList.java

350 lines
7.5 KiB
Java

package DataStructures.Lists;
import java.util.StringJoiner;
/** https://en.wikipedia.org/wiki/Linked_list */
public class SinglyLinkedList {
/** Head refer to the front of the list */
private Node head;
/** Size of SinglyLinkedList */
private int size;
/** Init SinglyLinkedList */
public SinglyLinkedList() {
head = null;
size = 0;
}
/**
* Init SinglyLinkedList with specified head node and size
*
* @param head the head node of list
* @param size the size of list
*/
public SinglyLinkedList(Node head, int size) {
this.head = head;
this.size = size;
}
/**
* Inserts an element at the head of the list
*
* @param x element to be added
*/
public void insertHead(int x) {
insertNth(x, 0);
}
/**
* Insert an element at the tail of the list
*
* @param data element to be added
*/
public void insert(int data) {
insertNth(data, size);
}
/**
* Inserts a new node at a specified position of the list
*
* @param data data to be stored in a new node
* @param position position at which a new node is to be inserted
*/
public void insertNth(int data, int position) {
checkBounds(position, 0, size);
Node newNode = new Node(data);
if (head == null) {
/* the list is empty */
head = newNode;
size++;
return;
} else if (position == 0) {
/* insert at the head of the list */
newNode.next = head;
head = newNode;
size++;
return;
}
Node cur = head;
for (int i = 0; i < position - 1; ++i) {
cur = cur.next;
}
newNode.next = cur.next;
cur.next = newNode;
size++;
}
/**
Detects if there is a loop in the singly linked list
using floy'd turtle and hare algorithm.
**/
public boolean detectLoop(){
Node currentNodeFast = head;
Node currentNodeSlow = head;
boolean flag = false;
while(currentNodeFast!=null && currentNodeFast.next != null && currentNodeSlow!=null && currentNodeSlow.next != null){
currentNodeFast = currentNodeFast.next.next;
currentNodeSlow = currentNodeSlow.next;
if (currentNodeFast==currentNodeSlow){
flag = true;
break;
}
}
return flag;
}
/**
Swaps nodes of two given values a and b.
**/
public void swapNodes(int a, int b){
Node currentNode = head;
Node temp = null;
while(currentNode!=null){
if (currentNode.next.value == a){
temp = currentNode.next;
}
if(currentNode.next.value == b){
currentNode.next=temp;
}
currentNode=currentNode.next;
}
}
/**
Reverse a singly linked list from a given node till the end
**/
Node reverseList(Node node) {
Node prev = null, curr = node, next;
while (curr != null) {
next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
node = prev;
return node;
}
/** Deletes a node at the head */
public void deleteHead() {
deleteNth(0);
}
/** Deletes an element at the tail */
public void delete() {
deleteNth(size - 1);
}
/** Deletes an element at Nth position */
public void deleteNth(int position) {
checkBounds(position, 0, size - 1);
if (position == 0) {
Node destroy = head;
head = head.next;
destroy = null; /* clear to let GC do its work */
size--;
return;
}
Node cur = head;
for (int i = 0; i < position - 1; ++i) {
cur = cur.next;
}
Node destroy = cur.next;
cur.next = cur.next.next;
destroy = null; // clear to let GC do its work
size--;
}
/**
* @param position to check position
* @param low low index
* @param high high index
* @throws IndexOutOfBoundsException if {@code position} not in range {@code low} to {@code high}
*/
public void checkBounds(int position, int low, int high) {
if (position > high || position < low) {
throw new IndexOutOfBoundsException(position + "");
}
}
/** Clear all nodes in the list */
public void clear() {
Node cur = head;
while (cur != null) {
Node prev = cur;
cur = cur.next;
prev = null; // clear to let GC do its work
}
head = null;
size = 0;
}
/**
* Checks if the list is empty
*
* @return {@code true} if list is empty, otherwise {@code false}.
*/
public boolean isEmpty() {
return size == 0;
}
/**
* Returns the size of the linked list.
*
* @return the size of the list.
*/
public int size() {
return size;
}
/**
* Get head of the list.
*
* @return head of the list.
*/
public Node getHead() {
return head;
}
/**
* Calculate the count of the list manually
*
* @return count of the list
*/
public int count() {
int count = 0;
Node cur = head;
while (cur != null) {
cur = cur.next;
count++;
}
return count;
}
/**
* Test if the value key is present in the list.
*
* @param key the value to be searched.
* @return {@code true} if key is present in the list, otherwise {@code false}.
*/
public boolean search(int key) {
Node cur = head;
while (cur != null) {
if (cur.value == key) {
return true;
}
cur = cur.next;
}
return false;
}
/**
* Return element at special index.
*
* @param index given index of element
* @return element at special index.
*/
public int getNth(int index) {
checkBounds(index, 0, size - 1);
Node cur = head;
for (int i = 0; i < index; ++i) {
cur = cur.next;
}
return cur.value;
}
@Override
public String toString() {
StringJoiner joiner = new StringJoiner("->");
Node cur = head;
while (cur != null) {
joiner.add(cur.value + "");
cur = cur.next;
}
return joiner.toString();
}
/** Driver Code */
public static void main(String[] arg) {
SinglyLinkedList list = new SinglyLinkedList();
assert list.isEmpty();
assert list.size() == 0 && list.count() == 0;
assert list.toString().equals("");
/* Test insert function */
list.insertHead(5);
list.insertHead(7);
list.insertHead(10);
list.insert(3);
list.insertNth(1, 4);
assert list.toString().equals("10->7->5->3->1");
/* Test search function */
assert list.search(10) && list.search(5) && list.search(1) && !list.search(100);
/* Test get function */
assert list.getNth(0) == 10 && list.getNth(2) == 5 && list.getNth(4) == 1;
/* Test delete function */
list.deleteHead();
list.deleteNth(1);
list.delete();
assert list.toString().equals("7->3");
assert list.size == 2 && list.size() == list.count();
list.clear();
assert list.isEmpty();
try {
list.delete();
assert false; /* this should not happen */
} catch (Exception e) {
assert true; /* this should happen */
}
}
}
/**
* This class is the nodes of the SinglyLinked List. They consist of a value and a pointer to the
* node after them.
*/
class Node {
/** The value of the node */
int value;
/** Point to the next node */
Node next;
Node() {}
/**
* Constructor
*
* @param value Value to be put in the node
*/
Node(int value) {
this(value, null);
}
/**
* Constructor
*
* @param value Value to be put in the node
* @param next Reference to the next node
*/
Node(int value, Node next) {
this.value = value;
this.next = next;
}
}