松散链表的java实现(附完整代码)

一.什么是松散链表?
松散链表中的每个节点存储多个元素,每一块中的所有节点由循环链表连接在一起。

下面是用java实现的代码(大约700行直接翻译自国外某大神的代码):
1.先创建一个类,里面定义了松散链表的块和操作:

package lianbiaostudy;

/*
 * This source code is placed in the public domain. This means you can use it
 * without any restrictions.
 */

import java.util.AbstractList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.io.Serializable;
import java.util.ConcurrentModificationException;



public class songsanlianbiao<E> extends AbstractList<E> implements List<E>, Serializable {




    private int nodeCapacity;//定义每个块最多能装多少元素

    private int size = 0;//存储链表的大小的变量

    private Node firstNode;//块的第一个节点

    private Node lastNode;//块的最后一个节点

    //定义块
    private class Node {


        Node next;//下一个块


        Node previous;//前一个块


        int numElements = 0;//存储在此块的元素数


        Object[] elements;//存储元素的数组

        //构造新块
        Node() {

            elements = new Object[nodeCapacity];

        }
    }


//带参构造方法,设置每个块装多少元素
    public songsanlianbiao(int nodeCapacity) throws IllegalArgumentException {
        if (nodeCapacity < 8) {
            throw new IllegalArgumentException("nodeCapacity < 8");
        }
        this.nodeCapacity = nodeCapacity;
        firstNode = new Node();
        lastNode = firstNode;
    }

  //默认构造方法,默认每个块装16个元素
    public songsanlianbiao() {
        this(16);
    }

  //返回链表的大小
    public int size() {
        return size;
    }


    //判断链表是否为空
    @Override
    public boolean isEmpty() {
        return (size == 0);
    }


    //查询链表是否包含指定元素,如果包含返回true
    @Override
    public boolean contains(Object o) {
        return (indexOf(o) != -1);
    }


    //遍历迭代器
    @Override
    public Iterator<E> iterator() {
        return new ULLIterator(firstNode, 0, 0);
    }


    //返回包含此列表中所有元素的数组按适当的顺序
    @Override
    public Object[] toArray() {

        Object[] array = new Object[size];
        int p = 0;
        for (Node node = firstNode; node != null; node = node.next) {
            for (int i = 0; i < node.numElements; i++) {
                array[p] = node.elements[i];
                p++;
            }
        }
        return array;

    }

//   返回包含此列表中所有元素的数组按适当的顺序
    @Override
    public <T> T[] toArray(T[] a) {

        if (a.length < size) {
            a = (T[]) java.lang.reflect.Array.newInstance(
                    a.getClass().getComponentType(), size);
        }
        Object[] result = a;
        int p = 0;
        for (Node node = firstNode; node != null; node = node.next) {
            for (int i = 0; i < node.numElements; i++) {
                result[p] = node.elements[i];
                p++;
            }
        }
        return a;

    }


    //将指定的元素追加到此列表的末尾。成功返回true
    @Override
    public boolean add(E e) {
        insertIntoNode(lastNode, lastNode.numElements, e);
        return true;
    }


    //删除
    @Override
    public boolean remove(Object o) {

        int index = 0;
        Node node = firstNode;
        if (o == null) {
            while (node != null) {
                for (int ptr = 0; ptr < node.numElements; ptr++) {
                    if (node.elements[ptr] == null) {
                        removeFromNode(node, ptr);
                        return true;
                    }
                }
                index += node.numElements;
                node = node.next;
            }
        } else {
            while (node != null) {
                for (int ptr = 0; ptr < node.numElements; ptr++) {
                    if (o.equals(node.elements[ptr])) {
                        removeFromNode(node, ptr);
                        return true;
                    }
                }
                index += node.numElements;
                node = node.next;
            }
        }
        return false;

    }




//要检查是否包含在此列表中如果此列表包含返回true

