You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于单链表实现的自定义队列达特定规模时抛出StackOverflowException

嘿,这个问题我太熟了!我敢打赌你的Length属性实现是用递归遍历节点来计数的,对吧?

问题根源

CLR的调用栈是有大小限制的(默认一般是1MB左右),每次递归调用都会在栈上压入一个栈帧。当你的队列节点数达到9300时,递归的深度直接超过了栈能承受的上限,自然就抛出StackOverflowException;而9200刚好卡在栈的临界值以内,所以暂时没问题。

解决方案

别用递归了,换两种更靠谱的方式:

1. 维护计数器字段(最优方案)

在队列类里加一个私有计数器,每次入队/出队时更新它,Length属性直接返回这个值——不仅不会栈溢出,还是O(1)的时间复杂度。

示例代码:

public class MyQueue<T>
{
    private MyQueueNode<T> _head;
    private MyQueueNode<T> _tail;
    private int _count; // 核心计数器

    public int Length => _count;

    public void Enqueue(T item)
    {
        var newNode = new MyQueueNode<T>(item);
        if (_tail == null)
        {
            _head = newNode;
            _tail = newNode;
        }
        else
        {
            _tail.Next = newNode;
            _tail = newNode;
        }
        _count++; // 入队加1
    }

    public T Dequeue()
    {
        if (_head == null) throw new InvalidOperationException("队列已空");
        var item = _head.Value;
        _head = _head.Next;
        if (_head == null) _tail = null;
        _count--; // 出队减1
        return item;
    }
}

2. 用迭代代替递归(应急方案)

如果实在不想改结构,就把递归遍历改成while循环迭代——这样不会占用调用栈空间,多少节点都不怕。

示例代码:

public int Length
{
    get
    {
        int count = 0;
        var currentNode = _head;
        while (currentNode != null)
        {
            count++;
            currentNode = currentNode.Next;
        }
        return count;
    }
}

总结

递归写起来简洁,但在这种可能有大量节点的场景里绝对是雷区。维护计数器才是队列长度的正确打开方式,既高效又安全。

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

火山引擎 最新活动