Adding an element to a singly linked list in Java - java

I'm implementing a singly linked list in Java. What I don't like about this code is that I need to check if (head.next == null) every time I add an element. But the condition is met only once, when adding the first element.
Is there a way to implement a singly linked non-circular list without such a condition?
package sample;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class SinglyLinkedList<T> implements Iterable<T> {
private Node<T> head = new Node<T>(null);
private Node<T> last = null;
public SinglyLinkedList(T... elements) {
addAll(elements);
}
public void add(T element) {
if (head.next == null) {
head.next = new Node<T>(element);
last = head.next;
} else {
Node<T> newNode = new Node<T>(element);
last.next = newNode;
last = last.next;
}
}
public void addAll(T... elements) {
for (T element : elements) {
add(element);
}
}
#Override
public String toString() {
Iterator<T> iterator = iterator();
if (!iterator.hasNext()) {
return "[]";
}
StringBuilder builder = new StringBuilder();
builder.append("[");
while (iterator.hasNext()) {
T element = iterator.next();
builder.append(element);
if (!iterator.hasNext()) {
return builder.append("]").toString();
}
builder.append(", ");
}
return builder.toString();
}
#Override
public Iterator<T> iterator() {
return new Iterator<T>() {
Node<T> current = head;
#Override
public boolean hasNext() {
return current.next != null;
}
#Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
Node<T> temp = current;
current = current.next;
return temp.next.element;
}
};
}
private static class Node<T> {
private Node<T> next;
private T element;
Node(T element) {
this.element = element;
}
#Override
public String toString() {
return element.toString();
}
}
}

You could initialize last to be pointing to head and then your if is redundant:
private Node<T> head = new Node<T>(null);
private Node<T> last = head;
public void add(T element) {
Node<T> newNode = new Node<T>(element);
last.next = newNode;
last = last.next;
}

There are many cases where "good OO design" allows you to go without if/else checks; most often by using some form of polymorphism.
Meaning: instead of asking some object about some property, to then make a decision on that in your client code, you somehow make sure that your client code can simply call a method on some other object. And then, the "if" is "hidden" within the code that initially generated that "other object" and gave it to your client code. (you find some nice examples how that works in these videos).
But - I think this would be clear overkill in this case!
The point is: from a readability point of view, that one check really doesn't hurt (you could refactor things into more methods maybe). And performance ... doesn't matter either. If your code is called so often that it would matter, the JIT will kick in anyway, and probably create code that that takes the correct branch directly for most cases.
Thus: this is a nice implementation; and I think you shouldn't worry about this one if-check there!

Related

How to iterate over a Queue I implemented myself?

