Handwritten one-way linked list

Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/Mr__Viking/article/details/89450613

A data structure for programmers is essential knowledge, although before also understand these data structures, but did not reach a total feeling of all the data structures are well aware of the state, so the author intends to achieve a variety of handwritten data structures, in order to learning to understand the whole picture of these data structures.

For in-depth analysis of the data structure if enough, then there must also involve jvm memory level, currently I do not have enough stock of knowledge, so just learn to understand these data structures to achieve the level from code.

The most simple one-way start list as a start, the most basic way linked list belonging to the list structure, which is defined as: list is a physical storage unit on a non-continuous, non-sequential storage structure , data elements Logic sequence through the list of pointers link the order achieved. Chain by a series of nodes (each node element is called a linked list), with the node can be dynamically generated at runtime. Each node consists of two parts: a storage data element of the data field, the other is to store a next node address pointer field. - Introduction from Baidu Encyclopedia

                                    

                                                                                 List structural diagram

 

With my understanding, the node list is composed of one belt link, each node consists of two parts, a first part of the data storage node, the second part is a pointer to the next node in the node. Such a structure we need to know first node of the list, one by one so we can get the entire list of all nodes.

List of features:

  1. No capacity constraints
  2. No expansion of demand
  3. Operating two fast, slow intermediate
  4. Thread safe

List of actions:

1. Insert a new node: a node pointer to the Next node insertion position assigned to the Next pointer of the newly inserted node, Next pointer then points to a node of the new node. The operation is complete.

                      

                                                                     A schematic view of the new node is inserted

2. Delete Node: Next pointer assignment on a node to node to be removed for the position you want to delete a node Next node pointer can be.

                              

                                                                               Schematic delete nodes

 

It is seen from the above diagram, if the operation head and tail of the list, then the operation speed is the fastest, and if the operation of the intermediate position in the list, the list will traverse operation.

He said a bunch of crap, let's start talking in code

The list of code implementation:

package dataStructure;

import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Consumer;

/**
 * Created by Viking on 2019/4/7
 * 实现的单向链表的集合
 * 只能从前往后单向遍历
 * 可插入重复元素
 * 实现迭代器遍历集合
 */
public class MySingleLinkList<E> {

    private transient int modCount = 0;
    private transient int size;
    private Node<E> first;
    private Node<E> last;

    public void addLast(E e){
        linkLast(e);
    }
    public E removeLast(){
        if (size==0) throw new NoSuchElementException();
       return unlinkLast(last);
    }
    public E remove(int index){
        return unlink(index);
    }
    public E getFirst(){
        return first.item;
    }
    public E getLast(){
        return last.item;
    }
    public E get(int index){
        checkElementIndex(index);
        return node(index).item;
    }

