简体   繁体   中英

Custom LinkedList in Java with a maintained order of insertion

I was trying to implement a linked list in Java. I came up with the following simple implementation

public class Node{
  public String data;
  public Node next;
  public Node(String data){
     this.data = data  
  }
}

public class LinkedLst{
  public Node currentNode;

  public void add(String data){
    Node newNode = new Node(data);
    newNode.next = currentNode;
    currentNode = newNode;
  }
  public Node remove(){
    Node temp = currentNode;
    currentNode = currentNode.next;
    return temp;
  }
  public void printList(){
    Node temp = currentNode;
    while(temp!=null){
      System.out.println(temp.data + ",");
      temp = temp.next;
    }
  }
}

But one obvious problem I see here is that the order of insertion gets reversed due to my design flaw. But in a LinkedList, the order of insertion should be maintained. How would I change this code to do that. I just could not think from a different perspective now.

Try analyzing the problem one step at a time.

Let us assume that you want to add the following number sequence into your list - 1, 2, 3, 4, 5. What EXACTLY happens?

There is only one field (currentNode) in an object of your LinkedList class. Let's try visualizing it like this;

LinkedList
  currentNode = null

At this point, we don't have any data in the list. Now let's insert the first node (I'm assigning letters to represent them).

LinkedList
  currentNode = A

The list sequence itself would look like this;

null <- A(value = 1)

Now lets add the second data into the list. Note what happens;

LinkedList
  currentNode = B

And the list sequence becomes;

null <- A(value = 1) <- B(value = 2)

And a few more elements and you get this situation

LinkedList
  currentNode = E

with the sequence being;

null <- A(value = 1) <- B(value = 2) <- C(value = 3) <- D(value = 4) <- E(value = 5)

In this situation, what is the ONLY order with which you can traverse the list? In reverse. Why? Because you are only storing the LAST (or tail) node of the list. If you want to retrieve the original order, you'll need to change your logic so that instead of the tail, you are storing the HEAD of the list. For starters, let's rename the field in your class as follows;

public class LinkedList {
    public Node HEAD;
}

The next change we'll need to address is your add() method. Think with the end objective in mind. How do you want to store things in the list? I suspect this is what you are looking for;

A(value = 1) -> B(value = 2) -> C(value = 3) -> D(value = 4) -> E(value = 5) -> null

If you have the first element in the above list (HEAD = A), how would you go about adding a new element to the list? You would need to traverse the list till you reach the last node and insert your new value there. So your function would become;

public void add(String data) {
    Node newNode = new Node(data);
    // check if HEAD is empty or not
    if (HEAD == null) {
        HEAD = newNode;
        return;
    }
    Node temp = HEAD;
    while(temp.next != null) {
        temp = temp.next;
    }
    // we must be at the end of the list now.
    // add the next element in here.
    temp.next = newNode;
}

To verify this, a small change in your print function is needed (to use HEAD instead of currentNode). The final class would look like this;

public class LinkedList {
    public Node HEAD;

    public void add(String data) {
        Node newNode = new Node(data);
        // check if HEAD is empty or not
        if (HEAD == null) {
            HEAD = newNode;
            return;
        }
        Node temp = HEAD;
        while(temp.next != null) {
            temp = temp.next;
        }
        // we must be at the end of the list now.
        // add the next element in here.
        temp.next = newNode;
    }

    public void printList() {
        Node temp = HEAD;
        while(temp != null) {
            System.out.print(temp.data + " -> " );
            temp = temp.next;
        }
    }
}

As far as the remove() method is concerned ... I'll leave that to you as an exercise. Can't just give everything away, now can we? ;)

Try this. But again you need to check cases where in remove is called without adding any element where in there is a possibility of NPE in your code you need to handle those scenarios and also about thread safety and performance of your list:-

package com.test.java;

import java.util.concurrent.atomic.AtomicInteger;

class Node<T> {
    T data;
    Node next;  
    int index;
    static AtomicInteger position = new AtomicInteger();
    public Node(T data){
        this.data = data;
        this.index = position.incrementAndGet(); 
    }
    @Override
    public String toString() {      
        return data.toString();
    }
}

public class LinkedLst<T> {
    private Node currentNode;

    public void add(T data){
        Node newNode = new Node(data);
        newNode.next = currentNode;
        currentNode = newNode;
    }

    public Node remove(){
        Node temp = currentNode;
        currentNode = currentNode.next;
        return temp;
    }

    public Node get(int index) {
        Node temp = currentNode;
        while(temp!=null){
            if(index == temp.index) {
                return temp;
            }
            temp = temp.next;
        }
        return null;
    }

    public void printList(){
        Node temp = currentNode;
        while(temp!=null){
            System.out.println(temp.data + ",");
            temp = temp.next;
        }
    }
}

What about:

public void add(String data){
  Node newNode = new Node(data);
  newNode.next = currentNode.next;
  currentNode.next = newNode;
} 

I came up with the following implementation.

public class LinkedLst {
    public Node head;
    public Node prev;
    public Node last;

    public void add(String data) {
        Node newNode = new Node(data);
        if(head == null){
            head = newNode;
            prev = newNode;
            last = newNode;
            return;
        }else if(head == last){
            prev.next = newNode;
            last = newNode;
            return;
        }
        prev = prev.next;
        prev.next = newNode;
        last = newNode;
    }

    public void fwdPrintList() {
       Node temp = head;
       while (temp!=null){
           System.out.println(temp.data);
           temp = temp.next;
       }
    }

    public Node remove(){
        if(isEmpty()){
            System.out.println("List is Empty");
            return head;
        }
        Node temp = head;
        head = head.next;
        return temp;
    }
    public boolean contains(String data) {
        Node temp = head;
        while (temp!=null){
            if (temp.data.equals(data)) {
                return true;
            }
        temp = temp.next;
        }
        return false;
    }

    public boolean isEmpty(){
        if(head==null){
            return true;
        }
        return false;
    }
}

and it works fine.

Most LinkedLists are implemented with a head and tail . Elements are added to end of the linked list, and read from the front of the linked list.

For example:

private Node head = new Node(null);
private Node tail = head;

public void add(Object o) {
    Node node = new Node(o);
    tail.next = node;
    tail = node; // Swing tail to the added node
}

public Object peek() {
    if (head != tail)
        return head.next.value; // Value of the next node
    return null; // Empty
}

public Object poll() {
    if (head != tail) {
        Object o = head.next.value;
        head = head.next;
        return o;
    }
    return null; // Empty
}

Objects in the head position should not be read.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM