4.4 松散链表的java实现(附完整代码及详细注释)

1.什么是松散链表?

1.1 松散链表定义

松散链表是单向链表和(循环链表/数组/双向链表/单向链表)的一种有效结合,松散链表中的每个节点存储一个块,每个块中可以有多个元素,
这些元素由(循环链表/数组/双向链表/单向链表)存放链接在一起。

如图所示:

这是松散链表的结构,它的节点也是链表结构

List1.next
List2.next
List3.next
List1
List2
List3
null

其中链表的结构如下

node1.next
node2.next
node3.next
node1
node2
node3
null

假设在任何时候松散链表中的块的个数不超过n。
为了进一步简化问题,我们假设除了最后一块外,其他块恰好含有n个元素。
在这样的情况下,在任何时候,松散链表中总元素的个数不会超过n^2。

1.2 在松散链表中查找一个元素

在松散链表中查找第k个块的时间开销最大为O(n),同理在一个块中找到第m个元素的时间开销最大为O(n)
所以,在松散链表中查找一个元素的最大时间开销为O(n^2),这和其他链表查找元素的时间复杂度一致。

1.3 在松散链表中查找指定位置的元素

这个操作相对于普通链表,松散链表的优势就体现出来了。在元素个数为n^2的链表中
普通链表查找指定位置的元素的时间复杂度为O(n^2)
松散链表查找指定位置的元素的时间复杂度为O(n), 由于块的原因,我们可以避免大量不必要的遍历。

1.4 在松散链表中插入一个元素

与其他类型的链表不同的是,当插入元素时,可能需要重新调整松散链表中的元素的位置来维护松散链表的属性。
假如每个块中包含n个元素,假设要在第i个元素的后面插入元素x,且将x放在第j块中。
如果链表中块的空间不足,则还需要在当前块后面添加一个新块。

如图所示:
例如,现在有下面的松散链表结构:
在这里插入图片描述

进行插入操作我们很容易知道其时间复杂度为O(i)
这个维护的时间复杂度我们需要进行分析一下:
其实,从直观的角度看,插入一个元素后,可能存在结构调整的情况,但是这个调整的时间复杂度也是极低的。
所以进行一次插入操作的总体时间复杂度为:O(n),这相比于普通链表提升了一个量级!!

2. Java实现松散链表

2.1 首先是节点定义

import lombok.Data;

@Data
public class Node {
    /**
     * 下一个块
     */
    Node next;
    /**
     * 前一个块
     */
    Node previous;
    /**
     * 此块的实际元素数量
     */
    int numElements = 0;
    /**
     * 块存储元素的数组
     */
    Object[] elements;
    //构造新块
    public Node(int nodeCapacity) {
        elements = new Object[nodeCapacity];
    }
}

2.2 然后就是具体的实现

package course.p4_list.s5_RelaxList;

import java.lang.reflect.Array;
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;


/**
 * 松散链表定义类
 * @param <E>
 */
public class RelaxList<E> extends AbstractList<E> implements List<E>, Serializable {

    /**
     * 链表中块的容量
     */
    private final int RelaxNodeCapacity;

    /**
     * 链表元素总个数
     */
    private int size = 0;

    /**
     *  链表第一个块
     */
    private final Node firstRelaxNode;

    /**
     *  链表最后一个块
     */
    private Node lastRelaxNode;

    private static final long serialVersionUID = -674052309103045211L;

    /**
     * 松散链表带参构造方法
     * @param RelaxNodeCapacity 指定松散链表的块大小,这里必须不小于8
     * @throws IllegalArgumentException 如果定义的块大小小于8,抛出异常
     */
    public RelaxList(int RelaxNodeCapacity) throws IllegalArgumentException {
        if (RelaxNodeCapacity < 8) {
            throw new IllegalArgumentException("RelaxNodeCapacity < 8");
        }
        this.RelaxNodeCapacity = RelaxNodeCapacity;
        firstRelaxNode = new Node(RelaxNodeCapacity);
        lastRelaxNode = firstRelaxNode;
    }

    /**
     * 松散链表无参构造方法,默认构造出块大小为16的松散链表
     */
    public RelaxList() {
        this(16);
    }

    /**
     * 将指定的元素添加到链表的末尾
     * @param e 指定元素
     * @return 返回true
     */
    @Override
    public boolean add(E e) {
        insertIntoRelaxNode(lastRelaxNode, lastRelaxNode.numElements, e);
        return true;
    }

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


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


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

    /**
     * 查找链表中是否存在指定元素
     * @param o 指定元素
     * @return 元素所在的位置
     */
    @Override
    public int indexOf(Object o) {
        int index = 0;
        Node RelaxNode = firstRelaxNode;
        if (o == null) {
            while (RelaxNode != null) {
                for (int ptr = 0; ptr < RelaxNode.numElements; ptr++) {
                    if (RelaxNode.elements[ptr] == null) {
                        return index + ptr;
                    }
                }
                index += RelaxNode.numElements;
                RelaxNode = RelaxNode.next;
            }
        } else {
            while (RelaxNode != null) {
                for (int ptr = 0; ptr < RelaxNode.numElements; ptr++) {
                    if (o.equals(RelaxNode.elements[ptr])) {
                        return index + ptr;
                    }
                }
                index += RelaxNode.numElements;
                RelaxNode = RelaxNode.next;
            }
        }
        return -1;
    }


    /**
     * 获得松散链表的迭代器
     * @return 迭代器
     */
    @Override
    public Iterator<E> iterator() {
        return new RelaxIterator(firstRelaxNode, 0, 0);
    }


    /**
     * 将链表元素集合转化为Object数组返回
     * @return 数组
     */
    @Override
    public Object[] toArray() {
        Object[] array = new Object[size];
        int p = 0;
        for (Node RelaxNode = firstRelaxNode; RelaxNode != null; RelaxNode = RelaxNode.next) {
            for (int i = 0; i < RelaxNode.numElements; i++) {
                array[p] = RelaxNode.elements[i];
                p++;
            }
        }
        return array;
    }

    /**
     * 返回指定类型的数组
     * @param a 指定类型的空数组
     * @param <T> 泛型变量
     * @return 类型数组对象
     */
    @Override
    @SuppressWarnings({ "unchecked" })
    public <T> T[] toArray(T[] a) {
        //如果传入的数组大小小于链表大小,则重新新建一个数组
        if (a.length < size) {
            //新建一个指定类型的数组
            a = (T[])Array.newInstance(a.getClass().getComponentType(),size);
        }
        Object[] result = a;
        int p = 0;
        for (Node RelaxNode = firstRelaxNode; RelaxNode != null; RelaxNode = RelaxNode.next) {
            for (int i = 0; i < RelaxNode.numElements; i++) {
                result[p] = RelaxNode.elements[i];
                p++;
            }
        }
        return a;
    }

    /**
     * 删除链表中指定元素
     * 如果成功删除返回true 如果不存在此元素返回false
     * @param o 指向元素对象
     * @return 是否成功删除
     */
    @Override
    public boolean remove(Object o) {
        int index = 0;
        Node RelaxNode = firstRelaxNode;
        if (o == null) {
            while (RelaxNode != null) {
                for (int ptr = 0; ptr < RelaxNode.numElements; ptr++) {
                    if (RelaxNode.elements[ptr] == null) {
                        removeFromRelaxNode(RelaxNode, ptr);
                        return true;
                    }
                }
                index += RelaxNode.numElements;
                RelaxNode = RelaxNode.next;
            }
        } else {
            while (RelaxNode != null) {
                for (int ptr = 0; ptr < RelaxNode.numElements; ptr++) {
                    if (o.equals(RelaxNode.elements[ptr])) {
                        removeFromRelaxNode(RelaxNode, ptr);
                        return true;
                    }
                }
                index += RelaxNode.numElements;
                RelaxNode = RelaxNode.next;
            }
        }
        return false;
    }


    /**
     * 判断链表是否包含入参集合的所有元素
     * @param c 集合
     * @return 全包含返回true 不全包含返回false
     */
    @Override
    public boolean containsAll(Collection<?> c) {
        if (c == null) {
            throw new NullPointerException();
        }
        for (Object o : c) {
            if (!contains(o)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 将指定集合中所有元素加入到链表中
     * @param c 指向集合
     * @return 成功返回true 失败返回false
     */
    @Override
    public boolean addAll(Collection<? extends E> c) {
        if (c == null) {
            throw new NullPointerException();
        }
        boolean changed = false;
        for (E e : c) {
            add(e);
            changed = true;
        }
        return changed;
    }


    /**
     * 从链表中删除集合c中所有元素
     * @param c 集合c
     * @return 成功标志
     */
    @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;
    }


    /**
     *删除链表中除包含在集合c中的其他所有元素,仅保留c中有的
     * @param c 指定集合c
     * @return 成功标志
     */
    @Override
    public boolean retainAll(Collection<?> c) {
        if (c == null) {
            throw new NullPointerException();
        }
        boolean changed = false;
        for (Node RelaxNode = firstRelaxNode; RelaxNode != null; RelaxNode = RelaxNode.next) {
            for (int i = 0; i < RelaxNode.numElements; i++) {
                if (!c.contains(RelaxNode.elements[i])) {
                    removeFromRelaxNode(RelaxNode, i);
                    i--;
                    changed = true;
                }
            }
        }
        return changed;
    }

    /**
     *清空链表,只剩一个头,且头中元素都清除了
     */
    @Override
    public void clear() {

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

    }

    /**
     *获得指定位置的元素
     * @param index 指定位置
     * @return 返回指定位置元素
     * @throws IndexOutOfBoundsException 如果传入的位置不合法,抛出异常
     */
    @SuppressWarnings({ "unchecked" })
    public E get(int index) throws IndexOutOfBoundsException {

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

    }


    /**
     *更新指定位置的元素
     * @param index 指定位置
     * @param element 指定元素
     * @return 返回此位置的原来的元素
     */
    @Override
    @SuppressWarnings({ "unchecked" })
    public E set(int index, E element) {

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

    }


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

        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException();
        }
        Node RelaxNode;
        int p = 0;
        if (size - index > index) {
            RelaxNode = firstRelaxNode;
            while (p <= index - RelaxNode.numElements) {
                p += RelaxNode.numElements;
                RelaxNode = RelaxNode.next;
            }
        } else {
            RelaxNode = lastRelaxNode;
            p = size;
            while ((p -= RelaxNode.numElements) > index) {
                RelaxNode = RelaxNode.previous;
            }
        }
        insertIntoRelaxNode(RelaxNode, index - p, element);

    }


    /**
     *删除指定位置的元素
     * @param index 指定位置
     * @return 返回删除之前这个位置的元素
     * @throws IndexOutOfBoundsException 如果位置不合法,抛出异常
     */
    @Override
    @SuppressWarnings({"unchecked"})
    public E remove(int index) throws IndexOutOfBoundsException {

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

    }

    /**
     *找出指定元素在链表中最后出现的位置索引
     * @param o 指定元素
     * @return 返回位置索引
     */
    @Override
    public int lastIndexOf(Object o) {
        int index = size;
        Node RelaxNode = lastRelaxNode;
        if (o == null) {
            while (RelaxNode != null) {
                index -= RelaxNode.numElements;
                for (int i = RelaxNode.numElements - 1; i >= 0; i--) {
                    if (RelaxNode.elements[i] == null) {
                        return (index + i);
                    }
                }
                RelaxNode = RelaxNode.previous;
            }
        } else {
            while (RelaxNode != null) {
                index -= RelaxNode.numElements;
                for (int i = RelaxNode.numElements - 1; i >= 0; i--) {
                    if (o.equals(RelaxNode.elements[i])) {
                        return (index + i);
                    }
                }
                RelaxNode = RelaxNode.previous;
            }
        }
        return -1;
    }