I'm trying to debug a part of a program that peeks at a queue object from a queue class I implemented myself, so I'm trying to iterate over it and print out all the elements to see what's wrong without altering the queue. How can I do this?
My Queue class (QueueLinkedList is the name):
public class QueueLinkedList<Customer> implements Queue<Customer> {
Node first, last;
public class Node {
Customer ele;
Node next;
}
public QueueLinkedList() {}
public boolean isEmpty() {
return first == null;
}
public QueueLinkedList<Customer> enqueue(Customer ele) {
Node current = last;
last = new Node();
last.ele = ele;
last.next = null;
if (current == null)
first = last;
else
current.next = last;
return this;
}
public Customer dequeue() {
if (isEmpty())
throw new java.util.NoSuchElementException();
Customer ele = first.ele;
first = first.next;
return ele;
}
public Customer peek() {
Customer ele = first.ele;
return ele;
}
You're using a linked-list to implement your queue. You can iterate over it just like you would iterate over any linked-list.
public void iterate() {
Node iterator = first;
while(iterator != null) {
Customer customer = iterator.ele;
// do something with the customer
iterator = iterator.next;
}
}
Edit: If your use case needs returning the iterator then ideally you should implement the Iterable interface. That solution is already mentioned in one other answer. For the sake of extending this answer to your use case I'm providing the below code. It would work, but its NOT an "Object-Oriented" way of doing it.
public class QueueLinkedList<Customer> implements Queue<Customer> {
private Node iterator;
// ...
public QueueLinkedList() {
iterator = null;
// ...
}
public Node iterator() {
iterator = first;
return iterator;
}
public boolean hasNext() {
return iterator != null;
}
public Node next() {
if(!hasNext()) {
throw new NoSuchElementException();
}
Node next = iterator;
iterator = iterator.next();
return next;
}
}
Usage:
QueueLinkedList queue = new QueueLinkedList();
// ...
Node iterator = queue.iterator();
while(queue.hasNext()) {
Node next = queue.next();
Customer customer = next.ele;
// do something with the customer
}
You need to implement Iterable<Customer> in your queue, as shown below, so that your queue can be iterated the same as arrays and other Java collections.
import java.util.*;
public class QueueLinkedList<Customer>
implements Queue<Customer>, Iterable<Customer>
{
Node first, last;
public class Node {
Customer ele;
Node next;
}
class Iter implements Iterator<Customer> {
Node current = first;
public boolean hasNext() {
return current != null;
}
public Customer next() {
if (!hasNext())
throw new NoSuchElementException();
Customer next = current.ele;
current = current.next;
return next;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
public QueueLinkedList() {}
public boolean isEmpty() {
return first == null;
}
public QueueLinkedList<Customer> enqueue(Customer ele) {
Node current = last;
last = new Node();
last.ele = ele;
last.next = null;
if (current == null)
first = last;
else
current.next = last;
return this;
}
public Customer dequeue() {
if (isEmpty())
throw new java.util.NoSuchElementException();
Customer ele = first.ele;
first = first.next;
return ele;
}
public Iterator<Customer> iterator {
return new Iter();
}
}
Note that the way you have declared your class, Customer is a generic type parameter, not the class Customer. This is actually a good thing as it means you can use your QueueLinkedList class with any data type. To make it clear that Customer is a type parameter, you should replace every occurrence of Customer with a class variable name comprised of a single uppercase letter such as E.
Alternatively, if you want QueueLinkedList to always be a queue of Customer objects, you should change the class declaration to:
public class QueueLinkedList
implements Queue<Customer>, Iterable<Customer>

Linked List using generics, getting "not applicable arguments for parameters" error

My Node class:
public class Node<T>
{
protected T data;
protected Node<T> next;
protected Node<T> previous;
public Node()
{
this.data = null;
this.next = null;
this.previous = null;
}
public Node(T data)
{
this.data = data;
this.next = null;
this.previous = null;
}
public Node(T data, Node<T> next, Node<T> previous)
{
this.data = data;
this.next = next;
this.previous = previous;
}
public T getData()
{
return data;
}
public void setData(T data)
{
this.data = data;
}
public Node<T> getNext()
{
return next;
}
public void setNext(Node<T> next)
{
this.next = next;
}
public Node<T> getPrevious()
{
return previous;
}
public void setPrevious(Node<T> previous)
{
this.previous = previous;
}
}
My LinkedList class:
public class LinkedList<T extends Node<T>>
{
private Node<T> head;
private Node<T> tail;
private Node<T> currNode;
public LinkedList()
{
head = null;
tail = null;
currNode = null;
}
public LinkedList(Node<T> head)
{
this.head = head;
tail = head;
currNode = head;
}
public void resetHead()
{
currNode = head;
}
public void add(T data)
{
Node<T> newNode = new Node<T>(data);
newNode.next = null;
if(head == null)
{
head = newNode;
}
else
{
tail.next = newNode;
newNode.previous = tail;
tail = newNode;
}
}
public void addHead(T data)
{
Node<T> newNode = new Node<T>(data);
newNode.next = head;
head.previous = newNode;
head = newNode;
}
public void addAfter(T data, Node<T> previousNode)
{
Node<T> newNode = new Node<T>(data);
newNode.next = previousNode.next;
previousNode.next = newNode;
}
public void addBefore(T data, Node<T> nextNode)
{
Node<T> newNode = new Node<T>(data);
newNode.next = nextNode;
nextNode.previous = newNode;
}
public void delete(Node<T> nodeToDelete)
{
(nodeToDelete.getNext()).setPrevious(nodeToDelete.getPrevious());
(nodeToDelete.getPrevious()).setNext(nodeToDelete.getNext());
nodeToDelete.setNext(null);
nodeToDelete.setPrevious(null);
}
public boolean hasNext()
{
if(head == null)
{
return false;
}
else if(currNode.next != null)
{
currNode = currNode.getNext();
return true;
}
else
{
return false;
}
}
public boolean hasPrevious()
{
if(tail == null)
{
return false;
}
else if(currNode.previous != null)
{
currNode = currNode.getPrevious();
return true;
}
else
{
return false;
}
}
public Node<T> getHead()
{
return head;
}
public void setHead(Node<T> head)
{
this.head = head;
}
public Node<T> getTail()
{
return tail;
}
public void setTail(Node<T> tail)
{
this.tail = tail;
}
public Node<T> getCurrNode()
{
return currNode;
}
public void setCurrNode(Node<T> currNode)
{
this.currNode = currNode;
}
}
The error crops up when attempting to use any of the add/insert methods in LinkedList. For example, if I try to use the add(T data) method, like so: listOfChars.add('B');, I get the following error: The method add(Node) in the type LinkedList is not applicable for the arguments (char). What I expect it to do is to accept the data (in this case, the char 'B'), create a new node with 'B' as the data, and then put it in the linked list after the last node in the list. From my understanding, the method is expecting a Node instead of any generic data type, such as a char.
After doing some researching, I think somewhere in my TestLinkedList class, I have declared the LinkedList object incorrectly:
public class TestLinkedList
{
public static void main(String[]args)
{
Node<Character> n1 = new Node<Character>('A');
LinkedList listOfChars = new LinkedList(n1);
listOfChars.add('B');
}
}
but I can't figure out how to declare it correctly. I've tried LinkedList<Character>, LinkedList<Node>, LinkedList<Node<T>>, and LinkedList<Node<Character>>, but none of them are correct. Any help would be appreciated as this is my first time using generics and I am just trying to learn how to apply it to a Linked List I've made.
You need to fix two things. First, the class declaration of LinkedList says:
public class LinkedList<T extends Node<T>> {
which means that T has to be both a Node and the element of a Node. This doesn't work with Character since a Character is not an instance of Node. If you remove the constraint so that T can be any value, it works with Character.
public class LinkedList<T> {
Next you should add the generic part to the main file for the listOfChars as well:
LinkedList<Character> listOfChars = new LinkedList<Character>(n1);
Also make sure that you have imported the right LinkedList and not the java standard class.
You simply have to rewrite LinkedList from
LinkedList<T extends Node<T>>
to
LinkedList<T>
since in the code of LinkedList you already state that you are using Node objects.
You can use it like this:
public static void main(String[]args)
{
Node<Character> n1 = new Node<>('A');
LinkedList<Character> listOfChars = new LinkedList<>(n1);
listOfChars.add('B');
}
I think its a combination of both Todd's and Adams answer
public class LinkedList<T extends Node<T>>
to
public class LinkedList<T>
and
LinkedList<Character> listOfChars = new LinkedList<>(n1);
As you can infer from the error The method add(Node) in the type LinkedList is not applicable for the arguments (char)
This is a type error, your add method expects a Node but in the main you call add with type character.
Your LinkedList class is expecting an object of type T extends Node. Which would imply a custom class that extends your Node object, however that is not what you are looking to use to add objects to the linkedlist.
Ok, so your class declaration
public class LinkedList<T extends Node<T>>
is saying 'This is a class LinkedList parameterised by T where T is a subtype of Node<T>
This means if you wanted T = Character for example, you would need Character to be a subtype of Node<Character>, which doesn't really make sense.
You probably want to just parameterise your class by T eg public class LinkedList<T>
Then you can go LinkedList<Character> listOfChars = new LinkedList<Character>(n1)
or more succinctly LinkedList<Character> listOfChars = new LinkedList<>(n1) as the second generic parameter can be inferred
Create your LinkedList like this:
LinkedList<Character> listOfChars = new LinkedList<>(n1);
EDIT:
M4ver1k is right that this alone won't fix it. I missed the part that Adam Arold pointed out. Adam's answer fixes the problem and should be accepted. My answer just prevents the LinkedList from being implicitly defined as a LinkedList<Object>.
.

Sorted Stack in Java

I'm trying to implement a stack that keeps the items in a sorted manner and returns the least element in every pop. I'm using two stacks to implement the sorted stack.
Here's my implementation of the plain vanilla stack.
public class Stack<T> implements Iterable{
private Node head;
#Override
public Iterator iterator() {
return new StackIterator();
}
private class Node<T extends Comparable<T>>{
private T data;
private Node next;
public Node(T data){
this.data = data;
next = null;
}
public int compareTo(T other){
return data.compareTo(other);
}
}
private class StackIterator<T> implements Iterator<T> {
Node current = head;
#Override
public boolean hasNext() {
return (current != null);
}
#Override
public T next() {
T item = (T) current.data;
current = current.next;
return item;
}
}
public void push(T item){
Node p = new Node((Comparable) item);
if(head == null){
head = p;
return;
}
p.next = head;
head = p;
}
public T pop(){
if(head == null){
System.out.println("Popping off an empty stack!!!");
System.exit(-1);
}
T item = (T) head.data;
head = head.next;
return item;
}
}
This stack is used in the SortedStack. Here's the partial code.
public class SortedStack<T> {
private int size;
private Stack<T> s1;
private Stack<T> s2;
public SortedStack(){
s1 = new Stack<>();
s1 = new Stack<>();
size = 0;
}
public void push(T item){
for (Iterator<T> iter = s1.iterator(); iter.hasNext(); iter.next()){
if (iter.compareTo(item) > 0){
s2.push(s1.pop());
}else if(iter.compareTo(item) < 0){
s1.push(item);
break;
}else{
s1.push(item);
break;
}
}
for (Iterator<T> iter = s2.iterator(); iter.hasNext(); iter.next()){
s1.push(s2.pop());
}
}
public T pop(){
}
}
The problem is the T(Object) comparison of the nodes doesn't get resolved in the SortedStack. The compareTo doesn't work. This is understandably because of the fact that Node is an inner private class of Stack. My question is how can I expose the compareTo method of the Node class to the SortedStack for implementing it's logic without indiscriminately making everything public?
You have many mistakes in your code.
For example, why are you trying to compare an iterator to an item?
Also, the logic is broken: you compare an item being inserted to s1's head, and then push it to the tail.
As long as the first item inserted is the smallest of all, all the others will always end up in the insertion order.
Consider inserting 0, then 3, then 1 for example.
To answer your question, you want your extends Comparable<T> type boundary on the SortedStack declaration, not on Node.
Node does not need to be Comparable at all.
If this is not for homework, just use TreeSet instead.

removing from a linked list

I made an SListClass which stands for sinle-linked list class and a node class SListNode. I'm having a problem with the removeLast method. When I print out the list of nodes, the first item is still there. I don't understand why
public class SListClass {
private SListNode head;
private double size;
SListClass(){
head = null;
size = 0;
}
SListClass(SListNode node){
head = node;
}
public void insertFront(int item){
head = new SListNode(item, head);
size++;
}
public void addLast(SListNode head, int value){
SListNode first = head;
while(first.next != null){
first = first.next;
}
first.next = new SListNode(value, null);
size++;
}
public void removeFirst(SListNode head){
head = head.next;
}
/*public String toString(){
return String.format(head + "");
}
*/
public String print(){
String result = head.item + " ";
if(head.next != null){
result += head.next.print();
}
return result;
}
public static void main(String[] args) {
SListNode list = new SListNode(21, new SListNode(5, new SListNode(19, null)));
SListClass x = new SListClass(list);
x.insertFront(33);
x.insertFront(100);
x.addLast(list, 123);
x.addLast(list, 9999);
x.removeFirst(list);
System.out.println(x.print());
}
}
output: 100 33 21 5 19 123 9999
The SListNode class:
public class SListNode {
protected int item;
protected SListNode next;
public SListNode(int item, SListNode next){
this.item = item;
this.next = next;
}
public SListNode(int item){
this(item, null);
}
public int getItem() {
return item;
}
public void setItem(int item) {
this.item = item;
}
public SListNode getNext() {
return next;
}
public void setNext(SListNode next) {
this.next = next;
}
}
Change the removeFirst to this.head = head.next. The head in the parameter list is hiding the class field head.
Also, consider this: in a removeFirst method, do you really want a head parameter, or should you use the head field instead since that is the real head for the linked list you are trying to update? If you don't want that parameter anymore, just delete the parameter from the method signature; then the field head is not hidden, so head = head.next does fine.
First of all, your naming is bad. Every class is a class, so ending the name of a class with Class is just noise. On the contrary S doesn't mean anything. If you must explain what SListClass stands for, then it means that the name is bad, and that you should choose another name, which doesn't need any explanation, like SinglyLinkedList.
The users of your class shouldn't care how the list retains the information. It should never have to pass a Node to any method. Only a value. So the following methods should be modified:
SListClass(SListNode node) --> SinglyLinkedList(int value)
void addLast(SListNode head, int value) --> void addLast(int value) : the list knows what the head node is. It makes no sense to pass it as argument.
void removeFirst(SListNode head) --> void removeFirst() : the list knows what the first node is. It makes no sense to pass it as argument
Once you get the API right, you'll see that everything will be much easier to figure out, because you won't confuse the actual head of the list with the unnecessary head passed as argument.

Implementing generic linkedlist add method java

I am trying to implement the add method for the linkedlist , it should take any data type, but I am kind of lost and is not working, any help will be appreciated.
public class LinkedList <T>extends AbstractList {
private class Node {
T data;
Node next;
Node(T data, Node next) {
this.data = data;
this.next = next;
}
Node(T data) {
this(data, null);
}
}
Node first;
Node last;
public LinkedList() {
first = null;
last = null;
}
#Override
public boolean add(T item) {
Node newNode = new Node((T)item);
if (isEmpty()) {
first = newNode;
last = first;
return true;
}
last.next = newNode;
last = null;
return true;
}
}
You don't tell us your concrete problem, so we can't fix it, only guess.
One issue I see though is that you extend AbstractList as a raw (nongeneric) type - your declaration should be instead
public class LinkedList<T> extends AbstractList<T> { ... }
You need:
last.next = newNode;
last = newNode;
Be careful that you understand why.
Before you add the new node, last is a reference to the last entry in the list.
What you want to do is to point its next reference to this new node.
The second line then updates last to refer to this new one too.

Categories

Resources