singly linked-list in java implementation - java

I have being given a task to implement the following method in Java: SubList(S, L) returns true if list S is a sublist of list L.
I need to use the following notation when I process lists as an abstract object in the recurrence relations. Given a list L, we write L = [H|R] where H is the head of the list and R is the rest of the list. For an empty list L, we write L = []. For example, if L = [1, 2, 3, 4, 5], H = 1, and R = [2, 3, 4, 5].
Hence my tasks are:
a) Provide the recurrence relations for SubList(S, L) using the above list notation.
b) Implement the recursive algorithm in Java using the recurrence relations.
Being stuck on this task for a day and a half now and still having trouble how to do this. Appreciate, if anyone can help me to solve this problem.
This is the java code I have been given to work with.
class SLLNode {
public Object info; // This is the data
public SLLNode next; // this is the address of the next node
public SLLNode() { // Here's how we construct an empty list.
next = null;
}
public SLLNode(Object el) {
info = el; next = null;
}
public SLLNode(Object el, SLLNode ptr) {
info = el; next = ptr;
}
}
class SLList {
protected SLLNode head = null;
public SLList() {
}
public void setToNull() {
head = null;
}
public boolean isEmpty() {
return head == null;
}
public Object first() {
return head.info;
}
public SLLNode head() {
return head;
}
public void printAll() {
for (SLLNode tmp = head; tmp != null; tmp = tmp.next)
System.out.print(tmp.info.toString());
}
public void add(Object el) {
head= new SLLNode(el,head);
}
public Object find(Object el) {
SLLNode tmp = head;
for ( ; tmp != null && !el.equals(tmp.info); tmp = tmp.next);
if (tmp == null)
return null;
else return tmp.info;
}
public boolean member(Object el) {
SLLNode tmp = head;
for ( ; tmp != null && !el.equals(tmp.info); tmp = tmp.next);
if (tmp == null)
return false;
else return true;
}
public Object deleteHead() { // remove the head and return its info;
Object el = head.info;
head = head.next;
return el;
}
public void delete(Object el) { // find and remove el;
if (head != null) // if non-empty list;
if (el.equals(head.info)) // if head needs to be removed;
head = head.next;
else {
SLLNode pred = head, tmp = head.next;
for ( ; tmp != null && !(tmp.info.equals(el));
pred = pred.next, tmp = tmp.next);
if (tmp != null) // if found
pred.next = tmp.next;
}
}
}

SubList([], L) = true (1)
SubList(H|[], H|*) = true (2)
SubList(H|[], []) = false (3)
SubList(SH|[], H|R) = SubList(SH|[], H|[]) OR SubList(SH|[], R) (4)
SubList(SH|SR, L) = SubList(SH|[], L) AND SubList(SR, L) (5)
In english, it means that if L contains the first element of your sublist S AND that it contains the remaining elements of the sublist, then your SubList method is gonna return true.
The recursion here visible on the 4th and 5th lines, where you see that we are invoking the same function again and again until SR contains only one element.
Ex:
L = [1,2,5]
S = [1,5]
SubList(S, L) = SubList([1,5], [1,2,5])
= SubList(1|[5], 1|[2,5]) (4+5)
= SubList(1|[], 1|[2,5]) AND SubList([5], 1|[2,5])
= SubList(1|[], 1|[2,5]) AND (SubList(5|[], 1|[]) OR SubList(5|[], [2,5]))
= SubList(1|[], 1|[2,5]) AND (SubList(5|[], 1|[]) OR (SubList(5|[], 2|[]) OR SubList(5|[], [5])))
= SubList(1|[], 1|[2,5]) AND (SubList(5|[], 1|[]) OR (SubList(5|[], 2|[]) OR SubList(5|[], 5|[])))
= true AND (false OR (false OR true))
= true AND true
= true
Possible Java implementation:
public SLList(SLNode h) {
this.head = h;
}
public SLList singletonList(SLNode n) {
return new SLList(new SLNode(n.info));
}
public SLList remainingList(SLNode n) {
if(n == null) return new SLList();
return new SLList(n);
}
private static boolean subList(SLList s, SLList l) {
if(s.isEmpty()) return true;
if(l.isEmpty()) return false;
if(s.head.next == null && l.first().equals(s.first())) return true;
return (subList(singletonList(s.head), singletonList(l.head)) ||
subList(singletonList(s.head), remainingList(l.head.next))) &&
subList(remainingList(s.head.next), l);
}
I haven't tested the code, there might be some null checks missing but the important thing is that you get the idea of how recursion works.