    /**
     * 向最后一个元素添加链接.
     */
    private void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }
    /**
     * 取消指向最后一个元素的链接.
     */
    private E unlinkLast(Node<E> l) {
        if (first==last&&first!=null) {
            first = null;
            last = null;
        }else if (first!=null) {
            Node<E> node = first;
            int i = 1;
            while (node.next!=null){
                if (node.next==l&&i==size-1) {
                    node.next = null;
                    last = node;
                }else  node = node.next;
                i++;
            }
        }
        size--;
        modCount++;
        return l.item;
    }

    /**
     * 取消指定索引的节点
     */
    private E unlink(int index){
        checkElementIndex(index);
        Node<E> cursor;
        if (index==0 && index==size-1){
            cursor = first;
            first = null;
            last = null;
        }else if (index==0) {
            cursor =first;
            first = cursor.next;
        }else if (0 < index && index < size-1){
            Node<E> node = first;
            for (int i =0;i<index-1;i++) node = node.next;
            cursor = node.next;
            node.next = cursor.next;
        }else {
            cursor = last;
            last = node(index-1);
            last.next = null;
        }
        size--;
        modCount++;
        return cursor.item;
    }
    /**
     * 判断指定索引是否存在元素.
     */
    private boolean isElementIndex(int index) {
        return index >= 0 && index < size;
    }
    private void checkElementIndex(int index) {
        if (!isElementIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    /**
     * 返回指定索引的元素.
     */
    private Node<E> node(int index){
        Node<E> node = first;
        for (int i =0;i<index;i++) node = node.next;
        return node;
    }
    /**
     * Constructs an IndexOutOfBoundsException detail message.
     * Of the many possible refactorings of the error handling code,
     * this "outlining" performs best with both server and client VMs.
     */
    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }
    public int size(){
        return size;
    }
    public boolean isEmpty(){
        return size==0;
    }
    public String toString(){
        StringBuilder str = new StringBuilder();
        if (first==null){
            str.append("[]");
        }else {
            Node<E> next = first;
            str.append("[");
            str.append(first.item);
            while (next.next!=null){
                next = next.next;
                str.append(",");
                str.append(next.item);
            }
            str.append("]");
        }
        return str.toString();
    }

    /**
     * 链表的节点
     */
    private static class Node<E> {
        E item;
        Node<E> next;

        Node(E element, Node<E> next) {
            this.item = element;
            this.next = next;
        }
    }

    public Iterator<E> myIterator(){
        return new MyIterator(0);
    }
    public Iterator<E> myIterator(int index){
        return new MyIterator(index);
    }

    /**
     * 实现迭代器遍历容器
     */
    private class MyIterator implements Iterator<E>{
        private Node<E> lastReturned;
        private Node<E> next;
        private int nextIndex;
        private int expectedModCount = modCount;
        private MyIterator(int index){
            next = index == size ? null : node(index);
            nextIndex = index;

        }
        @Override
        public boolean hasNext() {
            return nextIndex < size;
        }

        @Override
        public E next() {
            checkForComodification();
            if (!hasNext())
                throw new NoSuchElementException();

            lastReturned = next;
            next = next.next;
            nextIndex++;
            return lastReturned.item;
        }

        @Override
        public void remove() {
            checkForComodification();
            if (lastReturned == null)
                throw new IllegalStateException();

            Node<E> lastNext = lastReturned.next;
            unlink(nextIndex-1);
            if (next == lastReturned)
                next = lastNext;
            else
                nextIndex--;
            lastReturned = null;
            expectedModCount++;
        }

        @Override
        public void forEachRemaining(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            while (modCount == expectedModCount && nextIndex < size) {
                action.accept(next.item);
                lastReturned = next;
                next = next.next;
                nextIndex++;
            }
            checkForComodification();
        }
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
}

I made reference to the implementation of LinkedList source, LinkedList is a doubly linked list to achieve.

Write a test class:

import dataStructure.MySingleLinkList;

import java.util.*;

/**
 * Created by Viking on 2019/4/7
 */
public class TestSList {
    public static void main(String[] args) {
        MySingleLinkList<String> sList = new MySingleLinkList<>();
        System.out.println(sList.size());
        System.out.println(sList);
        sList.addLast("Hello!");
        sList.addLast("My");
        sList.addLast("Link");
        sList.addLast("List");
        sList.addLast("last");
        sList.addLast("same");
        sList.addLast("same");
        System.out.println(sList.size());
        System.out.println(sList.isEmpty());
        System.out.println(sList);
        System.out.println("index of 0:"+sList.get(0));
        System.out.println("index of 1:"+sList.get(1));
        System.out.println("index of 2:"+sList.get(2));
        System.out.println("index of 3:"+sList.get(3));
        System.out.println("index of 4:"+sList.get(4));
        System.out.println("getFirst:"+sList.getFirst());
        System.out.println("getLast:"+sList.getLast());
        System.out.println(sList);
        System.out.println(sList.removeLast());
        System.out.println("After remove 1 element:size="+sList.size());
        System.out.println(sList.removeLast());
        System.out.println("After remove 2 element:size="+sList.size());
        System.out.println(sList.removeLast());
        System.out.println("After remove 3 element:size="+sList.size());
        System.out.println(sList.removeLast());
        System.out.println("After remove 4 element:size="+sList.size());
        System.out.println(sList.removeLast());
        System.out.println("After remove 5 element:size="+sList.size());
        System.out.println(sList);
        sList.addLast("iterator");
        sList.addLast("is");
        sList.addLast("cool");
        Iterator<String> stringIterator = sList.myIterator();
//        while (stringIterator.hasNext()){
//            System.out.println(stringIterator.next());
//        }
//        System.out.println(sList);

        int i =0;
        while (stringIterator.hasNext()){//一迭代器对象只能执行一次迭代
            System.out.println(stringIterator.next());
            if (i<3) stringIterator.remove();
            i++;
//            if (sList.size()==1) break;
        }
        System.out.println(sList);
    }
}

Test Results:

0
[]
7
false
[Hello!,My,Link,List,last,same,same]
index of 0:Hello!
index of 1:My
index of 2:Link
index of 3:List
index of 4:last
getFirst:Hello!
getLast:same
[Hello!,My,Link,List,last,same,same]
same
After remove 1 element:size=6
same
After remove 2 element:size=5
last
After remove 3 element:size=4
List
After remove 4 element:size=3
Link
After remove 5 element:size=2
[Hello!,My]
Hello!
My
iterator
is
cool
[is,cool]

 

Guess you like

Origin blog.csdn.net/Mr__Viking/article/details/89450613