Write a simple LinkedList by yourself

Keywords: JDK less

I've written a brief version of ArrayList before, but now I'll go over a brief version of LinkedList (ps thinks that LinkedList in jdk source code has a lot of verbose and repetitive methods by looking at the source code).

  • First, LinkedList implements a linked list. A linked list defined by this class can also be used like a stack or queue. This is Baidu Encyclopedia. So we first need to create a new linked list class. Since this linked list class is only used in LinkedList, it adopts the static internal class approach.
    /**
     * A linked list is a discontinuous and non-sequential storage structure on a physical storage unit. The logical order of data elements is realized by the order of pointer links in the linked list.
     * Linked lists allow insertion and removal of nodes at any location on the table, but do not allow random access.
     *
     * @param <E>
     */
    private static class Entry<E>{
        E element;
        Entry<E> next;
        Entry<E> previous;
        Entry(E element, Entry<E> next, Entry<E> previous) {
            this.element = element;
            this.next = next;
            this.previous = previous;
        }
    }

To distinguish it from the LinkedList of the JDK source code, my class is called SimpleLinkedList.

  • Define a header as the beginning of a collection
    private Entry<E> header = new Entry<E>(null,null,null);

  • Constructor initialization set

    public SimpleLinkedList(){
        header.next = header;
        header.previous = header;
    }
  • Add elements at the end of the list
    public boolean add(E e){
        addBefore(e, header);
        return true;
    }

Implementation of public method addBefore(E,Entry)

    private Entry<E> addBefore(E e,Entry<E> entry){
        Entry<E> newEntry = new Entry<E>(e,entry,entry.previous);
        newEntry.previous.next=newEntry;
        newEntry.next.previous=newEntry;
        size++;
        return newEntry;
    }
  • Add elements to the head of the list
public void addFirst(E e){
        addBefore(e, header.next);
    }

In fact, there is another method addLast(E) in JDK, just like the add() method, which is not listed here.

  • Get elements
    Get the first and last element, because of the list structure, header acts as a zero boundary, and the next one points to the first element; the last one points to the last.
    public E getFirst(){
        return header.next.element;
    }

    public E getLast(){
        return header.previous.element;
    }
  • Getting elements from a specified location (Random fetching elements is inefficient compared to ArrayList)
public E get(int index){
        return entry(index).element;
    }

Common code entry(int)

private Entry<E> entry(int index) {
        Entry<E> e = header;
        if(index < (size >>1)){
            for(int i=0;i<=index;i++){
                e = e.next;
            }
        }else{
            for(int i=size; i>index; i--){
                e = e.previous;
            }
        }
        return e;
    }

If the index to be retrieved is less than half of the list size (move one bit to the right), the index position is found at the beginning of 0, and the index is found at the end if it is larger than size.

  • Replace the set method of the specified location element
public E set(int index,E e){
        Entry<E> entry = entry(index);
        E oldE = entry.element;
        entry.element = e;
        return oldE;
    }
  • Removing Elements
public E remove(int index){
        return remove(entry(index));
    }
    public E removeFirst(){
        return remove(header.next);
    }
    public E removeLast(){
        return remove(header.previous);
    }

    private E remove(Entry<E> e){
        if(e==header){
            throw new NoSuchElementException();
        }
        E result = e.element;
        e.next.previous = e.previous;
        e.previous.next = e.next;
        e.next = e.previous = null;
        e.element = null;
        size--;
        return result;
    }

In addition, after JDK 1.5, some Queue-related methods such as pop, peek,push and so on were added. I have implemented several simple methods, which are generally not good as the above methods. Here is the complete source code

/**
 * Implementation of Simulated LinkedList
 * 
 *
 */
public class SimpleLinkedList<E> {
    private int size = 0;
    private Entry<E> header = new Entry<E>(null,null,null);

    public SimpleLinkedList(){
        header.next = header;
        header.previous = header;
    }
    /**
     * Add an element at the end of the list
     * Implementing principle, adding a node before header each time
     * @param e
     * @return
     */
    public boolean add(E e){
        addBefore(e, header);
        return true;
    }
    /**
     * Add elements at the beginning of the list
     * @param e
     */
    public void addFirst(E e){
        addBefore(e, header.next);
    }
    /**
     * Double linked list structure, the next header, is just the first one of the linked list.
     *         header The last one, on the contrary, is the last element.
     * @return
     */
    public E getFirst(){
        return header.next.element;
    }

    public E getLast(){
        return header.previous.element;
    }

    public int size(){
        return size;
    }

    /**
     * Returns the element of the specified coordinate
     */
    public E get(int index){
        return entry(index).element;
    }

    private Entry<E> entry(int index) {
        Entry<E> e = header;
        /**
         * To move one bit to the right is equivalent to dividing it by two.
         * If the coordinates are less than half the length, start at 0 and find the current coordinates until you return to the next one of the current e.
         * If the coordinate to be searched is more than half the length of the list, find the first coordinate from the end and return to the last coordinate of the current e.
         */
        if(index < (size >>1)){
            for(int i=0;i<=index;i++){
                e = e.next;
            }
        }else{
            for(int i=size; i>index; i--){
                e = e.previous;
            }
        }
        return e;
    }
    /**
     * Replacement of elements with specified coordinates
     * @param index
     * @param e
     * @return
     */
    public E set(int index,E e){
        Entry<E> entry = entry(index);
        E oldE = entry.element;
        entry.element = e;
        return oldE;
    }

    public E remove(int index){
        return remove(entry(index));
    }
    public E removeFirst(){
        return remove(header.next);
    }
    public E removeLast(){
        return remove(header.previous);
    }

    private E remove(Entry<E> e){
        if(e==header){
            throw new NoSuchElementException();
        }
        E result = e.element;
        e.next.previous = e.previous;
        e.previous.next = e.next;
        e.next = e.previous = null;
        e.element = null;
        size--;
        return result;
    }




    //Some Methods of queue
    /**
     * add The difference between offer and offer is that
     * When the queue is empty add, offer returns false
     * LinkedList There is also a difference. add is the list method and offer is the Queue method.
     * @param e
     * @return
     */
    public boolean offer(E e){
        return add(e);
    }

    /**
     * Push elements into the stack represented by this list.
     * It's actually adding elements at the beginning of the list.
     * Rules for heap entry and exit, first in, last out
     * @param e
     */
    public void push(E e){
        addFirst(e);
    }
    /**
     * An element pops up at the stack represented by this list.
     * It's actually an element popping up from the head.
     * @return
     */
    public E pop(){
        return removeFirst();
    }
    /**
     * Get the first element, as opposed to pop, which does not delete the element
     * @return
     */
    public E peek(){
        if(size ==0){
            return null;
        }
        return getFirst();
    }

    /**
     * A linked list is a discontinuous and non-sequential storage structure on a physical storage unit. The logical order of data elements is realized by the order of pointer links in the linked list.
     * Linked lists allow insertion and removal of nodes at any location on the table, but do not allow random access.
     *
     * @param <E>
     */
    private static class Entry<E>{
        E element;
        Entry<E> next;
        Entry<E> previous;
        Entry(E element, Entry<E> next, Entry<E> previous) {
            this.element = element;
            this.next = next;
            this.previous = previous;
        }
    }
    private Entry<E> addBefore(E e,Entry<E> entry){
        Entry<E> newEntry = new Entry<E>(e,entry,entry.previous);
        newEntry.previous.next=newEntry;
        newEntry.next.previous=newEntry;
        size++;
        return newEntry;
    }

}

Posted by derezzz on Mon, 20 May 2019 13:36:34 -0700