Related

Reverse even numbers (Only) from given Singly Linked List

I want to reverse even numbers in a singly linked list in java, but I face some difficulty to get the correct output.
For example,
input : 2, 18, 24, 3, 5, 7, 9, 6, 12
the method should reverse the even numbers only which are {2,18,24} and {6,12}
the correct output : 24 , 18 ,2 , 3 , 5 ,7 , 9 , 12 , 6
But,my output: 24 18 3 5 7 9 12 6 which it is wrong
the main method
public static void main(String[] args) throws Exception {
SLL<Integer> p = new SLL<Integer>();
int[] e = { 2, 18, 24, 3, 5, 7, 9, 6, 12,5 ,4 ,3 ,2,6,8};
for (int i = 0; i < e.length; i++) {
p.addToHead(e[i]);
}
p = reverse(p);
p.printAll();
}
This is the method (that doesn't work correctly)
public static SLL<Integer> reverse(SLL<Integer> p) {
SLL<Integer> returnList = new SLL<Integer>();
Stack<Integer> stk = new Stack<Integer>();
for (SLLNode tmp = p.getHead(); tmp != null; tmp = tmp.next) {
if ((((Integer) tmp.info) % 2) != 0) {
returnList.addToHead((Integer) tmp.info);
p.deleteFromHead();
} else if ((((Integer) tmp.info) % 2) == 0) {
stk.push((Integer) tmp.info);
p.deleteFromHead();
}
if (stk.getLSize() >= 2) {
while (!(stk.isEmpty())) {
returnList.addToHead((Integer) stk.pop());
}
}
}
return returnList;
}
this is the SLLNode class
public class SLLNode<T> {
public T info;
public SLLNode<T> next;
public SLLNode() {
this(null,null);
}
public SLLNode(T el) {
this(el,null);
}
public SLLNode(T el, SLLNode<T> ptr) {
info = el;
next = ptr;
}
}
this is the SLL class
public class SLL<T> {
protected SLLNode<T> head, tail;
public SLL() {
head = tail = null;
}
public boolean isEmpty() {
return head == null;
}
public void addToHead(T el) {
head = new SLLNode<T>(el, head);
if (tail == null)
tail = head;
}
public SLLNode getHead(){
return head;
}
public void addToTail(T el) {
if (!isEmpty()) {
tail.next = new SLLNode<T>(el);
tail = tail.next;
} else
head = tail = new SLLNode<T>(el);
}
public T deleteFromHead() { // delete the head and return its info;
if (isEmpty())
return null;
T el = head.info;
if (head == tail) // if only one node on the list;
head = tail = null;
else
head = head.next;
return el;
}
public T deleteFromTail() { // delete the tail and return its info;
if (isEmpty())
return null;
T el = tail.info;
if (head == tail) // if only one node in the list;
head = tail = null;
else { // if more than one node in the list,
SLLNode<T> tmp; // find the predecessor of tail;
for (tmp = head; tmp.next != tail; tmp = tmp.next)
;
tail = tmp; // the predecessor of tail becomes tail;
tail.next = null;
}
return el;
}
public void delete(T el) { // delete the node with an element el;
if (!isEmpty())
if (head == tail && el.equals(head.info)) // if only one
head = tail = null; // node on the list;
else if (el.equals(head.info)) // if more than one node on the list;
head = head.next; // and el is in the head node;
else { // if more than one node in the list
SLLNode<T> pred, tmp;// and el is in a nonhead node;
for (pred = head, tmp = head.next; tmp != null
&& !tmp.info.equals(el); pred = pred.next, tmp = tmp.next)
;
if (tmp != null) { // if el was found;
pred.next = tmp.next;
if (tmp == tail) // if el is in the last node;
tail = pred;
}
}
}
public void printAll() {
for (SLLNode<T> tmp = head; tmp != null; tmp = tmp.next)
System.out.print(tmp.info + " ");
}
public boolean isInList(T el) {
SLLNode<T> tmp;
for (tmp = head; tmp != null && !tmp.info.equals(el); tmp = tmp.next)
;
return tmp != null;
}
public int length() {
int length = 0;
for (SLLNode tmp = head; tmp != null; tmp = tmp.next) {
length += 1;
}
return length;
}
Running your reverse method gives me a different output to what you see. So, I suspect you got your output from slightly different code.
I get : 24, 6, 9, 7, 5, 3, 2, 18
In your reverse method you start adding even numbers to your returnList when you have 2 on the stack. If you want to reverse all even numbers you need to wait until you have all the continuous even numbers on the stack. Or in other words, when you get an odd number, or there are no numbers left, you can pop all the even numbers back off the stack..
I think you should also use addTail rather than addHead.
So something like
public static SLL<Integer> reverse(SLL<Integer> p) {
SLL<Integer> returnList = new SLL<Integer>();
Stack<Integer> stk = new Stack<Integer>();
for (SLLNode tmp = p.getHead(); tmp != null; tmp = tmp.next) {
if ((((Integer) tmp.info) % 2) != 0) {
// add any stacked even numbers
while (!(stk.isEmpty())) {
returnList.addToTail((Integer) stk.pop());
}
// add the odd number
returnList.addToTail((Integer) tmp.info);
} else if ((((Integer) tmp.info) % 2) == 0) {
System.out.println("even " + tmp.info);
stk.push((Integer) tmp.info);
}
}
// add any remaining even numbers from the stack
while (!(stk.isEmpty())) {
returnList.addToTail((Integer) stk.pop());
}
return returnList;
}
I made it using list of python, I just wanted to know whether I could write this program without using a linked list or not. The complexities may be high, but it is just an experimental implementation which works
arr = [2,18,24,3,5,7,9,6,12]
arr_final = []
temp = []
for i in arr:
if i%2 == 0:
temp.append(i)
else:
if temp!=[]:
temp.reverse()
for j in temp:
arr_final.append(j)
temp = []
arr_final.append(i)
if temp!=[]:
temp.reverse()
for j in temp:
arr_final.append(j)
temp = []
print(arr_final)

Trying to figure out what's wrong with my return in my list function

public class Linked {
static class Node {
public Node (double item, Node next) { this.item = item; this.next = next; }
public double item;
public Node next;
}
int N;
Node first;
public int posofLastNine () {
if(first != null) {
int index = 0;
int indexTemp = 0;
for (Node x = this.first; x != null; x=x.next) {
if (x.item == 9.0)
indexTemp = index;
index++;
}
index -= 1;
if (this.first.item == 9.0)
return index;
if (indexTemp == 0)
return -1;
return index - indexTemp;
}
return -1;
}
The point is to return the last index in a list that is 9. That is 0,1,9,9,10 would return 3. The issue is, it needs to return -1 if a 9 does not exist. I cannot figure out what's wrong in my code that's preventing it. I cannot add a function or add to parameters. But that's the only issue.
Your code uses variables and classes that you have not shown us, so I can't discern what's going on there. Please provide more information if you want specific help.
To get the last index of a specific element in an array (or list), the easiest way is to simply iterate backwards through the array. Return the first element that matches your parameters. If the whole array is traversed and no dice, return -1.
Here is an example with int[]:
public static int indexOfLastNine(int[] arrayIn) {
for (int i = arrayIn.length - 1; i >= 0; i--) {
if (arrayIn[i] == 9) return i;
}
return -1;
}
Edit
If we have to use your specific type of Linked list, here is an implementation that will work. Please note that this assumes the last node in the Linked list points to null.
public int posOfLastNine() {
int lastNineIndex = -1;
int currentNodeIndex = 0;
Node currentNode = first;
while (true) {
if (currentNode == null) {
break;
}
if (currentNode.item == 9.0) {
lastNineIndex = currentNodeIndex;
}
currentNodeIndex++;
currentNode = currentNode.next;
}
return lastNineIndex;
}
It seems that the logic to detect the last index of 9.0 is overcomplicated.
It could be refactored like this:
remove null check for first
set resulting index to -1 immediately
remove redundant checks after the loop
always return calculated result
public int posofLastNine () {
int result = -1;
int index = 0;
for (Node x = this.first; x != null; x = x.next) {
if (x.item == 9.0) {
result = index;
}
index++;
}
return result;
}
Test code:
public static boolean test(int pos, String data) {
if (null == data || data.trim().isEmpty()) {
return -1 == pos;
}
String[] s = data.split("\\s");
Node head = null;
if (s.length > 0) {
head = new Node(Double.parseDouble(s[0]), null);
Node curr = head;
for (int i = 1; i < s.length; i++) {
Node next = new Node(Double.parseDouble(s[i]), null);
curr.next = next;
curr = next;
}
}
Linked linked = new Linked();
linked.N = pos;
linked.first = head;
return linked.N == linked.posofLastNine();
}
public static void main(String[] args) {
System.out.println(test(-1, null));
System.out.println(test(-1, ""));
System.out.println(test(0, "9 11 14 31"));
System.out.println(test(-1, "8 11 14 31")); // no 9
System.out.println(test(3, "9 11 9 9 14 16"));
}
Output:
true
true
true
true
true

partition in a singly linked list

I was doing this exercice:
Write code to partition a linked list around a value x, such that all nodes less than x come before all nodes greater than or equal to x. Example input: 3 -> 5 -> 8 -> 5 -> 10 -> 2 -> 1 output: 3 -> 1 -> 2 -> 10 -> 5 -> 5 -> 8
I found it hard to find a solution for Singly linked list (that created by my own, not using library), I would like to know if there is uncessary code blocks in my code and is there a way to avoid putting in two lists and then merge? because it seems to have very slow performance like that.
public CustomLinkedList partition(CustomLinkedList list, int x) {
CustomLinkedList beforeL = new CustomLinkedList();
CustomLinkedList afterL = new CustomLinkedList();
LinkedListNode current = list.getHead();
while (current != null) {
if (current.getData() < x) {
addToLinkedList(beforeL, current.getData());
} else {
addToLinkedList(afterL, current.getData());
}
// increment current
current = current.getNext();
}
if (beforeL.getHead() == null)
return afterL;
mergeLinkedLists(beforeL, afterL);
return beforeL;
}
public void addToLinkedList(CustomLinkedList list, int value) {
LinkedListNode newEnd = new LinkedListNode(value);
LinkedListNode cur = list.getHead();
if (cur == null)
list.setHead(newEnd);
else {
while (cur.getNext() != null) {
cur = cur.getNext();
}
cur.setNext(newEnd);
cur = newEnd;
}
}
public void mergeLinkedLists(CustomLinkedList list1, CustomLinkedList list2) {
LinkedListNode start = list1.getHead();
LinkedListNode prev = null;
while (start != null) {
prev = start;
start = start.getNext();
}
prev.setNext(list2.getHead());
}
CustumLinkedList contains two attributes: -LinkedListNode which is the head and an int which is the size.
LinkedListNode contains two attributes: One of type LinkedListNode pointing to next node and one of type int: data value
Thank you.
The problem of your code is not merging two lists as you mentioned. It's wrong to use the word merge here because you're only linking up the tail of the left list with head of right list which is a constant time operation.
The real problem is - on inserting a new element on the left or right list, you are iterating from head to tail every time which yields in-total O(n^2) operation and is definitely slow.
Here I've wrote a simpler version and avoid iterating every time from head to insert a new item by keeping track of the current tail.
The code is very simple and is definitely faster than yours(O(n)). Let me know if you need explanation on any part.
// I don't know how your CustomLinkedList is implemented. Here I wrote a simple LinkedList node
public class ListNode {
private int val;
private ListNode next;
public ListNode(int x) {
val = x;
}
public int getValue() {
return this.val;
}
public ListNode getNext() {
return this.next;
}
public void setNext(ListNode next) {
this.next = next;
}
}
public ListNode partition(ListNode head, int x) {
if(head == null) return null;
ListNode left = null;
ListNode right = null;
ListNode iterL = left;
ListNode iterR = right;
while(iter != null) {
if(iter.getValue() < x) {
iterL = addNode(iterL, iter.getValue());
}
else {
iterR = addNode(iterR, iter.getValue());
}
iter = iter.getNext();
}
// link up the left and right list
iterL.setNext(iterR);
return left;
}
public ListNode addNode(ListNode curr, int value) {
ListNode* newNode = new ListNode(value);
if(curr == null) {
curr = newNode;
} else {
curr.setNext(newNode);
curr = curr.getNext();
}
return curr;
}
Hope it helps!
If you have any list of data, access orderByX Method.
Hope it would help you.
public class OrderByX {
Nodes root = null;
OrderByX() {
root = null;
}
void create(int[] array, int k) {
for (int i = 0; i < array.length; ++i) {
root = insert(root, array[i]);
}
}
Nodes insert(Nodes root, int data) {
if (root == null) {
root = new Nodes(data);
} else {
Nodes tempNew = new Nodes(data);
tempNew.setNext(root);
root = tempNew;
}
return root;
}
void display() {
Nodes tempNode = root;
while (tempNode != null) {
System.out.print(tempNode.getData() + ", ");
tempNode = tempNode.getNext();
}
}
void displayOrder(Nodes root) {
if (root == null) {
return;
} else {
displayOrder(root.getNext());
System.out.print(root.getData() + ", ");
}
}
Nodes orderByX(Nodes root, int x) {
Nodes resultNode = null;
Nodes lessNode = null;
Nodes greatNode = null;
Nodes midNode = null;
while (root != null) {
if (root.getData() < x) {
if (lessNode == null) {
lessNode = root;
root = root.getNext();
lessNode.setNext(null);
} else {
Nodes temp = root.getNext();
root.setNext(lessNode);
lessNode = root;
root = temp;
}
} else if (root.getData() > x) {
if (greatNode == null) {
greatNode = root;
root = root.getNext();
greatNode.setNext(null);
} else {
Nodes temp = root.getNext();
root.setNext(greatNode);
greatNode = root;
root = temp;
}
} else {
if (midNode == null) {
midNode = root;
root = root.getNext();
midNode.setNext(null);
} else {
Nodes temp = root.getNext();
root.setNext(midNode);
midNode = root;
root = temp;
}
}
}
resultNode = lessNode;
while (lessNode.getNext() != null) {
lessNode = lessNode.getNext();
}
lessNode.setNext(midNode);
while (midNode.getNext() != null) {
midNode = midNode.getNext();
}
midNode.setNext(greatNode);
return resultNode;
}
public static void main(String... args) {
int[] array = { 7, 1, 6, 2, 8 };
OrderByX obj = new OrderByX();
obj.create(array, 0);
obj.display();
System.out.println();
obj.displayOrder(obj.root);
System.out.println();
obj.root = obj.orderByX(obj.root, 2);
obj.display();
}
}
class Nodes {
private int data;
private Nodes next;
Nodes(int data) {
this.data = data;
this.next = null;
}
public Nodes getNext() {
return next;
}
public void setNext(Nodes next) {
this.next = next;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
}
I think that maintaining two lists is not an issue. It is possible to use a single list, but at the cost of loosing some of the simplicity.
The principal problem seems to be the addToLinkedList(CustomLinkedList list, int value) method.
It iterates throughout the entire list in order to add a new element.
One alternative is to always add elements at the front of the list. This would also produce a valid solution, and would run faster.

Deleting a node from a linked list in Java

I'm trying to write a code that handles a linked list. This linked list is somehow different because it's a key-value pair linked list (singly). The linked list should provide the user with basic functions, such as retrieving the size of linked list, checking for a key whether it's in the list or not, insertion, and deletion. It seems that all the functions are working properly except for the deletion. The code for the deletion method run correctly with no run time error, but it gives me results that's not what I wanted to have. Here is my code:
public class SequentialSearch<Key,Value> {
private int N; // number of key-value pairs
private Node head; // the linked list of key-value pairs
private Node tail;
// a helper linked list data type
private class Node {
private Key key;
private Value val;
private Node next;
public Node(Key key, Value val, Node next) {
this.key = key;
this.val = val;
this.next = next;
}
public void setNext(Node next) {
this.next = next;
}
}
public SequentialSearch() {
}
public int size() {
if (head == null)
return 0;
else {
Node x = head;
while (x.next != null) {
N++;
x = x.next;
}
}
return N;
}
public boolean isEmpty() {
return size() == 0;
}
public boolean contains(Key key) {
return get(key) != null;
}
public Value get(Key key) {
for (Node x = head; x != null; x = x.next) {
if (key.equals(x.key))
return x.val;
}
return null;
}
public void put(Key key, Value val) {
if (val == null) {
delete(key);
return;
}
for (Node x = first; x != null; x = x.next) {
if (key.equals(x.key)) {
x.val = val;
return;
}
}
first = new Node(key, val, first);
N++;
}
public boolean delete(Key key) {
Node curr = head;
Node prev = null;
boolean result = false;
if(isEmpty())
System.err.println("Error: The list is empty.");
while(curr != null) {
if(key.equals(curr.key)) {
if(curr.equals(head)) {
head = curr = null;
N--;
result = true;
return result;
} else {
prev.next = curr.next;
curr.setNext(null);
N--;
result = true;
return result;
}
} else {
prev = curr;
curr = curr.next;
}
}
return result;
}
}
I've written a main program to test for the add (put) and deletion, but it seems to be working for the insertion but not for the deletion. I think I might have a problem the deletion in case there is only one node in the list and the case of deleting a node from the middle of the list.
I'm also trying to modify the deletion method by writing a new method using the recursion, but I faced some errors -also logically. Here is the code of that function:
public void delete(Key key) {
first = delete(first, key);
}
private Node delete(Node x, Key key) {
if (x == null) return null;
if (key.equals(x.key)) {
N--;
return x.next;
}
x.next = delete(x.next, key);
return x;
}
Could you please tell me what did I do wrong?
head = curr = null;
This statement is a little confusing but I think it might be your problem for when deleting. If you're deleting a match that is at 'head', you just want to set head to 'curr.next'
What I think is going on:
delete(a)
a -> b -> c -> d
head = a
curr = a
curr.next = b
you set head to null, but head needs to point to the first item in the new list, which if you deleted 'a', would be 'b', or curr.next

What is wrong with this linked list?

The assignment was to write a function to swap 2 nodes in the list. If the function could swap the nodes regardless of the order, a 10% was awarded. I think my implementation is able to swap 2 elements regardless of the order in the list but I still did not received the bonus marks. Is there anything that I am missing?
I was given a generic node class,
public class Node<T> {
public T val;
public Node<T> next;
public Node(T val) {
this.val = val;
this.next = null;
}
}
I was also given an interface defined as below,
public interface SwapList<T> {
public void add(T val);
/**
* Swaps two elements in the list, but only if #param val1 comes BEFORE #param
* val2. Solve the problem regardless of the order, for 10% extra. list: A B
* C -> swap(A,B) will result in the list B A C list: A B C -> swap(B,A)
* will not swap. list: A C C -> swap(A, D) will throw a
* NoSuchElementException list: A B C B -> swap (A, B) will result in the
* list B A C B list: A B C A B B -> swap (A,B) will result in the list B A
* C A B B a list with one or zero elements cannot do a swap
*/
public void swap(T val1, T val2);
public T get(int i);
}
and I have my own implementation of this interface as below,
import java.util.NoSuchElementException;
public class SwapListImpl<T> implements SwapList<T> {
private Node<T> head;
private Node<T> tail;
private int counter;
public SwapListImpl() {
head = null;
tail = null;
counter = 0;
}
#Override
public void add(T val) {
Node<T> node = new Node<T>(val);
if (head == null) {
head = node;
tail = node;
} else {
tail.next = node;
tail = node;
}
counter++;
}
#Override
public void swap(T val1, T val2) {
if (counter < 2 || val1.equals(val2))
return;
Node<T> current = head;
Node<T> currentPrev = null;
Node<T> first = head;
Node<T> firstPrev = null;
Node<T> firstNext = first.next;
Node<T> second = head;
Node<T> secondPrev = null;
Node<T> secondNext = second.next;
boolean foundFirst = false;
boolean foundSecond = false;
boolean inOrder = false;
while (current != null) {
if (!foundFirst && current.val.equals(val1)) {
firstPrev = currentPrev;
first = current;
firstNext = current.next;
if (!foundSecond)
inOrder = true;
foundFirst = true;
}
if (!foundSecond && current.val.equals(val2)) {
secondPrev = currentPrev;
second = current;
secondNext = current.next;
if (foundFirst)
inOrder = true;
foundSecond = true;
}
if (foundFirst && foundSecond) {
if (!inOrder) {
Node<T> temp = first;
first = second;
second = temp;
temp = firstPrev;
firstPrev = secondPrev;
secondPrev = temp;
temp = firstNext;
firstNext = secondNext;
secondNext = temp;
}
if (firstPrev == null) {
head = second;
if (first == secondPrev) {
second.next = first;
first.next = secondNext;
} else {
second.next = firstNext;
secondPrev.next = first;
first.next = secondNext;
}
} else {
firstPrev.next = second;
first.next = secondNext;
if (first == secondPrev) {
second.next = first;
} else {
second.next = firstNext;
secondPrev.next = first;
}
}
break;
}
currentPrev = current;
current = current.next;
}
if (!foundFirst || !foundSecond) {
throw new NoSuchElementException();
}
}
#Override
public T get(int i) {
if (i < counter) {
Node<T> node = head;
for (int n = 0; n < i; n++) {
node = node.next;
}
return node.val;
} else {
throw new IndexOutOfBoundsException();
}
}
}
I think the problem is the swap itself: you forgot to set the tail.
Here is a small test for exactly that problem:
#Test
public void test() {
SwapListImpl<String> list = new SwapListImpl<String>();
list.add("A");
list.add("B");
list.add("C");
list.swap("A", "C");
assertEquals("C", list.get(0));
assertEquals("C", list.getHead().val);
assertEquals("B", list.get(1));
assertEquals("A", list.get(2));
assertEquals("A", list.getTail().val);
list.add("D");
assertEquals("C", list.get(0));
assertEquals("C", list.getHead().val);
assertEquals("B", list.get(1));
assertEquals("A", list.get(2));
assertEquals("D", list.get(3));
assertEquals("D", list.getTail().val);
list.swap("A", "C");
assertEquals("A", list.get(0));
assertEquals("A", list.getHead().val);
assertEquals("B", list.get(1));
assertEquals("C", list.get(2));
assertEquals("D", list.get(3));
assertEquals("D", list.getTail().val);
list.swap("C", "B");
assertEquals("A", list.get(0));
assertEquals("A", list.getHead().val);
assertEquals("C", list.get(1));
assertEquals("B", list.get(2));
assertEquals("D", list.get(3));
assertEquals("D", list.getTail().val);
}
You see I added two methods to the list, for getting the head and tail, but that's not important - the test would even fail without the explicit test for head and tail. The extra methods for the list are really simple:
public Node<T> getTail() {
return this.tail;
}
public Node<T> getHead() {
return this.head;
}
The problem of not setting tail occurs when swapping the last element of the list and then adding another element.
Here is a fixed version of the actual swap:
if (foundFirst && foundSecond) {
if (second == this.tail) {
this.tail = first;
} else if (first == this.tail) {
this.tail = second;
}
if (first == this.head) {
this.head = second;
} else if (second == this.head) {
this.head = first;
}
if (firstPrev == second) {
first.next = second;
} else {
if (firstPrev != null) {
firstPrev.next = second;
}
first.next = secondNext;
}
if (secondPrev == first) {
second.next = first;
} else {
if (secondPrev != first && secondPrev != null) {
secondPrev.next = first;
}
second.next = firstNext;
}
break;
}
You see I didn't add lines to your code - instead I wrote the code in another way. I think it's more readable, but you also can try just to set the tail in the correct way. But it was too complex for me, so I reduced the complexity of that code - that's the reason why I rewrote it.
I would suggest, that you use first and second for the first/second occurence and not for the first/second argument. I think that would improve the readability of the method. But that's another point ;-)
Hope that helps - so the order IMHO is not the problem, but the tail.

Categories

Resources