You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

不使用size()方法实现LinkedList的Spliterator按规则拆分

解决LinkedList的Spliterator拆分问题(不使用size())

我明白你卡在这里的痛点——LinkedList没法随机访问,又不能用size(),要实现按规则拆分确实有点绕。咱们一步步来拆解这个问题:

核心思路

因为不能用size(),所以必须通过遍历计数来判断是否满足拆分条件:当当前Spliterator的起始位置往后数至少有5个元素时,拆分出前4个,原Spliterator从第5个元素开始继续遍历;否则返回null。

LinkedList的遍历只能靠节点移动或者Iterator,这里提供两种实现方案,分别对应高效的内部节点操作和通用的Iterator缓存方案。


方案一:直接操作LinkedList内部节点(高效)

如果你的代码和LinkedList同包(或者能通过反射访问内部节点),可以直接用节点来跟踪遍历位置,效率最高:

import java.util.LinkedList;
import java.util.Spliterator;
import java.util.function.Consumer;

public class LinkedListSpliterator<E> implements Spliterator<E> {
    private LinkedList.Node<E> currentNode;

    // 从LinkedList初始化
    public LinkedListSpliterator(LinkedList<E> list) {
        this.currentNode = list.getFirst();
    }

    // 用于拆分的私有构造方法
    private LinkedListSpliterator(LinkedList.Node<E> currentNode) {
        this.currentNode = currentNode;
    }

    @Override
    public boolean tryAdvance(Consumer<? super E> action) {
        if (currentNode == null) return false;
        action.accept(currentNode.item);
        currentNode = currentNode.next;
        return true;
    }

    @Override
    public void forEachRemaining(Consumer<? super E> action) {
        LinkedList.Node<E> node = currentNode;
        while (node != null) {
            action.accept(node.item);
            node = node.next;
        }
        currentNode = null; // 标记为已遍历完成
    }

    @Override
    public Spliterator<E> trySplit() {
        if (currentNode == null) return null;

        // 遍历到第4个节点,同时检查是否存在第5个节点
        LinkedList.Node<E> splitEnd = currentNode;
        int count = 1;
        while (splitEnd.next != null && count < 4) {
            splitEnd = splitEnd.next;
            count++;
        }

        // 没有第5个节点,不满足拆分条件
        if (splitEnd.next == null) return null;

        // 保存原Spliterator的新起点(第5个节点)
        LinkedList.Node<E> newCurrent = splitEnd.next;
        splitEnd.next = null; // 断开拆分部分和原链表的连接,避免遍历越界

        // 创建并返回拆分出的前4个元素的Spliterator
        LinkedListSpliterator<E> splitSpliterator = new LinkedListSpliterator<>(currentNode);
        this.currentNode = newCurrent;
        return splitSpliterator;
    }

    @Override
    public long estimateSize() {
        return Spliterator.UNKNOWN_SIZE; // 无法提前知道大小
    }

    @Override
    public int characteristics() {
        return Spliterator.ORDERED | Spliterator.NONNULL; // LinkedList是有序的,元素非空
    }
}

方案二:通用Iterator缓存方案(无需访问内部节点)

如果没法访问LinkedList的内部节点,用Iterator配合缓存来实现,兼容性更强:

import java.util.LinkedList;
import java.util.List;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.ArrayList;
import java.util.Iterator;

public class LinkedListSpliterator<E> implements Spliterator<E> {
    private final Iterator<E> iterator;
    private List<E> buffer; // 缓存拆分失败时取出的元素

    public LinkedListSpliterator(LinkedList<E> list) {
        this.iterator = list.iterator();
        this.buffer = null;
    }

    // 用于拆分的私有构造方法
    private LinkedListSpliterator(List<E> buffer) {
        this.iterator = null;
        this.buffer = buffer;
    }

    @Override
    public boolean tryAdvance(Consumer<? super E> action) {
        // 优先处理缓存的元素
        if (buffer != null) {
            if (!buffer.isEmpty()) {
                action.accept(buffer.remove(0));
                return true;
            }
            buffer = null;
        }
        return iterator.hasNext() && (action.accept(iterator.next()) != null);
    }

    @Override
    public void forEachRemaining(Consumer<? super E> action) {
        if (buffer != null) {
            buffer.forEach(action);
            buffer = null;
        }
        iterator.forEachRemaining(action);
    }

    @Override
    public Spliterator<E> trySplit() {
        if (iterator == null || !iterator.hasNext()) return null;

        // 收集前4个元素
        List<E> splitElements = new ArrayList<>(4);
        for (int i = 0; i < 4 && iterator.hasNext(); i++) {
            splitElements.add(iterator.next());
        }

        // 收集4个元素后没有剩余,说明总元素不足5个,把元素放回缓存
        if (!iterator.hasNext()) {
            buffer = splitElements;
            return null;
        }

        // 满足条件,返回拆分出的Spliterator
        return new LinkedListSpliterator<>(splitElements);
    }

    @Override
    public long estimateSize() {
        return Spliterator.UNKNOWN_SIZE;
    }

    @Override
    public int characteristics() {
        return Spliterator.ORDERED | Spliterator.NONNULL;
    }
}

如何获取所有拆分批次

要拿到所有可拆分的批次,需要循环拆分每个Spliterator直到无法拆分为止,把所有拆分出的和剩余的Spliterator收集起来:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Spliterator;

public class Main {
    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        for (int i = 1; i <= 12; i++) {
            list.add(i);
        }

        Spliterator<Integer> mainSpliterator = new LinkedListSpliterator<>(list);
        List<Spliterator<Integer>> allBatches = new ArrayList<>();
        allBatches.add(mainSpliterator);

        // 循环拆分所有可拆分的Spliterator
        int index = 0;
        while (index < allBatches.size()) {
            Spliterator<Integer> current = allBatches.get(index);
            Spliterator<Integer> split = current.trySplit();
            if (split != null) {
                allBatches.add(split);
            } else {
                index++;
            }
        }

        // 遍历所有批次
        for (int i = 0; i < allBatches.size(); i++) {
            System.out.printf("批次 %d:", i + 1);
            allBatches.get(i).forEachRemaining(item -> System.out.print(item + " "));
            System.out.println();
        }
    }
}

运行后会输出所有拆分后的批次,比如1-4、5-8、9-12这样的分组。

内容的提问来源于stack exchange,提问作者Andrei

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:39:10