    /**
     *得到这个链表的迭代器
     * @return 链表迭代器
     */
    @Override
    public ListIterator<E> listIterator() {
        return new RelaxIterator(firstRelaxNode, 0, 0);
    }

    /**
     *得到从指定位置后的松散链表迭代器
     * @param index 指定位置
     * @return 链表迭代器
     */
    @Override
    public ListIterator<E> listIterator(int index) {

        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException();
        }
        Node RelaxNode;
        int p = 0;
        if (size - index > index) {
            RelaxNode = firstRelaxNode;
            while (p <= index - RelaxNode.numElements) {
                p += RelaxNode.numElements;
                RelaxNode = RelaxNode.next;
            }
        } else {
            RelaxNode = lastRelaxNode;
            p = size;
            while ((p -= RelaxNode.numElements) > index) {
                RelaxNode = RelaxNode.previous;
            }
        }
        return new RelaxIterator(RelaxNode, index - p, index);

    }

    /**
     * 向指定块的指定位置插入指定元素
     * @param RelaxNode 指定块
     * @param ptr 指定位置
     * @param element 指定元素
     */
    private void insertIntoRelaxNode(Node RelaxNode, int ptr, E element) {
        //如果这个块满了
        if (RelaxNode.numElements == RelaxNodeCapacity) {
            // 创建一个新块
            Node newRelaxNode = new Node(RelaxNodeCapacity);
            // 将一半的元素移到新块中
            int elementsToMove = RelaxNodeCapacity / 2;
            int startIndex = RelaxNodeCapacity - elementsToMove;
            int i;
            for (i = 0; i < elementsToMove; i++) {
                newRelaxNode.elements[i] = RelaxNode.elements[startIndex + i];
                RelaxNode.elements[startIndex + i] = null;
            }
            RelaxNode.numElements -= elementsToMove;
            newRelaxNode.numElements = elementsToMove;
            // 将新块插入到链表指定块后面
            newRelaxNode.next = RelaxNode.next;
            newRelaxNode.previous = RelaxNode;
            if (RelaxNode.next != null) {
                RelaxNode.next.previous = newRelaxNode;
            }
            RelaxNode.next = newRelaxNode;

            if (RelaxNode == lastRelaxNode) {
                lastRelaxNode = newRelaxNode;
            }
            // 如果插入位置大于原始块的实际元素数,此元素应该插入新块中
            if (ptr > RelaxNode.numElements) {
                RelaxNode = newRelaxNode;
                ptr -= RelaxNode.numElements;
            }
        }
        //由于块是数组是实现,所以插入位置后的元素都后移一位
        for (int i = RelaxNode.numElements; i > ptr; i--) {
            RelaxNode.elements[i] = RelaxNode.elements[i-1];
        }
        //执行插入操作
        RelaxNode.elements[ptr] = element;
        RelaxNode.numElements++;
        //维护链表大小
        size++;
        modCount++;
    }

    /**
     * 删除块指定位置的元素
     * @param RelaxNode 指定块
     * @param ptr 指定位置
     */
    private void removeFromRelaxNode(Node RelaxNode, int ptr) {
        RelaxNode.numElements--;
        //后面的元素向前移动一位
        for (int i = ptr; i < RelaxNode.numElements; i++) {
            RelaxNode.elements[i] = RelaxNode.elements[i + 1];
        }
        RelaxNode.elements[RelaxNode.numElements] = null;
        //如果此块不是最后一个块且此块和它的下一个块的元素总数小于块大小,则进行块合并操作
        if (RelaxNode.next != null && (RelaxNode.next.numElements + RelaxNode.numElements) <= RelaxNodeCapacity) {
            mergeWithNextRelaxNode(RelaxNode);
            //如果此块不是最后一个块且它和上一个块的元素总数小于块大小,则进行合并操作
        } else if (RelaxNode.previous != null && (RelaxNode.previous.numElements + RelaxNode.numElements) <= RelaxNodeCapacity) {
            mergeWithNextRelaxNode(RelaxNode.previous);
        }
        size--;
        modCount++;

    }

    /**
     * 块合并操作:将指定块和它的下一个块进行合并
     * @param RelaxNode 指定块
     */
    private void mergeWithNextRelaxNode(Node RelaxNode) {
        Node next = RelaxNode.next;
        for (int i = 0; i < next.numElements; i++) {
            RelaxNode.elements[RelaxNode.numElements + i] = next.elements[i];
            next.elements[i] = null;
        }
        //块的元素总数变量维护
        RelaxNode.numElements += next.numElements;
        if (next.next != null) {
            next.next.previous = RelaxNode;
        }
        RelaxNode.next = next.next;
        if (next == lastRelaxNode) {
            lastRelaxNode = RelaxNode;
        }
    }

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

        Node currentRelaxNode;
        int ptr;
        int index;

        private final int expectedModCount = modCount;

        RelaxIterator(Node RelaxNode, int ptr, int index) {

            this.currentRelaxNode = RelaxNode;
            this.ptr = ptr;
            this.index = index;

        }

        //下一个位置
        @Override
        public boolean hasNext() {
            return (index < size - 1);
        }


        @Override
        @SuppressWarnings({"unchecked"})
        public E next() {

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

        }

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

            return (index > 0);

        }

        @Override
        @SuppressWarnings({"unchecked"})
        public E previous() {

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

        }

        @Override
        public int nextIndex() {

            return (index + 1);

        }

        @Override
        public int previousIndex() {

            return (index - 1);

        }

        @Override
        public void remove() {

            checkForModification();
            removeFromRelaxNode(currentRelaxNode, ptr);

        }

        @Override
        public void set(E e) {

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

        }

        @Override
        public void add(E e) {

            checkForModification();
            insertIntoRelaxNode(currentRelaxNode, ptr + 1, e);

        }

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

}