    @Override
    public boolean containsAll(Collection<?> c) {

        if (c == null) {
            throw new NullPointerException();
        }
        Iterator<?> it = c.iterator();
        while (it.hasNext()) {
            if (!contains(it.next())) {
                return false;
            }
        }
        return true;

    }


    @Override
    public boolean addAll(Collection<? extends E> c) {

        if (c == null) {
            throw new NullPointerException();
        }
        boolean changed = false;
        Iterator<? extends E> it = c.iterator();
        while (it.hasNext()) {
            add(it.next());
            changed = true;
        }
        return changed;

    }


    @Override
    public boolean removeAll(Collection<?> c) {

        if (c == null) {
            throw new NullPointerException();
        }
        Iterator<?> it = c.iterator();
        boolean changed = false;
        while (it.hasNext()) {
            if (remove(it.next())) {
                changed = true;
            }
        }
        return changed;

    }


    @Override
    public boolean retainAll(Collection<?> c) {

        if (c == null) {
            throw new NullPointerException();
        }
        boolean changed = false;
        for (Node node = firstNode; node != null; node = node.next) {
            for (int i = 0; i < node.numElements; i++) {
                if (!c.contains(node.elements[i])) {
                    removeFromNode(node, i);
                    i--;
                    changed = true;
                }
            }
        }
        return changed;

    }

//
    @Override
    public void clear() {

        Node node = firstNode.next;
        while (node != null) {
            Node next = node.next;
            node.next = null;
            node.previous = null;
            node.elements = null;
            node = next;
        }
        lastNode = firstNode;
        for (int ptr = 0; ptr < firstNode.numElements; ptr++) {
            firstNode.elements[ptr] = null;
        }
        firstNode.numElements = 0;
        firstNode.next = null;
        size = 0;

    }

    //得到指定位置的数
    public E get(int index) throws IndexOutOfBoundsException {

        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }
        Node node;
        int p = 0;
        if (size - index > index) {
            node = firstNode;
            while (p <= index - node.numElements) {
                p += node.numElements;
                node = node.next;
            }
        } else {
            node = lastNode;
            p = size;
            while ((p -= node.numElements) > index) {
                node = node.previous;
            }
        }
        return (E) node.elements[index - p];

    }

//设置指定位置的元素
    @Override
    public E set(int index, E element) {

        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }
        E el = null;
        Node node;
        int p = 0;
        if (size - index > index) {
            node = firstNode;
            while (p <= index - node.numElements) {
                p += node.numElements;
                node = node.next;
            }
        } else {
            node = lastNode;
            p = size;
            while ((p -= node.numElements) > index) {
                node = node.previous;
            }
        }
        el = (E) node.elements[index - p];
        node.elements[index - p] = element;
        return el;

    }

//在指定位置添加元素
    @Override
    public void add(int index, E element) throws IndexOutOfBoundsException {

        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException();
        }
        Node node;
        int p = 0;
        if (size - index > index) {
            node = firstNode;
            while (p <= index - node.numElements) {
                p += node.numElements;
                node = node.next;
            }
        } else {
            node = lastNode;
            p = size;
            while ((p -= node.numElements) > index) {
                node = node.previous;
            }
        }
        insertIntoNode(node, index - p, element);

    }


    //删除指定位置的元素
    @Override
    public E remove(int index) throws IndexOutOfBoundsException {

        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }
        E element = null;
        Node node;
        int p = 0;
        if (size - index > index) {
            node = firstNode;
            while (p <= index - node.numElements) {
                p += node.numElements;
                node = node.next;
            }
        } else {
            node = lastNode;
            p = size;
            while ((p -= node.numElements) > index) {
                node = node.previous;
            }
        }
        element = (E) node.elements[index - p];
        removeFromNode(node, index - p);
        return element;

    }


    //
    @Override
    public int indexOf(Object o) {

        int index = 0;
        Node node = firstNode;
        if (o == null) {
            while (node != null) {
                for (int ptr = 0; ptr < node.numElements; ptr++) {
                    if (node.elements[ptr] == null) {
                        return index + ptr;
                    }
                }
                index += node.numElements;
                node = node.next;
            }
        } else {
            while (node != null) {
                for (int ptr = 0; ptr < node.numElements; ptr++) {
                    if (o.equals(node.elements[ptr])) {
                        return index + ptr;
                    }
                }
                index += node.numElements;
                node = node.next;
            }
        }
        return -1;

    }


    @Override
    public int lastIndexOf(Object o) {

        int index = size;
        Node node = lastNode;
        if (o == null) {
            while (node != null) {
                index -= node.numElements;
                for (int i = node.numElements - 1; i >= 0; i--) {
                    if (node.elements[i] == null) {
                        return (index + i);
                    }
                }
                node = node.previous;
            }
        } else {
            while (node != null) {
                index -= node.numElements;
                for (int i = node.numElements - 1; i >= 0; i--) {
                    if (o.equals(node.elements[i])) {
                        return (index + i);
                    }
                }
                node = node.previous;
            }
        }
        return -1;

    }

    /**
     * Returns a list iterator over the elements in this list (in proper
     * sequence).
     *
     * @return a list iterator over the elements in this list (in proper
     *         sequence)
     */
    @Override
    public ListIterator<E> listIterator() {

        return new ULLIterator(firstNode, 0, 0);

    }


    @Override
    public ListIterator<E> listIterator(int index) {

        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException();
        }
        Node node;
        int p = 0;
        if (size - index > index) {
            node = firstNode;
            while (p <= index - node.numElements) {
                p += node.numElements;
                node = node.next;
            }
        } else {
            node = lastNode;
            p = size;
            while ((p -= node.numElements) > index) {
                node = node.previous;
            }
        }
        return new ULLIterator(node, index - p, index);

    }

    private static final long serialVersionUID = -674052309103045211L;




    //松散链表迭代器
    private class ULLIterator implements ListIterator<E> {

        Node currentNode;
        int ptr;
        int index;

        private int expectedModCount = modCount;

        ULLIterator(Node node, int ptr, int index) {

            this.currentNode = node;
            this.ptr = ptr;
            this.index = index;

        }

       //下一个位置
        @Override
        public boolean hasNext() {

            return (index < size - 1);

        }


        @Override
        public E next() {

            ptr++;
            if (ptr >= currentNode.numElements) {
                if (currentNode.next != null) {
                    currentNode = currentNode.next;
                    ptr = 0;
                } else {
                    throw new NoSuchElementException();
                }
            }
            index++;
            checkForModification();
            return (E) currentNode.elements[ptr];

        }

        //判断
        @Override
        public boolean hasPrevious() {

            return (index > 0);

        }

        @Override
        public E previous() {

            ptr--;
            if (ptr < 0) {
                if (currentNode.previous != null) {
                    currentNode = currentNode.previous;
                    ptr = currentNode.numElements - 1;
                } else {
                    throw new NoSuchElementException();
                }
            }
            index--;
            checkForModification();
            return (E) currentNode.elements[ptr];

        }

        @Override
        public int nextIndex() {

            return (index + 1);

        }

        @Override
        public int previousIndex() {

            return (index - 1);

        }

        @Override
        public void remove() {

            checkForModification();
            removeFromNode(currentNode, ptr);

        }

        @Override
        public void set(E e) {

            checkForModification();
            currentNode.elements[ptr] = e;

        }

        @Override
        public void add(E e) {

            checkForModification();
            insertIntoNode(currentNode, ptr + 1, e);

        }

        private void checkForModification() {

            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }

        }

    }

    /**
     * Insert an element into the specified node. If the node is already full,
     * a new node will be created and inserted into the list after
     * the specified node.
     *
     * @param node
     * @param ptr the position at which the element should be inserted
     *            into the <tt>node.elements<tt> array
     * @param element the element to be inserted
     */
    private void insertIntoNode(Node node, int ptr, E element) {

        //如果这个块满了
        if (node.numElements == nodeCapacity) {
            // 创建一个新块
            Node newNode = new Node();
            // 将一半的元素移到新块中
            int elementsToMove = nodeCapacity / 2;
            int startIndex = nodeCapacity - elementsToMove;
            int i;
            for (i = 0; i < elementsToMove; i++) {
                newNode.elements[i] = node.elements[startIndex + i];
                node.elements[startIndex + i] = null;
            }
            node.numElements -= elementsToMove;
            newNode.numElements = elementsToMove;
            // 将新块插入到链表中
            newNode.next = node.next;
            newNode.previous = node;
            if (node.next != null) {
                node.next.previous = newNode;
            }
            node.next = newNode;

            if (node == lastNode) {
                lastNode = newNode;
            }

            // 检查是否这个元素应该被插入
            // 原始块或进入新块
            if (ptr > node.numElements) {
                node = newNode;
                ptr -= node.numElements;
            }
        }
        for (int i = node.numElements; i > ptr; i--) {
            node.elements[i] = node.elements[i - 1];
        }
        node.elements[ptr] = element;
        node.numElements++;
        size++;
        modCount++;

    }

    /**
     * Removes an element from the specified node.
     *
     * @param node the node from which an element should be removed
     * @param ptr the index of the element to be removed within
     * the <tt>node.elements<tt> array
     */
    //从指定节点中删除元素
    private void removeFromNode(Node node, int ptr) {

        node.numElements--;
        for (int i = ptr; i < node.numElements; i++) {
            node.elements[i] = node.elements[i + 1];
        }
        node.elements[node.numElements] = null;
        if (node.next != null && node.next.numElements + node.numElements <= nodeCapacity) {
            mergeWithNextNode(node);
        } else if (node.previous != null && node.previous.numElements + node.numElements <= nodeCapacity) {
            mergeWithNextNode(node.previous);
        }
        size--;
        modCount++;

    }

    /**
     * This method does merge the specified node with the next node.
     *
     * @param node the node which should be merged with the next node
     */
    //将指定块和下一个块合并

    private void mergeWithNextNode(Node node) {

        Node next = node.next;
        for (int i = 0; i < next.numElements; i++) {
            node.elements[node.numElements + i] = next.elements[i];
            next.elements[i] = null;
        }
        node.numElements += next.numElements;
        if (next.next != null) {
            next.next.previous = node;
        }
        node.next = next.next;
        if (next == lastNode) {
            lastNode = node;
        }

    }

    
}