2.3 最后就是测试工作

import org.junit.Test;

import java.util.LinkedList;

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

        //统计jdk自带链表add 500万个元素所需时间
        LinkedList<Integer> ll = new LinkedList<Integer>();
        long endTime;
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 5000000; i++) {
            ll.add(i);
        }
        endTime = System.currentTimeMillis();
        System.out.println("Jdk实现的普通链表add500万个元素所需时间 -> " + (endTime - startTime)+"ms");
        //统计长度为500万的普通链表删除第250万个位置的元素所需时间
        startTime = System.currentTimeMillis();
        ll.remove(2500000);
        endTime = System.currentTimeMillis();
        System.out.println("普通链表删除第250万个元素所需要的时间->" + (endTime - startTime)+"ms");
        ll = null;
        System.gc();

        //相同条件下松散链表的表现
        RelaxList<Integer> ull = new RelaxList<>(16);
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 5000000; i++) {
            ull.add(i);
        }
        System.out.println(ull.size());
        endTime = System.currentTimeMillis();
        System.out.println("松散链表add 500万个元素所需时间 -> " + (endTime - startTime)+"ms");
        startTime = System.currentTimeMillis();
        System.out.println(ull.remove(2500000));
        endTime = System.currentTimeMillis();
        System.out.println("松散链表删除第250万个元素所需时间->" + (endTime - startTime)+"ms");
    }


    @Test
    public void Test(){
        RelaxList<String> test1=new RelaxList<>(10);
        RelaxList<String> test2=new RelaxList<>(12);
    }
}

测试结果如下:

在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小牧之

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值