2.测试代码:
里面对比了松散链表和java自带的链表的效率:

public class ceshi {
    public static void main(String[] args) {

        LinkedList<Integer> ll = new LinkedList<Integer>();
        long endTime;
        // Láncolt lista - feltöltés
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 5000000; i++) {
            ll.add(i);
        }
        endTime = System.currentTimeMillis();

        System.out.println("普通链表:LL: FILL -> " + (endTime - startTime));

        // Lánsolt lista - törlés
        startTime = System.currentTimeMillis();
        ll.remove(2500000);
        endTime = System.currentTimeMillis();
        System.out.println("LL: REMOVE -> " + (endTime - startTime));

        ll = null;
        System.gc();

        // ULL - feltöltés
        songsanlianbiao<Integer> ull = new songsanlianbiao<>(8);
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 5000000; i++) {
            ull.add(i);
        }

        System.out.println(ull.size());

        endTime = System.currentTimeMillis();
        System.out.println("松散链表:ULL: FILL -> " + (endTime - startTime));

        // ull - törlés
        startTime = System.currentTimeMillis();
        System.out.println(ull.remove(20));
        endTime = System.currentTimeMillis();
        System.out.println("ULL: REMOVE -> " + (endTime - startTime));

        System.out.println(ull.lastIndexOf(4999999));

    }
}

结果:
在这里插入图片描述

发布了73 篇原创文章 · 获赞 1 · 访问量 2463

猜你喜欢

转载自blog.csdn.net/c1776167012/article/details/104884064
今日推荐